From 30bd6e4c1c5e2c892965212d850a3c8aa9ab886d Mon Sep 17 00:00:00 2001 From: Dennis Potman <45659984+dennis-adlink@users.noreply.github.com> Date: Thu, 5 Dec 2019 10:30:35 +0100 Subject: [PATCH] DDS Security built-in Cryptographic plugin (#306) * DDS Security built-in Cryptographic plugin This commit adds the built-in Cryptographic plugin that is part of the DDS Security implementation for Cyclone. The Cryptographic plugin defines the types and operations necessary to support encryption, digest, message authentication codes, and key exchange for DDS DomainParticipants, DataWriters and DDS DataReaders. Similar to other builtin plugins, the DDS Security cryptographic plugin is built as a shared library to allow dynamic library loading on runtime. This enables DDS participants to use specific plugin implementations with different configurations. Although I think this initial version is a reasonable starting point to be merged in the security branch, some parts of the code will need refactoring: * crypto_key_factory.c: crypto_factory_get_endpoint_relation returns arbitrary local-remote relation if no specific key for remote is found, which will not work in Cyclone because participants can have different security settings * performance of encoding data can be improved by not copying plain_rtps_message to a new buffer (to enable this, crypto_cipher_encrypt_data should allow encrypting parts of a message) * when decoding a message the message is split in several parts (header, body, footer, etc) and for this memory is allocated which is probably not necessary. Performance should be improved by removing these allocations and use pointers to the data instead. Signed-off-by: Dennis Potman * WIP processing crypto plugin review comments Signed-off-by: Dennis Potman * WIP more refactoring based on review comments Signed-off-by: Dennis Potman * WIP fixing crypto plugin support for 128 bit key size Signed-off-by: Dennis Potman * WIP refactored master key storage to reduce memory usage when using 128 bit keys Signed-off-by: Dennis Potman * WIP fixing windows build linker issue Signed-off-by: Dennis Potman * WIP refactored crypto key types, avoid returning pointers to released ref-counted object Signed-off-by: Dennis Potman * Fixed bug in test decode_datareader_submessage.invalid_data Signed-off-by: Dennis Potman * Fixed issues from review: use correct constant for hashing and handle different src/dst keysize correctly Signed-off-by: Dennis Potman --- .../dds/security/dds_security_api_defs.h | 55 +- .../dds/security/dds_security_api_err.h | 2 + src/security/builtin_plugins/CMakeLists.txt | 1 + .../authentication/src/authentication.c | 4 +- .../cryptographic/CMakeLists.txt | 58 + .../cryptographic/src/crypto_cipher.c | 258 ++ .../cryptographic/src/crypto_cipher.h | 99 + .../cryptographic/src/crypto_defs.h | 114 + .../cryptographic/src/crypto_key_exchange.c | 538 ++++ .../cryptographic/src/crypto_key_exchange.h | 27 + .../cryptographic/src/crypto_key_factory.c | 1869 +++++++++++++ .../cryptographic/src/crypto_key_factory.h | 146 + .../cryptographic/src/crypto_objects.c | 593 ++++ .../cryptographic/src/crypto_objects.h | 354 +++ .../cryptographic/src/crypto_transform.c | 2469 +++++++++++++++++ .../cryptographic/src/crypto_transform.h | 28 + .../cryptographic/src/crypto_utils.c | 153 + .../cryptographic/src/crypto_utils.h | 95 + .../cryptographic/src/cryptography.c | 98 + .../cryptographic/src/cryptography.h | 33 + .../builtin_plugins/tests/CMakeLists.txt | 67 +- .../tests/common/src/crypto_helper.c | 112 + .../tests/common/src/crypto_helper.h | 38 + ...te_local_datareader_crypto_tokens_utests.c | 501 ++++ ...te_local_datawriter_crypto_tokens_utests.c | 505 ++++ ...e_local_participant_crypto_tokens_utests.c | 362 +++ .../src/decode_datareader_submessage_utests.c | 1748 ++++++++++++ .../src/decode_datawriter_submessage_utests.c | 1771 ++++++++++++ .../src/decode_rtps_message_utests.c | 1492 ++++++++++ .../src/decode_serialized_payload_utests.c | 1119 ++++++++ .../src/encode_datareader_submessage_utests.c | 1275 +++++++++ .../src/encode_datawriter_submessage_utests.c | 1348 +++++++++ .../src/encode_rtps_message_utests.c | 1322 +++++++++ .../src/encode_serialized_payload_utests.c | 786 ++++++ ...thenticated_peer_credential_token_utests.c | 35 +- .../src/preprocess_secure_submsg_utests.c | 930 +++++++ .../src/process_handshake_utests.c | 35 +- .../src/register_local_datareader_utests.c | 311 +++ .../src/register_local_datawriter_utests.c | 333 +++ .../src/register_local_participant_utests.c | 154 + ...egister_matched_remote_datareader_utests.c | 392 +++ ...egister_matched_remote_datawriter_utests.c | 376 +++ ...gister_matched_remote_participant_utests.c | 229 ++ ...t_remote_datareader_crypto_tokens_utests.c | 980 +++++++ ...t_remote_datawriter_crypto_tokens_utests.c | 1029 +++++++ ..._remote_participant_crypto_tokens_utests.c | 545 ++++ .../validate_begin_handshake_reply_utests.c | 37 +- .../security/core/dds_security_serialize.h | 10 +- .../dds/security/core/dds_security_types.h | 6 +- .../dds/security/core/dds_security_utils.h | 40 +- .../include/dds/security/core/shared_secret.h | 29 +- .../core/src/dds_security_serialize.c | 62 +- src/security/core/src/dds_security_utils.c | 73 +- src/security/core/src/shared_secret.c | 30 +- 54 files changed, 24804 insertions(+), 272 deletions(-) create mode 100644 src/security/builtin_plugins/cryptographic/CMakeLists.txt create mode 100644 src/security/builtin_plugins/cryptographic/src/crypto_cipher.c create mode 100644 src/security/builtin_plugins/cryptographic/src/crypto_cipher.h create mode 100644 src/security/builtin_plugins/cryptographic/src/crypto_defs.h create mode 100644 src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.c create mode 100644 src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.h create mode 100644 src/security/builtin_plugins/cryptographic/src/crypto_key_factory.c create mode 100644 src/security/builtin_plugins/cryptographic/src/crypto_key_factory.h create mode 100644 src/security/builtin_plugins/cryptographic/src/crypto_objects.c create mode 100644 src/security/builtin_plugins/cryptographic/src/crypto_objects.h create mode 100644 src/security/builtin_plugins/cryptographic/src/crypto_transform.c create mode 100644 src/security/builtin_plugins/cryptographic/src/crypto_transform.h create mode 100644 src/security/builtin_plugins/cryptographic/src/crypto_utils.c create mode 100644 src/security/builtin_plugins/cryptographic/src/crypto_utils.h create mode 100644 src/security/builtin_plugins/cryptographic/src/cryptography.c create mode 100644 src/security/builtin_plugins/cryptographic/src/cryptography.h create mode 100644 src/security/builtin_plugins/tests/common/src/crypto_helper.c create mode 100644 src/security/builtin_plugins/tests/common/src/crypto_helper.h create mode 100644 src/security/builtin_plugins/tests/create_local_datareader_crypto_tokens/src/create_local_datareader_crypto_tokens_utests.c create mode 100644 src/security/builtin_plugins/tests/create_local_datawriter_crypto_tokens/src/create_local_datawriter_crypto_tokens_utests.c create mode 100644 src/security/builtin_plugins/tests/create_local_participant_crypto_tokens/src/create_local_participant_crypto_tokens_utests.c create mode 100644 src/security/builtin_plugins/tests/decode_datareader_submessage/src/decode_datareader_submessage_utests.c create mode 100644 src/security/builtin_plugins/tests/decode_datawriter_submessage/src/decode_datawriter_submessage_utests.c create mode 100644 src/security/builtin_plugins/tests/decode_rtps_message/src/decode_rtps_message_utests.c create mode 100644 src/security/builtin_plugins/tests/decode_serialized_payload/src/decode_serialized_payload_utests.c create mode 100644 src/security/builtin_plugins/tests/encode_datareader_submessage/src/encode_datareader_submessage_utests.c create mode 100644 src/security/builtin_plugins/tests/encode_datawriter_submessage/src/encode_datawriter_submessage_utests.c create mode 100644 src/security/builtin_plugins/tests/encode_rtps_message/src/encode_rtps_message_utests.c create mode 100644 src/security/builtin_plugins/tests/encode_serialized_payload/src/encode_serialized_payload_utests.c create mode 100644 src/security/builtin_plugins/tests/preprocess_secure_submsg/src/preprocess_secure_submsg_utests.c create mode 100644 src/security/builtin_plugins/tests/register_local_datareader/src/register_local_datareader_utests.c create mode 100644 src/security/builtin_plugins/tests/register_local_datawriter/src/register_local_datawriter_utests.c create mode 100644 src/security/builtin_plugins/tests/register_local_participant/src/register_local_participant_utests.c create mode 100644 src/security/builtin_plugins/tests/register_matched_remote_datareader/src/register_matched_remote_datareader_utests.c create mode 100644 src/security/builtin_plugins/tests/register_matched_remote_datawriter/src/register_matched_remote_datawriter_utests.c create mode 100644 src/security/builtin_plugins/tests/register_matched_remote_participant/src/register_matched_remote_participant_utests.c create mode 100644 src/security/builtin_plugins/tests/set_remote_datareader_crypto_tokens/src/set_remote_datareader_crypto_tokens_utests.c create mode 100644 src/security/builtin_plugins/tests/set_remote_datawriter_crypto_tokens/src/set_remote_datawriter_crypto_tokens_utests.c create mode 100644 src/security/builtin_plugins/tests/set_remote_participant_crypto_tokens/src/set_remote_participant_crypto_tokens_utests.c diff --git a/src/security/api/include/dds/security/dds_security_api_defs.h b/src/security/api/include/dds/security/dds_security_api_defs.h index a0e6739..d3d1705 100644 --- a/src/security/api/include/dds/security/dds_security_api_defs.h +++ b/src/security/api/include/dds/security/dds_security_api_defs.h @@ -37,7 +37,8 @@ typedef enum { #define DDS_SECURITY_HANDLE_NIL (0) - +#define DDS_SECURITY_SUCCESS (0) +#define DDS_SECURITY_FAILED (-1) /************************************************************************** @@ -45,30 +46,30 @@ typedef enum { * Attribute flags. * * * **************************************************************************/ -#define DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_PROTECTED (0x00000001 ) -#define DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_PROTECTED (0x00000001 << 1) -#define DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_PROTECTED (0x00000001 << 2) -#define DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID (0x00000001 << 31) +#define DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_PROTECTED (1u ) +#define DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_PROTECTED (1u << 1) +#define DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_PROTECTED (1u << 2) +#define DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID (1u << 31) -#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED (0x00000001 ) -#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_ENCRYPTED (0x00000001 << 1) -#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_ENCRYPTED (0x00000001 << 2) -#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED (0x00000001 << 3) -#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_AUTHENTICATED (0x00000001 << 4) -#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_AUTHENTICATED (0x00000001 << 5) +#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED (1u ) +#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_ENCRYPTED (1u << 1) +#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_ENCRYPTED (1u << 2) +#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED (1u << 3) +#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_AUTHENTICATED (1u << 4) +#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_AUTHENTICATED (1u << 5) -#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_READ_PROTECTED (0x00000001 ) -#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_WRITE_PROTECTED (0x00000001 << 1) -#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_DISCOVERY_PROTECTED (0x00000001 << 2) -#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_PROTECTED (0x00000001 << 3) -#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_PROTECTED (0x00000001 << 4) -#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_KEY_PROTECTED (0x00000001 << 5) -#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_LIVELINESS_PROTECTED (0x00000001 << 6) -#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_VALID (0x00000001 << 31) +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_READ_PROTECTED (1u ) +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_WRITE_PROTECTED (1u << 1) +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_DISCOVERY_PROTECTED (1u << 2) +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_PROTECTED (1u << 3) +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_PROTECTED (1u << 4) +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_KEY_PROTECTED (1u << 5) +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_LIVELINESS_PROTECTED (1u << 6) +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_VALID (1u << 31) -#define DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED (0x00000001 ) -#define DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED (0x00000001 << 1) -#define DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED (0x00000001 << 2) +#define DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED (1u ) +#define DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED (1u << 1) +#define DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED (1u << 2) @@ -175,10 +176,12 @@ typedef enum { **************************************************************************/ #define DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE 32 -#define DDS_SECURITY_MASTER_SALT_SIZE 32 -#define DDS_SECURITY_MASTER_SENDER_KEY_SIZE 32 -#define DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE 32 - +#define DDS_SECURITY_MASTER_SALT_SIZE_128 16 +#define DDS_SECURITY_MASTER_SALT_SIZE_256 32 +#define DDS_SECURITY_MASTER_SENDER_KEY_SIZE_128 16 +#define DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256 32 +#define DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_128 16 +#define DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256 32 #if defined (__cplusplus) diff --git a/src/security/api/include/dds/security/dds_security_api_err.h b/src/security/api/include/dds/security/dds_security_api_err.h index f4e8904..20ee24b 100644 --- a/src/security/api/include/dds/security/dds_security_api_err.h +++ b/src/security/api/include/dds/security/dds_security_api_err.h @@ -106,6 +106,8 @@ extern "C" { #define DDS_SECURITY_ERR_PERMISSIONS_OUT_OF_VALIDITY_DATE_MESSAGE "Permissions of subject (%s) outside validity date: %s - %s" #define DDS_SECURITY_ERR_URI_TYPE_NOT_SUPPORTED_CODE 151 #define DDS_SECURITY_ERR_URI_TYPE_NOT_SUPPORTED_MESSAGE "Unsupported URI type: %s" +#define DDS_SECURITY_ERR_INVALID_CRYPTO_DATA_NOT_ALIGNED_CODE 152 +#define DDS_SECURITY_ERR_INVALID_CRYPTO_DATA_NOT_ALIGNED_MESSAGE "The payload is not aligned at 4 bytes" #define DDS_SECURITY_ERR_UNDEFINED_CODE 200 #define DDS_SECURITY_ERR_UNDEFINED_MESSAGE "Undefined Error Message" diff --git a/src/security/builtin_plugins/CMakeLists.txt b/src/security/builtin_plugins/CMakeLists.txt index 69e5aed..113d0b4 100644 --- a/src/security/builtin_plugins/CMakeLists.txt +++ b/src/security/builtin_plugins/CMakeLists.txt @@ -12,6 +12,7 @@ cmake_minimum_required(VERSION 3.7) add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/authentication") +add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/cryptographic") # TODO: improve test inclusion. if((BUILD_TESTING) AND ((NOT DEFINED MSVC_VERSION) OR (MSVC_VERSION GREATER "1800"))) diff --git a/src/security/builtin_plugins/authentication/src/authentication.c b/src/security/builtin_plugins/authentication/src/authentication.c index eb4117f..c893254 100644 --- a/src/security/builtin_plugins/authentication/src/authentication.c +++ b/src/security/builtin_plugins/authentication/src/authentication.c @@ -1687,7 +1687,7 @@ validate_pdata( pdata = DDS_Security_ParticipantBuiltinTopicData_alloc(); - if (!DDD_Security_Deserialize_ParticipantBuiltinTopicData(deserializer, pdata, ex)) { + if (!DDS_Security_Deserialize_ParticipantBuiltinTopicData(deserializer, pdata, ex)) { result = DDS_SECURITY_VALIDATION_FAILED; goto err_incorrect_data; } @@ -1696,7 +1696,7 @@ validate_pdata( result = get_adjusted_participant_guid(cert, &cguid, &aguid, ex); if (result == DDS_SECURITY_VALIDATION_OK) { DDS_Security_BuiltinTopicKey_t key; - DDD_Security_BuiltinTopicKeyBE(key, pdata->key); + DDS_Security_BuiltinTopicKeyBE(key, pdata->key); if (memcmp(key, aguid.prefix, 6) != 0) { result = DDS_SECURITY_VALIDATION_FAILED; DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, diff --git a/src/security/builtin_plugins/cryptographic/CMakeLists.txt b/src/security/builtin_plugins/cryptographic/CMakeLists.txt new file mode 100644 index 0000000..3be3010 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/CMakeLists.txt @@ -0,0 +1,58 @@ +# +# Copyright(c) 2006 to 2019 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +include (GenerateExportHeader) + +find_package(OpenSSL) + +PREPEND(srcs_cryptographic "${CMAKE_CURRENT_LIST_DIR}/src" + crypto_cipher.c + crypto_key_exchange + crypto_key_factory.c + crypto_objects.c + crypto_transform.c + crypto_utils.c + cryptography.c +) + +add_library(dds_security_crypto SHARED "") + +generate_export_header( + dds_security_crypto + BASE_NAME SECURITY + EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/include/dds/security/export.h" +) + +add_definitions(-DDDSI_INCLUDE_SSL) + +target_link_libraries(dds_security_crypto PUBLIC ddsc) +target_link_libraries(dds_security_crypto PUBLIC OpenSSL::SSL) + +target_sources(dds_security_crypto + PRIVATE + ${srcs_cryptographic} +) + +target_include_directories(dds_security_crypto + PUBLIC + "$>" + "$>" + "$>" + "$" +) + +install( + TARGETS + EXPORT "${PROJECT_NAME}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT lib + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib +) diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_cipher.c b/src/security/builtin_plugins/cryptographic/src/crypto_cipher.c new file mode 100644 index 0000000..80d79f3 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_cipher.c @@ -0,0 +1,258 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/types.h" +#include "crypto_defs.h" +#include "crypto_utils.h" +#include "crypto_cipher.h" + +bool crypto_cipher_encrypt_data( + const crypto_session_key_t *session_key, + uint32_t key_size, + const unsigned char *iv, + const unsigned char *data, + uint32_t data_len, + const unsigned char *aad, + uint32_t aad_len, + unsigned char *encrypted, + uint32_t *encrypted_len, + crypto_hmac_t *tag, + DDS_Security_SecurityException *ex) +{ + EVP_CIPHER_CTX *ctx; + int len = 0; + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_CIPHER_CTX_new failed: "); + goto fail_ctx_new; + } + + /* initialize the cipher and set to AES GCM */ + if (key_size == 128) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptInit_ex to set aes_128_gcm failed: "); + goto fail_encrypt; + } + } + else if (key_size == 256) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptInit_ex to set aes_256_gcm failed: "); + goto fail_encrypt; + } + } + else + { + assert(0); + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptInit_ex invalid key size: %u", key_size); + goto fail_encrypt; + } + + /* Initialise key and IV */ + if (!EVP_EncryptInit_ex(ctx, NULL, NULL, session_key->data, iv)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptInit_ex failed: "); + goto fail_encrypt; + } + + if (aad) + { + if (aad_len > INT_MAX) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptUpdate to update aad failed: aad_len exceeds INT_MAX"); + goto fail_encrypt; + } + + /* Provide any AAD data */ + if (!EVP_EncryptUpdate(ctx, NULL, &len, aad, (int) aad_len)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptUpdate to update aad failed: %s"); + goto fail_encrypt; + } + } + + if (data) + { + if (data_len > INT_MAX) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptUpdate to update data failed: data_len exceeds INT_MAX"); + goto fail_encrypt; + } + + /* encrypt the message */ + if (!EVP_EncryptUpdate(ctx, encrypted, &len, data, (int) data_len)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptUpdate update data failed: "); + goto fail_encrypt; + } + assert (len >= 0); /* conform openssl spec */ + *encrypted_len = (uint32_t) len; + } + + /* finalize the encryption */ + if (data) + { + if (!EVP_EncryptFinal_ex(ctx, encrypted + len, &len)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptFinal_ex to finalize encryption failed: "); + goto fail_encrypt; + } + assert (len >= 0); /* conform openssl spec */ + *encrypted_len += (uint32_t) len; + } + else + { + unsigned char temp[32]; + if (!EVP_EncryptFinal_ex(ctx, temp, &len)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptFinal_ex to finalize aad failed: "); + goto fail_encrypt; + } + } + + /* get the tag */ + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, CRYPTO_HMAC_SIZE, tag->data)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_CIPHER_CTX_ctrl to get the tag failed: "); + goto fail_encrypt; + } + + EVP_CIPHER_CTX_free(ctx); + return true; + +fail_encrypt: + EVP_CIPHER_CTX_free(ctx); +fail_ctx_new: + return false; +} + +bool crypto_cipher_decrypt_data( + const remote_session_info *session, + const unsigned char *iv, + const unsigned char *encrypted, + uint32_t encrypted_len, + const unsigned char *aad, + uint32_t aad_len, + unsigned char *data, + uint32_t *data_len, + crypto_hmac_t *tag, + DDS_Security_SecurityException *ex) +{ + EVP_CIPHER_CTX *ctx; + int len = 0; + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_CIPHER_CTX_new failed: "); + goto fail_ctx_new; + } + + /* initialize the cipher and set to AES GCM */ + if (session->key_size == 128) + { + if (EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_DecryptInit_ex to set aes_128_gcm failed: "); + goto fail_decrypt; + } + } + else if (session->key_size == 256) + { + if (EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) != 1) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_DecryptInit_ex to set aes_256_gcm failed: "); + goto fail_decrypt; + } + } + else + { + assert(0); + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "Internal key_size is not correct: %u", session->key_size); + goto fail_decrypt; + } + + /* Initialise key and IV */ + if (EVP_DecryptInit_ex(ctx, NULL, NULL, session->key.data, iv) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_DecryptInit_ex to set aes_256_gcm failed: %s"); + goto fail_decrypt; + } + + if (aad) + { + assert (aad_len <= INT32_MAX); + /* Provide any AAD data for signature */ + if (EVP_DecryptUpdate(ctx, NULL, &len, aad, (int) aad_len) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_DecryptUpdate to update aad failed: "); + goto fail_decrypt; + } + } + + /* Set expected tag value. */ + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, CRYPTO_HMAC_SIZE, tag->data) != 1) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_CIPHER_CTX_ctrl to get tag failed: "); + goto fail_decrypt; + } + + if (data) + { + /* decrypt the message */ + if (EVP_DecryptUpdate(ctx, data, &len, encrypted, (int) encrypted_len) != 1) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_DecryptUpdate update data failed: "); + goto fail_decrypt; + } + assert (len >= 0); + *data_len = (uint32_t)len; + } + + if (data) + { + if (EVP_DecryptFinal_ex(ctx, data + len, &len) != 1) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_DecryptFinal_ex to finalize decryption failed: "); + goto fail_decrypt; + } + assert (len >= 0); + *data_len += (uint32_t)len; + } + else + { + unsigned char temp[32]; + if (EVP_DecryptFinal_ex(ctx, temp, &len) != 1) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_DecryptFinal_ex to finalize signature check failed: "); + goto fail_decrypt; + } + } + + EVP_CIPHER_CTX_free(ctx); + return true; + +fail_decrypt: + EVP_CIPHER_CTX_free(ctx); +fail_ctx_new: + return false; +} diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_cipher.h b/src/security/builtin_plugins/cryptographic/src/crypto_cipher.h new file mode 100644 index 0000000..eb365b9 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_cipher.h @@ -0,0 +1,99 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTO_CIPHER_H +#define CRYPTO_CIPHER_H + +#include "dds/ddsrt/types.h" +#include "crypto_objects.h" + +/** + * @brief Encodes the provide data using the provided key + * + * This function encodes the provide data using the provided key, key_size + * and initialization_vector. It also computes the common_mac from the provided data. + * The data parameter contains the data that has to encoded. The aad parameter contains + * the data that is not encoded but is used in the computation of the common_mac + * On return the encrypted parameter contains the encoded data and the tag parameter + * the common mac. + * This function will be used either to encode the provided data in that case the + * data parameter should be set to the data to be encoded and the aad parameter should + * be NULL. Also the encrypted parameter should be set and contain a buffer large enough + * to contain the encoded data. + * This function is also used to only computer the common_mac. In that case the + * data parameter should be NULL and the aad parameter should point to the data on + * which the common_mac has to be computed. The encryped parameter is not relevant + * in this case. + * + * @param[in] session_key The session key used to encode the provided data + * @param[in] key_size The size of the session key (128 or 256 bit) + * @param[in] iv The init vector used by the encoding + * @param[in] data The data to be encoded + * @param[in] data_len The size of the data to be encoded + * @param[in] aad The additional data not be encoded but only used in the computation of the mac + * @param[in] aad_len The size of the additional data + * @param[in,out] encrypted The buffer to hold on return the encoded data + * @param[in,out] encrypted_len The size of the encrypted data buffer + * @param[in,out] tag Contains on return the mac value calculated over the provided data + * @param[in,out] ex Security exception (optional) + */ +bool crypto_cipher_encrypt_data( + const crypto_session_key_t *session_key, + uint32_t key_size, + const unsigned char *iv, + const unsigned char *data, + uint32_t data_len, + const unsigned char *aad, + uint32_t aad_len, + unsigned char *encrypted, + uint32_t *encrypted_len, + crypto_hmac_t *tag, + DDS_Security_SecurityException *ex); + +/** + * @brief Decodes the provided data using the session key and key_size + * + * This function decodes the provided data using the session key and key_size provided + * by by the session parameter. The iv parameter contains the initialization_vector used + * by the decode operation which is the concatination of received session_id and init_vector_suffix. + * The function checks if the common_mac (tag parameter) is corresponds with the provided data. + * This function will be used either to decode the provided data in that case the + * encrypted parameter should be set to the data to be decoded and the aad parameter should + * be NULL. Also the data parameter should be set and contain a buffer large enough + * to contain the decoded data. + * This function is also used to only verify the common_mac. In that case the + * data and the encrypted parameter should be NULL and the aad parameter should point to + * the data for which the common_mac has to be verified. + * + * @param[in] session Contains the session key and key size used of the decoding + * @param[in] iv The init vector used by the decoding + * @param[in] encrypted The encoded data + * @param[in] encrypted_len The size of the encoded data + * @param[in] aad The not encoded data used in the verification of the provided mac + * @param[in] aad_len The size of the additional data + * @param[in,out] data The buffer to hold on return the decoded data + * @param[in,out] data_len The size of the decoded data buffer + * @param[in,out] tag The mac value which has to be verified + * @param[in,out] ex Security exception (optional) + */ +bool crypto_cipher_decrypt_data( + const remote_session_info *session, + const unsigned char *iv, + const unsigned char *encrypted, + uint32_t encrypted_len, + const unsigned char *aad, + uint32_t aad_len, + unsigned char *data, + uint32_t *data_len, + crypto_hmac_t *tag, + DDS_Security_SecurityException *ex); + +#endif /* CRYPTO_CIPHER_H */ diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_defs.h b/src/security/builtin_plugins/cryptographic/src/crypto_defs.h new file mode 100644 index 0000000..a0fdf2a --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_defs.h @@ -0,0 +1,114 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTO_DEFS_H +#define CRYPTO_DEFS_H + +#include "dds/security/dds_security_api.h" + +#define DDS_CRYPTO_PLUGIN_CONTEXT "Cryptographic" + +#define CRYPTO_HMAC_SIZE 16 +#define CRYPTO_KEY_SIZE_128 16 +#define CRYPTO_KEY_SIZE_256 32 +#define CRYPTO_KEY_SIZE_MAX CRYPTO_KEY_SIZE_256 + +#define CRYPTO_SESSION_ID_SIZE 4 +#define CRYPTO_INIT_VECTOR_SUFFIX_SIZE 8 +#define CRYPTO_CIPHER_BLOCK_SIZE 16 + +typedef enum SecureSubmsgKind_t +{ + SMID_SEC_BODY_KIND = 0x30, + SMID_SEC_PREFIX_KIND = 0x31, + SMID_SEC_POSTFIX_KIND = 0x32, + SMID_SRTPS_PREFIX_KIND = 0x33, + SMID_SRTPS_POSTFIX_KIND = 0x34, + SMID_SRTPS_INFO_SRC_KIND = 0x0c +} SecureSubmsgKind_t; + +typedef struct crypto_session_key_t +{ + unsigned char data[CRYPTO_KEY_SIZE_MAX]; +} crypto_session_key_t; + +typedef struct crypto_hmac_t +{ + unsigned char data[CRYPTO_HMAC_SIZE]; +} crypto_hmac_t; + +typedef enum RTPS_Message_Type +{ + /** The Constant PAD. */ + RTPS_Message_Type_PAD = 0x01, + + /** The Constant ACKNACK. */ + RTPS_Message_Type_ACKNACK = 0x06, + + /** The Constant HEARTBEAT. */ + RTPS_Message_Type_HEARTBEAT = 0x07, + + /** The Constant GAP. */ + RTPS_Message_Type_GAP = 0x08, + + /** The Constant INFO_TS. */ + RTPS_Message_Type_INFO_TS = 0x09, + + /** The Constant INFO_SRC. */ + RTPS_Message_Type_INFO_SRC = 0x0c, + + /** The Constant INFO_REPLY_IP4. */ + RTPS_Message_Type_INFO_REPLY_IP4 = 0x0d, + + /** The Constant INFO_DST. */ + RTPS_Message_Type_INFO_DST = 0x0e, + + /** The Constant INFO_REPLY. */ + RTPS_Message_Type_INFO_REPLY = 0x0f, + + /** The Constant NACK_FRAG. */ + RTPS_Message_Type_NACK_FRAG = 0x12, + + /** The Constant HEARTBEAT_FRAG. */ + RTPS_Message_Type_HEARTBEAT_FRAG = 0x13, + + /** The Constant DATA. */ + RTPS_Message_Type_DATA = 0x15, + + /** The Constant DATA_FRAG. */ + RTPS_Message_Type_DATA_FRAG = 0x16, + + /** The Constant MSG_LENGTH. */ + RTPS_Message_Type_MSG_LEN = 0x81, + + /** The Constant MSG_ENTITY_ID. */ + RTPS_Message_Type_MSG_ENTITY_ID = 0x82, + + /** The Constant INFO_LASTHB. */ + RTPS_Message_Type_INFO_LASTHB = 0x83, + + /** The Constant SEC_PREFIX. */ + RTPS_Message_Type_SEC_BODY = 0x30, + + /** The Constant SEC_PREFIX. */ + RTPS_Message_Type_SEC_PREFIX = 0x31, + + /** The Constant SEC_POSTFIX. */ + RTPS_Message_Type_SEC_POSTFIX = 0x32, + + /** The Constant SRTPS_PREFIX. */ + RTPS_Message_Type_SRTPS_PREFIX = 0x33, + + /** The Constant SRTPS_POSTFIX. */ + RTPS_Message_Type_SRTPS_POSTFIX = 0x34 +} RTPS_Message_Type; + +#endif /* CRYPTO_DEFS_H */ \ No newline at end of file diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.c b/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.c new file mode 100644 index 0000000..f002ad7 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.c @@ -0,0 +1,538 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/dds_security_serialize.h" +#include "crypto_defs.h" +#include "crypto_utils.h" +#include "cryptography.h" +#include "crypto_key_exchange.h" +#include "crypto_key_factory.h" + +static const char *CRYPTO_TOKEN_CLASS_ID = "DDS:Crypto:AES_GCM_GMAC"; +static const char *CRYPTO_TOKEN_PROPERTY_NAME = "dds.cryp.keymat"; + +/** + * Implementation structure for storing encapsulated members of the instance + * while giving only the interface definition to user + */ + +typedef struct dds_security_crypto_key_exchange_impl +{ + dds_security_crypto_key_exchange base; + const dds_security_cryptography *crypto; +} dds_security_crypto_key_exchange_impl; + +static bool check_crypto_tokens(const DDS_Security_DataHolderSeq *tokens) +{ + bool status = true; + uint32_t i; + + if (tokens->_length == 0 || tokens->_buffer == NULL) + status = false; + + for (i = 0; status && (i < tokens->_length); i++) + { + status = (tokens->_buffer[i].class_id != NULL) && + (strcmp(CRYPTO_TOKEN_CLASS_ID, tokens->_buffer[i].class_id) == 0) && + (tokens->_buffer[i].binary_properties._length == 1) && + (tokens->_buffer[i].binary_properties._buffer != NULL) && + (tokens->_buffer[i].binary_properties._buffer[0].name != NULL) && + (strcmp(CRYPTO_TOKEN_PROPERTY_NAME, tokens->_buffer[i].binary_properties._buffer[0].name) == 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._length > 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._buffer != NULL); + } + + return status; +} + +static bool check_not_data_empty(const DDS_Security_OctetSeq *seq) +{ + uint32_t i; + + for (i = 0; i < seq->_length; i++) + { + if (seq->_buffer[i] != 0) + return true; + } + return false; +} + +static bool check_crypto_keymaterial(const DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat) +{ + bool status; + + uint32_t transform_kind = CRYPTO_TRANSFORM_KIND(keymat->transformation_kind); + uint32_t key_sz = CRYPTO_KEY_SIZE_BYTES(transform_kind); + + status = (transform_kind >= CRYPTO_TRANSFORMATION_KIND_AES128_GMAC && transform_kind <= CRYPTO_TRANSFORMATION_KIND_AES256_GCM && + keymat->master_salt._length == key_sz && keymat->master_salt._buffer != NULL && check_not_data_empty(&keymat->master_salt) && + keymat->master_sender_key._length == key_sz && keymat->master_sender_key._buffer != NULL && check_not_data_empty(&keymat->master_sender_key)); + + if (status && CRYPTO_TRANSFORM_ID(keymat->receiver_specific_key_id)) + { + status = (keymat->master_receiver_specific_key._length == key_sz && + keymat->master_receiver_specific_key._buffer != NULL && check_not_data_empty(&keymat->master_receiver_specific_key)); + } + + return status; +} + +// serialized_key_material +// { +// uint32_t transformation_kind +// uint32_t master_salt_len +// uint8_t[SALT_SIZE] master_salt +// uint32_t sender_key_id +// uint32_t master_sender_key_len +// uint8_t[KEY_SIZE] master_sender_key +// uint32_t receiver_specific_key_id +// uint32_t master_receiver_specific_key_len +// uint8_t[KEY_SIZE] master_receiver_specific_key +// } +static void +serialize_master_key_material( + const master_key_material *keymat, + uint8_t **buffer, + uint32_t *length) +{ + uint32_t *sd; + size_t i = 0; + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(keymat->transformation_kind); + size_t sz = 6 * sizeof (uint32_t) + 2 * key_bytes; + if (keymat->receiver_specific_key_id) + sz += key_bytes; + *buffer = ddsrt_malloc(sz); + *length = (uint32_t)sz; + sd = (uint32_t *)(*buffer); + + sd[i++] = ddsrt_toBE4u(keymat->transformation_kind); + sd[i++] = ddsrt_toBE4u(key_bytes); + memcpy(&sd[i], keymat->master_salt, key_bytes); + i += key_bytes / sizeof (uint32_t); + sd[i++] = ddsrt_toBE4u(keymat->sender_key_id); + sd[i++] = ddsrt_toBE4u(key_bytes); + memcpy(&sd[i], keymat->master_sender_key, key_bytes); + i += key_bytes / sizeof (uint32_t); + sd[i++] = ddsrt_toBE4u(keymat->receiver_specific_key_id); + if (keymat->receiver_specific_key_id) + { + sd[i++] = ddsrt_toBE4u(key_bytes); + memcpy(&sd[i], keymat->master_receiver_specific_key, key_bytes); + } + else + { + sd[i++] = ddsrt_toBE4u(0); + } +} + + +/** + * Function implementations + */ +static DDS_Security_boolean +create_local_participant_crypto_tokens( + dds_security_crypto_key_exchange *instance, + DDS_Security_ParticipantCryptoTokenSeq *tokens, + const DDS_Security_ParticipantCryptoHandle local_id, + const DDS_Security_ParticipantCryptoHandle remote_id, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_exchange_impl *impl = (dds_security_crypto_key_exchange_impl *)instance; + dds_security_crypto_key_factory *factory; + participant_key_material *pp_key_material; + uint8_t *buffer; + uint32_t length; + + if (!instance || !tokens || local_id == 0 || remote_id == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "create_local_participant_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_invalid_arg; + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + if (!crypto_factory_get_participant_crypto_tokens(factory, local_id, remote_id, &pp_key_material, NULL, ex)) + goto fail_invalid_arg; + serialize_master_key_material(pp_key_material->local_P2P_key_material, &buffer, &length); + CRYPTO_OBJECT_RELEASE(pp_key_material); + + tokens->_buffer = DDS_Security_DataHolderSeq_allocbuf(1); + tokens->_length = tokens->_maximum = 1; + tokens->_buffer[0].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + tokens->_buffer[0].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + tokens->_buffer[0].binary_properties._length = tokens->_buffer[0].binary_properties._maximum = 1; + tokens->_buffer[0].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + tokens->_buffer[0].binary_properties._buffer[0].value._length = + tokens->_buffer[0].binary_properties._buffer[0].value._maximum = length; + tokens->_buffer[0].binary_properties._buffer[0].value._buffer = buffer; + return true; + +fail_invalid_arg: + return false; +} + +static DDS_Security_boolean +set_remote_participant_crypto_tokens( + dds_security_crypto_key_exchange *instance, + const DDS_Security_ParticipantCryptoHandle local_id, + const DDS_Security_ParticipantCryptoHandle remote_id, + const DDS_Security_ParticipantCryptoTokenSeq *tokens, + DDS_Security_SecurityException *ex) +{ + DDS_Security_boolean result = false; + dds_security_crypto_key_exchange_impl *impl = (dds_security_crypto_key_exchange_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_KeyMaterial_AES_GCM_GMAC remote_key_mat; + const DDS_Security_OctetSeq *tdata; + DDS_Security_Deserializer deserializer; + + if (!instance || !tokens || local_id == 0 || remote_id == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "set_remote_participant_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + if (!check_crypto_tokens(tokens)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "set_remote_participant_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + tdata = &tokens->_buffer[0].binary_properties._buffer[0].value; + + deserializer = DDS_Security_Deserializer_new(tdata->_buffer, tdata->_length); + if (!deserializer) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, + "set_remote_participant_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); + result = false; + } + else if (!DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC(deserializer, &remote_key_mat)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, + "set_remote_participant_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); + result = false; + } + else if (!check_crypto_keymaterial(&remote_key_mat)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, + "set_remote_participant_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); + result = false; + } + else + { + factory = cryptography_get_crypto_key_factory(impl->crypto); + result = crypto_factory_set_participant_crypto_tokens(factory, local_id, remote_id, &remote_key_mat, ex); + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&remote_key_mat); + } + + DDS_Security_Deserializer_free(deserializer); + + return result; +} + +static DDS_Security_boolean +create_local_datawriter_crypto_tokens( + dds_security_crypto_key_exchange *instance, + DDS_Security_DatawriterCryptoTokenSeq *tokens, + const DDS_Security_DatawriterCryptoHandle local_writer_handle, + const DDS_Security_DatareaderCryptoHandle remote_reader_handle, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_exchange_impl *impl = (dds_security_crypto_key_exchange_impl *)instance; + dds_security_crypto_key_factory *factory; + master_key_material *key_mat[2]; + uint32_t num_key_mat = 2; + uint32_t i; + + if (!instance || !tokens || local_writer_handle == DDS_SECURITY_HANDLE_NIL || remote_reader_handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "create_local_datawriter_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + if (!crypto_factory_get_datawriter_crypto_tokens(factory, local_writer_handle, remote_reader_handle, key_mat, &num_key_mat, ex)) + return false; + + tokens->_length = tokens->_maximum = num_key_mat; + tokens->_buffer = (num_key_mat > 0) ? DDS_Security_DataHolderSeq_allocbuf(num_key_mat) : NULL; + + for (i = 0; i < num_key_mat; i++) + { + uint8_t *buffer; + uint32_t length; + + serialize_master_key_material(key_mat[i], &buffer, &length); + + tokens->_buffer[i].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + tokens->_buffer[i].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + tokens->_buffer[i].binary_properties._length = tokens->_buffer[0].binary_properties._maximum = 1; + tokens->_buffer[i].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + tokens->_buffer[i].binary_properties._buffer[0].value._length = + tokens->_buffer[i].binary_properties._buffer[0].value._maximum = length; + tokens->_buffer[i].binary_properties._buffer[0].value._buffer = buffer; + CRYPTO_OBJECT_RELEASE(key_mat[i]); + } + + return true; +} + +static DDS_Security_boolean +set_remote_datawriter_crypto_tokens( + dds_security_crypto_key_exchange *instance, + const DDS_Security_DatareaderCryptoHandle local_reader_handle, + const DDS_Security_DatawriterCryptoHandle remote_writer_handle, + const DDS_Security_DatawriterCryptoTokenSeq *tokens, + DDS_Security_SecurityException *ex) +{ + DDS_Security_boolean result = true; + dds_security_crypto_key_exchange_impl *impl = (dds_security_crypto_key_exchange_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_KeyMaterial_AES_GCM_GMAC remote_key_mat[2]; + uint32_t i; + + if (!instance || !tokens || local_reader_handle == DDS_SECURITY_HANDLE_NIL || remote_writer_handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "set_remote_datawriter_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + if (!check_crypto_tokens(tokens)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "set_remote_datawriter_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + if (tokens->_length > 2) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "set_remote_datawriter_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + for (i = 0; result && (i < tokens->_length); i++) + { + const DDS_Security_OctetSeq *tdata = &tokens->_buffer[i].binary_properties._buffer[0].value; + DDS_Security_Deserializer deserializer = DDS_Security_Deserializer_new(tdata->_buffer, tdata->_length); + if (!deserializer) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, + "set_remote_datawriter_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); + result = false; + } + else if (!DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC(deserializer, &remote_key_mat[i])) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, + "set_remote_datawriter_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); + result = false; + } + else if (!check_crypto_keymaterial(&remote_key_mat[i])) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, + "set_remote_datawriter_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); + result = false; + } + DDS_Security_Deserializer_free(deserializer); + } + + if (result) + { + factory = cryptography_get_crypto_key_factory(impl->crypto); + result = crypto_factory_set_datawriter_crypto_tokens(factory, local_reader_handle, remote_writer_handle, remote_key_mat, tokens->_length, ex); + } + + for (i = 0; i < tokens->_length; i++) + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&remote_key_mat[i]); + + return result; +} + +static DDS_Security_boolean +create_local_datareader_crypto_tokens( + dds_security_crypto_key_exchange *instance, + DDS_Security_DatareaderCryptoTokenSeq *tokens, + const DDS_Security_DatareaderCryptoHandle local_reader_handle, + const DDS_Security_DatawriterCryptoHandle remote_writer_handle, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_exchange_impl *impl = (dds_security_crypto_key_exchange_impl *)instance; + dds_security_crypto_key_factory *factory; + master_key_material *key_mat = NULL; + uint8_t *buffer; + uint32_t length; + + if (!instance || !tokens || local_reader_handle == DDS_SECURITY_HANDLE_NIL || remote_writer_handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "create_local_datareader_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + if (!crypto_factory_get_datareader_crypto_tokens(factory, local_reader_handle, remote_writer_handle, &key_mat, ex)) + return false; + + if (key_mat != NULL) + { /* there may be no keymaterial according to configuration */ + + serialize_master_key_material(key_mat, &buffer, &length); + + tokens->_buffer = DDS_Security_DataHolderSeq_allocbuf(1); + tokens->_length = tokens->_maximum = 1; + + tokens->_buffer[0].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + tokens->_buffer[0].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + tokens->_buffer[0].binary_properties._length = tokens->_buffer[0].binary_properties._maximum = 1; + tokens->_buffer[0].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + tokens->_buffer[0].binary_properties._buffer[0].value._length = + tokens->_buffer[0].binary_properties._buffer[0].value._maximum = length; + tokens->_buffer[0].binary_properties._buffer[0].value._buffer = buffer; + + CRYPTO_OBJECT_RELEASE(key_mat); + } + else + { + tokens->_buffer = NULL; + tokens->_length = 0; + tokens->_maximum = 0; + } + + return true; +} + +static DDS_Security_boolean +set_remote_datareader_crypto_tokens( + dds_security_crypto_key_exchange *instance, + const DDS_Security_DatawriterCryptoHandle local_writer_handle, + const DDS_Security_DatareaderCryptoHandle remote_reader_handle, + const DDS_Security_DatareaderCryptoTokenSeq *tokens, + DDS_Security_SecurityException *ex) +{ + DDS_Security_boolean result = false; + dds_security_crypto_key_exchange_impl *impl = (dds_security_crypto_key_exchange_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_KeyMaterial_AES_GCM_GMAC remote_key_mat; + const DDS_Security_OctetSeq *tdata; + DDS_Security_Deserializer deserializer; + + if (!instance || !tokens || local_writer_handle == DDS_SECURITY_HANDLE_NIL || remote_reader_handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "set_remote_datareader_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + if (!check_crypto_tokens(tokens)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "set_remote_datareader_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + tdata = &tokens->_buffer[0].binary_properties._buffer[0].value; + + deserializer = DDS_Security_Deserializer_new(tdata->_buffer, tdata->_length); + if (!deserializer) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, + "set_remote_datareader_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); + result = false; + } + else if (!DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC(deserializer, &remote_key_mat)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, + "set_remote_datareader_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); + result = false; + } + else if (!check_crypto_keymaterial(&remote_key_mat)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, + "set_remote_datareader_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); + result = false; + } + else + { + factory = cryptography_get_crypto_key_factory(impl->crypto); + result = crypto_factory_set_datareader_crypto_tokens(factory, local_writer_handle, remote_reader_handle, &remote_key_mat, ex); + } + + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&remote_key_mat); + + DDS_Security_Deserializer_free(deserializer); + + return result; +} + +static DDS_Security_boolean +return_crypto_tokens( + dds_security_crypto_key_exchange *instance, + DDS_Security_CryptoTokenSeq *tokens, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_exchange_impl *impl = (dds_security_crypto_key_exchange_impl *)instance; + + if (!impl || !tokens) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "return_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_invalid_arg; + } + + if (!check_crypto_tokens(tokens)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "set_remote_participant_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_invalid_arg; + } + + DDS_Security_CryptoTokenSeq_freebuf(tokens); + memset(tokens, 0, sizeof(*tokens)); + return true; + +fail_invalid_arg: + return false; +} + +dds_security_crypto_key_exchange * +dds_security_crypto_key_exchange__alloc( + const dds_security_cryptography *crypto) +{ + dds_security_crypto_key_exchange_impl *instance = ddsrt_malloc(sizeof(*instance)); + instance->crypto = crypto; + instance->base.create_local_participant_crypto_tokens = &create_local_participant_crypto_tokens; + instance->base.set_remote_participant_crypto_tokens = &set_remote_participant_crypto_tokens; + instance->base.create_local_datawriter_crypto_tokens = &create_local_datawriter_crypto_tokens; + instance->base.set_remote_datawriter_crypto_tokens = &set_remote_datawriter_crypto_tokens; + instance->base.create_local_datareader_crypto_tokens = &create_local_datareader_crypto_tokens; + instance->base.set_remote_datareader_crypto_tokens = &set_remote_datareader_crypto_tokens; + instance->base.return_crypto_tokens = &return_crypto_tokens; + return (dds_security_crypto_key_exchange *)instance; +} + +void dds_security_crypto_key_exchange__dealloc( + dds_security_crypto_key_exchange *instance) +{ + ddsrt_free(instance); +} diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.h b/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.h new file mode 100644 index 0000000..c1852b3 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.h @@ -0,0 +1,27 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTO_KEY_EXCHANGE_H +#define CRYPTO_KEY_EXCHANGE_H + +#include "dds/security/dds_security_api.h" + +/** + * @brief Allocation function for implementer structure (with internal variables) transparently. + */ +dds_security_crypto_key_exchange * +dds_security_crypto_key_exchange__alloc( + const dds_security_cryptography *crypto); + +void dds_security_crypto_key_exchange__dealloc( + dds_security_crypto_key_exchange *instance); + +#endif /* CRYPTO_KEY_EXCHANGE_H */ diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.c b/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.c new file mode 100644 index 0000000..833ca01 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.c @@ -0,0 +1,1869 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include +#include +#include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/shared_secret.h" +#include "crypto_defs.h" +#include "crypto_utils.h" +#include "crypto_cipher.h" +#include "crypto_key_factory.h" +#include "crypto_objects.h" + +/** + * Implementation structure for storing encapsulated members of the instance + * while giving only the interface definition to user + */ + +#define KXKEYCOOKIE "key exchange key" +#define KXSALTCOOKIE "keyexchange salt" + +typedef struct dds_security_crypto_key_factory_impl +{ + dds_security_crypto_key_factory base; + const dds_security_cryptography *crypto; + ddsrt_mutex_t lock; + struct CryptoObjectTable *crypto_objects; /* table for storing CryptoHandle - ParticipantKeyMaterial pairs */ + ddsrt_atomic_uint32_t next_key_id; +} dds_security_crypto_key_factory_impl; + +static void +crypto_token_copy( + master_key_material *dst, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *src) +{ + DDS_Security_CryptoTransformKind_Enum src_transform_kind = CRYPTO_TRANSFORM_KIND(src->transformation_kind); + + if (CRYPTO_TRANSFORM_HAS_KEYS(dst->transformation_kind)) + { + ddsrt_free(dst->master_salt); + ddsrt_free(dst->master_sender_key); + ddsrt_free(dst->master_receiver_specific_key); + } + if (CRYPTO_TRANSFORM_HAS_KEYS(src_transform_kind)) + { + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(src_transform_kind); + dst->master_salt = ddsrt_calloc(1, key_bytes); + dst->master_sender_key = ddsrt_calloc(1, key_bytes); + dst->master_receiver_specific_key = ddsrt_calloc(1, key_bytes); + memcpy(dst->master_salt, src->master_salt._buffer, key_bytes); + dst->sender_key_id = CRYPTO_TRANSFORM_ID(src->sender_key_id); + memcpy(dst->master_sender_key, src->master_sender_key._buffer, key_bytes); + dst->receiver_specific_key_id = CRYPTO_TRANSFORM_ID(src->receiver_specific_key_id); + if (dst->receiver_specific_key_id) + memcpy(dst->master_receiver_specific_key, src->master_receiver_specific_key._buffer, key_bytes); + } + dst->transformation_kind = src_transform_kind; +}; + +/* Compute KeyMaterial_AES_GCM_GMAC as described in DDS Security spec v1.1 section 9.5.2.1.2 (table 67 and table 68) */ +static bool +calculate_kx_keys( + const DDS_Security_SharedSecretHandle shared_secret, + master_key_material *kx_key_material, + DDS_Security_SecurityException *ex) +{ + bool result = false; + const DDS_Security_octet *challenge1, *challenge2, *shared_secret_key; + unsigned char *kx_master_salt, *kx_master_sender_key; + size_t shared_secret_size = get_secret_size_from_secret_handle(shared_secret); + unsigned char hash[SHA256_DIGEST_LENGTH]; + size_t concatenated_bytes1_size = DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE * 2 + sizeof(KXSALTCOOKIE); + size_t concatenated_bytes2_size = DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE * 2 + sizeof(KXKEYCOOKIE); + DDS_Security_octet *concatenated_bytes1, *concatenated_bytes2; + + memset(ex, 0, sizeof(*ex)); + + if (shared_secret_size > UINT32_MAX) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, 0, "shared_secret_size > UINT32_MAX"); + goto fail_kx; + } + concatenated_bytes1 = ddsrt_malloc(concatenated_bytes1_size); + concatenated_bytes2 = ddsrt_malloc(concatenated_bytes2_size); + challenge1 = get_challenge1_from_secret_handle(shared_secret); + challenge2 = get_challenge2_from_secret_handle(shared_secret); + shared_secret_key = get_secret_from_secret_handle(shared_secret); + + /* master_salt */ + memcpy(concatenated_bytes1, challenge1, DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE); + memcpy(concatenated_bytes1 + DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE, KXSALTCOOKIE, sizeof(KXSALTCOOKIE)); + memcpy(concatenated_bytes1 + DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE + sizeof(KXSALTCOOKIE), challenge2, + DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE); + + SHA256(concatenated_bytes1, concatenated_bytes1_size, hash); + if (!(kx_master_salt = crypto_hmac256(hash, SHA256_DIGEST_LENGTH, shared_secret_key, (uint32_t) shared_secret_size, ex))) + goto fail_kx_salt; + + /* master_sender_key */ + memcpy(concatenated_bytes2, challenge2, DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE); + memcpy(concatenated_bytes2 + DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE, KXKEYCOOKIE, sizeof(KXKEYCOOKIE)); + memcpy(concatenated_bytes2 + DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE + sizeof(KXKEYCOOKIE), challenge1, + DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE); + + SHA256(concatenated_bytes2, concatenated_bytes2_size, hash); + if (!(kx_master_sender_key = crypto_hmac256(hash, SHA256_DIGEST_LENGTH, shared_secret_key, (uint32_t) shared_secret_size, ex))) + goto fail_kx_key; + + assert (kx_key_material->transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES256_GCM); /* set in crypto_participant_key_material_new */ + memcpy(kx_key_material->master_salt, kx_master_salt, CRYPTO_KEY_SIZE_256); + kx_key_material->sender_key_id = 0; + memcpy(kx_key_material->master_sender_key, kx_master_sender_key, CRYPTO_KEY_SIZE_256); + kx_key_material->receiver_specific_key_id = 0; + + memset (kx_master_sender_key, 0, CRYPTO_KEY_SIZE_256); + ddsrt_free(kx_master_sender_key); + result = true; + +fail_kx_key: + memset (kx_master_salt, 0, CRYPTO_KEY_SIZE_256); + ddsrt_free(kx_master_salt); +fail_kx_salt: + ddsrt_free(concatenated_bytes2); + ddsrt_free(concatenated_bytes1); +fail_kx: + return result; +} + +static uint32_t +generate_key( + dds_security_crypto_key_factory_impl *implementation, + master_key_material *key_material, + DDS_Security_SecurityException *ex) +{ + assert (key_material->transformation_kind != CRYPTO_TRANSFORMATION_KIND_NONE); + if (RAND_bytes(key_material->master_salt, (int)CRYPTO_KEY_SIZE_BYTES(key_material->transformation_kind)) < 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_CODE, 0, + DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_MESSAGE); + return DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_CODE; + } + if (RAND_bytes(key_material->master_sender_key, (int)CRYPTO_KEY_SIZE_BYTES(key_material->transformation_kind)) < 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_CODE, 0, + DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_MESSAGE); + return DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_CODE; + } + key_material->sender_key_id = ddsrt_atomic_inc32_ov(&implementation->next_key_id); + return DDS_SECURITY_ERR_OK_CODE; +} + +static DDS_Security_ProtectionKind +attribute_to_rtps_protection_kind( + const DDS_Security_ParticipantSecurityAttributes *attributes) +{ + DDS_Security_ProtectionKind kind = DDS_SECURITY_PROTECTION_KIND_NONE; + assert(attributes); + if (attributes->is_rtps_protected) + { + if (attributes->plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED) + { + if (attributes->plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED) + kind = DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION; + else + kind = DDS_SECURITY_PROTECTION_KIND_ENCRYPT; + } + else + { + if (attributes->plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED) + kind = DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION; + else + kind = DDS_SECURITY_PROTECTION_KIND_SIGN; + } + } + + return kind; +} + +static DDS_Security_ProtectionKind +attribute_to_meta_protection_kind( + const DDS_Security_EndpointSecurityAttributes *attributes) +{ + DDS_Security_ProtectionKind kind = DDS_SECURITY_PROTECTION_KIND_NONE; + assert(attributes); + if (attributes->is_submessage_protected) + { + if (attributes->plugin_endpoint_attributes & DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED) + { + if (attributes->plugin_endpoint_attributes & DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED) + kind = DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION; + else + kind = DDS_SECURITY_PROTECTION_KIND_ENCRYPT; + } + else + { + if (attributes->plugin_endpoint_attributes & DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED) + kind = DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION; + else + kind = DDS_SECURITY_PROTECTION_KIND_SIGN; + } + } + + return kind; +} + +static DDS_Security_BasicProtectionKind +attribute_to_data_protection_kind( + const DDS_Security_EndpointSecurityAttributes *attributes) +{ + DDS_Security_BasicProtectionKind kind = DDS_SECURITY_BASICPROTECTION_KIND_NONE; + assert(attributes); + if (attributes->is_payload_protected) + { + if (attributes->plugin_endpoint_attributes & DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED) + kind = DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT; + else + kind = DDS_SECURITY_BASICPROTECTION_KIND_SIGN; + } + return kind; +} + +static void +remove_relation_from_keymaterial( + const participant_key_material *key_material, + CryptoObject *local_crypto, + CryptoObject *remote_crypto) +{ + endpoint_relation *relation; + relation = crypto_endpoint_relation_find_by_crypto(key_material->endpoint_relations, local_crypto, remote_crypto); + if (relation) + { + crypto_object_table_remove_object(key_material->endpoint_relations, (CryptoObject *)relation); + CRYPTO_OBJECT_RELEASE(relation); + } +} + +static void +remove_remote_writer_relation( + dds_security_crypto_key_factory_impl *implementation, + remote_datawriter_crypto *remote_writer) +{ + local_datareader_crypto *local_reader; + remote_participant_crypto *remote_participant; + participant_key_material *key_material; + + assert(remote_writer); + remote_participant = remote_writer->participant; + assert(remote_participant); + local_reader = (local_datareader_crypto *)crypto_object_table_find(implementation->crypto_objects, remote_writer->local_reader_handle); + if (local_reader) + { + key_material = (participant_key_material *)crypto_object_table_find( + remote_participant->key_material, CRYPTO_OBJECT_HANDLE(local_reader->participant)); + if (key_material) + { + remove_relation_from_keymaterial(key_material, (CryptoObject *)local_reader, (CryptoObject *)remote_writer); + CRYPTO_OBJECT_RELEASE(key_material); + } + CRYPTO_OBJECT_RELEASE(local_reader); + } +} + +static void +remove_remote_reader_relation( + dds_security_crypto_key_factory_impl *implementation, + remote_datareader_crypto *remote_reader) +{ + local_datawriter_crypto *local_writer; + remote_participant_crypto *remote_participant; + participant_key_material *key_material; + + assert(remote_reader); + remote_participant = remote_reader->participant; + assert(remote_participant); + local_writer = (local_datawriter_crypto *)crypto_object_table_find(implementation->crypto_objects, remote_reader->local_writer_handle); + if (local_writer) + { + key_material = (participant_key_material *)crypto_object_table_find( + remote_participant->key_material, CRYPTO_OBJECT_HANDLE(local_writer->participant)); + if (key_material) + { + remove_relation_from_keymaterial(key_material, (CryptoObject *)local_writer, (CryptoObject *)remote_reader); + CRYPTO_OBJECT_RELEASE(key_material); + } + CRYPTO_OBJECT_RELEASE(local_writer); + } +} + +/** + * Function implementations + */ + +static DDS_Security_ParticipantCryptoHandle +register_local_participant( + dds_security_crypto_key_factory *instance, + const DDS_Security_IdentityHandle participant_identity, + const DDS_Security_PermissionsHandle participant_permissions, + const DDS_Security_PropertySeq *participant_properties, + const DDS_Security_ParticipantSecurityAttributes *participant_security_attributes, + DDS_Security_SecurityException *ex) +{ + local_participant_crypto *participant_crypto; + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + + if ((participant_identity == DDS_SECURITY_HANDLE_NIL) || + (participant_permissions == DDS_SECURITY_HANDLE_NIL)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, + DDS_SECURITY_ERR_IDENTITY_EMPTY_MESSAGE); + goto err_invalid_argument; + } + + /*init objects */ + participant_crypto = crypto_local_participant_crypto__new(participant_identity); + participant_crypto->rtps_protection_kind = attribute_to_rtps_protection_kind(participant_security_attributes); + participant_crypto->key_material = crypto_master_key_material_new( + DDS_Security_protectionkind2transformationkind(participant_properties, participant_crypto->rtps_protection_kind)); + + /* No need to create session material if there is no protection for RTPS */ + if (participant_crypto->key_material->transformation_kind != CRYPTO_TRANSFORMATION_KIND_NONE) + { + if (generate_key(implementation, participant_crypto->key_material, ex) != DDS_SECURITY_ERR_OK_CODE) + goto err_random_generation; + participant_crypto->session = crypto_session_key_material_new(participant_crypto->key_material); + } + + crypto_object_table_insert(implementation->crypto_objects, (CryptoObject *)participant_crypto); + CRYPTO_OBJECT_RELEASE(participant_crypto); + + return PARTICIPANT_CRYPTO_HANDLE(participant_crypto); + + /* error cases*/ +err_random_generation: + CRYPTO_OBJECT_RELEASE(participant_crypto); +err_invalid_argument: + return DDS_SECURITY_HANDLE_NIL; +} + +struct resolve_remote_part_arg +{ + DDS_Security_IdentityHandle ident; + remote_participant_crypto *pprmte; +}; + +static int +resolve_remote_participant_by_id( + CryptoObject *obj, + void *arg) +{ + struct resolve_remote_part_arg *info = arg; + + remote_participant_crypto *pprmte; + if (obj->kind == CRYPTO_OBJECT_KIND_REMOTE_CRYPTO) + { + pprmte = (remote_participant_crypto *)obj; + if (pprmte->identity_handle == info->ident) + { + info->pprmte = (remote_participant_crypto *)CRYPTO_OBJECT_KEEP(pprmte); + return 0; + } + } + + return 1; +} + +static DDS_Security_ParticipantCryptoHandle +register_matched_remote_participant( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle local_participant_crypto_handle, + const DDS_Security_IdentityHandle remote_participant_identity, + const DDS_Security_PermissionsHandle remote_participant_permissions, + const DDS_Security_SharedSecretHandle shared_secret, + DDS_Security_SecurityException *ex) +{ + /* declarations */ + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + remote_participant_crypto *participant_crypto; + local_participant_crypto *local_participant_crypto_ref; + DDS_Security_SecurityException exception; + participant_key_material *key_material; + + if (local_participant_crypto_handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_PARTICIPANT_CRYPTO_HANDLE_EMPTY_CODE, 0, + DDS_SECURITY_ERR_PARTICIPANT_CRYPTO_HANDLE_EMPTY_MESSAGE); + goto err_invalid_argument; + } + else if (remote_participant_identity == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, + DDS_SECURITY_ERR_IDENTITY_EMPTY_MESSAGE); + goto err_invalid_argument; + } + else if (remote_participant_permissions == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_PERMISSION_HANDLE_EMPTY_CODE, 0, + DDS_SECURITY_ERR_PERMISSION_HANDLE_EMPTY_MESSAGE); + goto err_invalid_argument; + } + + /* Check if local_participant_crypto_handle exists in the map */ + + local_participant_crypto_ref = (local_participant_crypto *)crypto_object_table_find(implementation->crypto_objects, local_participant_crypto_handle); + if (local_participant_crypto_ref == NULL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_argument; + } + + /* find or create remote participant crypto structure */ + { + struct resolve_remote_part_arg arg = {remote_participant_identity, NULL}; + crypto_object_table_walk(implementation->crypto_objects, resolve_remote_participant_by_id, &arg); + if (arg.pprmte) + { + participant_crypto = arg.pprmte; + } + else + { + participant_crypto = crypto_remote_participant_crypto__new(remote_participant_identity); + crypto_object_table_insert(implementation->crypto_objects, (CryptoObject *)participant_crypto); + } + } + + key_material = (participant_key_material *)crypto_object_table_find(participant_crypto->key_material, local_participant_crypto_ref->_parent.handle); + + if (!key_material) + { + key_material = crypto_participant_key_material_new(local_participant_crypto_ref); + + /* set remote participant keymaterial with local keymaterial values */ + crypto_master_key_material_set(key_material->local_P2P_key_material, local_participant_crypto_ref->key_material); + + if (!calculate_kx_keys(shared_secret, key_material->P2P_kx_key_material, &exception)) + goto fail_calc_key; + + key_material->P2P_writer_session = crypto_session_key_material_new(key_material->P2P_kx_key_material); + key_material->P2P_reader_session = crypto_session_key_material_new(key_material->P2P_kx_key_material); + + /* if we do not have OriginAuthentication, receiver specific info remains empty/NULL */ + if ((local_participant_crypto_ref->rtps_protection_kind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION) || + (local_participant_crypto_ref->rtps_protection_kind == DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION)) + { + if (RAND_bytes(key_material->local_P2P_key_material->master_receiver_specific_key, (int)CRYPTO_KEY_SIZE_BYTES(key_material->local_P2P_key_material->transformation_kind)) < 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_CODE, 0, + DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_MESSAGE); + goto err_random_generation; + } + key_material->local_P2P_key_material->receiver_specific_key_id = ddsrt_atomic_inc32_ov(&implementation->next_key_id); + } + participant_crypto->session = (session_key_material *)CRYPTO_OBJECT_KEEP(local_participant_crypto_ref->session); + + crypto_object_table_insert(participant_crypto->key_material, (CryptoObject *)key_material); + } + + participant_crypto->rtps_protection_kind = local_participant_crypto_ref->rtps_protection_kind; /* Same as local */ + + CRYPTO_OBJECT_RELEASE(key_material); + CRYPTO_OBJECT_RELEASE(participant_crypto); + CRYPTO_OBJECT_RELEASE(local_participant_crypto_ref); + + return PARTICIPANT_CRYPTO_HANDLE(participant_crypto); + +/* error cases*/ +err_random_generation: +fail_calc_key: + CRYPTO_OBJECT_RELEASE(key_material); + CRYPTO_OBJECT_RELEASE(participant_crypto); + CRYPTO_OBJECT_RELEASE(local_participant_crypto_ref); +err_invalid_argument: + return DDS_SECURITY_HANDLE_NIL; +} + +static DDS_Security_DatawriterCryptoHandle +register_local_datawriter( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle participant_crypto_handle, + const DDS_Security_PropertySeq *datawriter_properties, + const DDS_Security_EndpointSecurityAttributes *datawriter_security_attributes, + DDS_Security_SecurityException *ex) +{ + local_participant_crypto *participant_crypto; + local_datawriter_crypto *writer_crypto; + bool is_builtin = false; + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + DDS_Security_ProtectionKind metadata_protection; + DDS_Security_BasicProtectionKind data_protection; + + memset(ex, 0, sizeof(*ex)); + + if (participant_crypto_handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + participant_crypto = (local_participant_crypto *)crypto_object_table_find(implementation->crypto_objects, participant_crypto_handle); + if (!participant_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + if (datawriter_properties != NULL && datawriter_properties->_length > 0) + { + const DDS_Security_Property_t *property = DDS_Security_PropertySeq_find_property( + datawriter_properties, "dds.sec.builtin_endpoint_name"); + if (property != NULL && strcmp(property->value, "BuiltinParticipantVolatileMessageSecureWriter") == 0) + is_builtin = true; + } + + data_protection = attribute_to_data_protection_kind(datawriter_security_attributes); + metadata_protection = attribute_to_meta_protection_kind(datawriter_security_attributes); + + writer_crypto = crypto_local_datawriter_crypto__new(participant_crypto, metadata_protection, data_protection); + writer_crypto->is_builtin_participant_volatile_message_secure_writer = is_builtin; + + if (!is_builtin) + { + if (writer_crypto->metadata_protectionKind != DDS_SECURITY_PROTECTION_KIND_NONE) + { + writer_crypto->writer_key_material_message = crypto_master_key_material_new( + DDS_Security_protectionkind2transformationkind(datawriter_properties, metadata_protection)); + if (generate_key(implementation, writer_crypto->writer_key_material_message, ex) != DDS_SECURITY_ERR_OK_CODE) + goto err_random_generation; + writer_crypto->writer_session_message = crypto_session_key_material_new(writer_crypto->writer_key_material_message); + } + + if (writer_crypto->data_protectionKind != DDS_SECURITY_BASICPROTECTION_KIND_NONE) + { + writer_crypto->writer_key_material_payload = crypto_master_key_material_new( + DDS_Security_basicprotectionkind2transformationkind(datawriter_properties, data_protection)); + if (generate_key(implementation, writer_crypto->writer_key_material_payload, ex) != DDS_SECURITY_ERR_OK_CODE) + goto err_random_generation; + writer_crypto->writer_session_payload = crypto_session_key_material_new(writer_crypto->writer_key_material_payload); + } + } + + crypto_object_table_insert(implementation->crypto_objects, (CryptoObject *)writer_crypto); + CRYPTO_OBJECT_RELEASE(participant_crypto); + CRYPTO_OBJECT_RELEASE(writer_crypto); + return writer_crypto->_parent.handle; + +err_random_generation: + CRYPTO_OBJECT_RELEASE(participant_crypto); + CRYPTO_OBJECT_RELEASE(writer_crypto); +err_invalid_parameter: + return DDS_SECURITY_HANDLE_NIL; +} + +static DDS_Security_DatareaderCryptoHandle +register_matched_remote_datareader( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatawriterCryptoHandle local_datawriter_crypto_handle, + const DDS_Security_ParticipantCryptoHandle remote_participant_crypto_handle, + const DDS_Security_SharedSecretHandle shared_secret, + const DDS_Security_boolean relay_only, DDS_Security_SecurityException *ex) +{ + remote_datareader_crypto *reader_crypto; + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + local_datawriter_crypto *local_writer; + remote_participant_crypto *remote_participant; + DDS_Security_ProtectionKind metadata_protectionKind; + DDS_Security_BasicProtectionKind data_protectionKind; + + memset(ex, 0, sizeof(*ex)); + + DDSRT_UNUSED_ARG(shared_secret); + DDSRT_UNUSED_ARG(relay_only); + + if ((remote_participant_crypto_handle == DDS_SECURITY_HANDLE_NIL) || + (local_datawriter_crypto_handle == DDS_SECURITY_HANDLE_NIL)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + remote_participant = (remote_participant_crypto *)crypto_object_table_find(implementation->crypto_objects, remote_participant_crypto_handle); + if (!remote_participant) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + local_writer = (local_datawriter_crypto *)crypto_object_table_find(implementation->crypto_objects, local_datawriter_crypto_handle); + if (!local_writer) + { + CRYPTO_OBJECT_RELEASE(remote_participant); + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + data_protectionKind = local_writer->data_protectionKind; + metadata_protectionKind = local_writer->metadata_protectionKind; + + reader_crypto = crypto_remote_datareader_crypto__new(remote_participant, metadata_protectionKind, data_protectionKind, local_datawriter_crypto_handle); + + /* check if the writer is BuiltinParticipantVolatileMessageSecureWriter */ + if (local_writer->is_builtin_participant_volatile_message_secure_writer) + { + participant_key_material *key_material; + + key_material = (participant_key_material *)crypto_object_table_find(remote_participant->key_material, CRYPTO_OBJECT_HANDLE(local_writer->participant)); + assert(key_material); + + reader_crypto->reader2writer_key_material = (master_key_material *)CRYPTO_OBJECT_KEEP(key_material->P2P_kx_key_material); + reader_crypto->writer2reader_key_material_message = (master_key_material *)CRYPTO_OBJECT_KEEP(key_material->P2P_kx_key_material); + reader_crypto->writer_session = (session_key_material *)CRYPTO_OBJECT_KEEP(key_material->P2P_writer_session); + reader_crypto->is_builtin_participant_volatile_message_secure_reader = true; + CRYPTO_OBJECT_RELEASE(key_material); + } + else + { + if (local_writer->writer_key_material_message) + { + reader_crypto->writer2reader_key_material_message = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_NONE); + crypto_master_key_material_set(reader_crypto->writer2reader_key_material_message, local_writer->writer_key_material_message); + if ((metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION) || + (metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION)) + { + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(reader_crypto->writer2reader_key_material_message->transformation_kind); + if (RAND_bytes(reader_crypto->writer2reader_key_material_message->master_receiver_specific_key, (int)key_bytes) < 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_CODE, 0, + DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_MESSAGE); + goto err_random_generation; + } + reader_crypto->writer2reader_key_material_message->receiver_specific_key_id = ddsrt_atomic_inc32_ov(&implementation->next_key_id); + } + reader_crypto->writer_session = (session_key_material *)CRYPTO_OBJECT_KEEP(local_writer->writer_session_message); + } + + if (local_writer->writer_key_material_payload) + { + reader_crypto->writer2reader_key_material_payload = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_NONE); + crypto_master_key_material_set(reader_crypto->writer2reader_key_material_payload, local_writer->writer_key_material_payload); + } + } + + crypto_object_table_insert(implementation->crypto_objects, (CryptoObject *)reader_crypto); + CRYPTO_OBJECT_RELEASE(remote_participant); + CRYPTO_OBJECT_RELEASE(local_writer); + CRYPTO_OBJECT_RELEASE(reader_crypto); + return DATAREADER_CRYPTO_HANDLE(reader_crypto); + +err_random_generation: + CRYPTO_OBJECT_RELEASE(reader_crypto); + CRYPTO_OBJECT_RELEASE(remote_participant); + CRYPTO_OBJECT_RELEASE(local_writer); +err_invalid_parameter: + return DDS_SECURITY_HANDLE_NIL; +} + +static DDS_Security_DatareaderCryptoHandle +register_local_datareader( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle participant_crypto_handle, + const DDS_Security_PropertySeq *datareader_properties, + const DDS_Security_EndpointSecurityAttributes *datareader_security_attributes, + DDS_Security_SecurityException *ex) +{ + local_participant_crypto *participant_crypto; + local_datareader_crypto *reader_crypto; + bool is_builtin = false; + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + DDS_Security_ProtectionKind metadata_protection; + DDS_Security_BasicProtectionKind data_protection; + + if (!instance || (participant_crypto_handle == DDS_SECURITY_HANDLE_NIL)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + participant_crypto = (local_participant_crypto *)crypto_object_table_find(implementation->crypto_objects, participant_crypto_handle); + if (!participant_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + if (datareader_properties != NULL && datareader_properties->_length > 0) + { + const DDS_Security_Property_t *property = DDS_Security_PropertySeq_find_property( + datareader_properties, "dds.sec.builtin_endpoint_name"); + if (property != NULL && strcmp(property->value, "BuiltinParticipantVolatileMessageSecureReader") == 0) + is_builtin = true; + } + + data_protection = attribute_to_data_protection_kind(datareader_security_attributes); + metadata_protection = attribute_to_meta_protection_kind(datareader_security_attributes); + + reader_crypto = crypto_local_datareader_crypto__new(participant_crypto, metadata_protection, data_protection); + reader_crypto->is_builtin_participant_volatile_message_secure_reader = is_builtin; + + if (!is_builtin) + { + if (reader_crypto->metadata_protectionKind != DDS_SECURITY_PROTECTION_KIND_NONE) + { + reader_crypto->reader_key_material = crypto_master_key_material_new( + DDS_Security_protectionkind2transformationkind(datareader_properties, metadata_protection)); + if (generate_key(implementation, reader_crypto->reader_key_material, ex) != DDS_SECURITY_ERR_OK_CODE) + goto err_random_generation; + reader_crypto->reader_session = crypto_session_key_material_new(reader_crypto->reader_key_material); + } + } + + crypto_object_table_insert(implementation->crypto_objects, (CryptoObject *)reader_crypto); + CRYPTO_OBJECT_RELEASE(participant_crypto); + CRYPTO_OBJECT_RELEASE(reader_crypto); + return DATAREADER_CRYPTO_HANDLE(reader_crypto); + +err_random_generation: + CRYPTO_OBJECT_RELEASE(participant_crypto); + CRYPTO_OBJECT_RELEASE(reader_crypto); +err_invalid_parameter: + return DDS_SECURITY_HANDLE_NIL; +} + +static DDS_Security_DatawriterCryptoHandle +register_matched_remote_datawriter( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatareaderCryptoHandle local_datareader_crypto_handle, + const DDS_Security_ParticipantCryptoHandle remote_participant_crypto_handle, + const DDS_Security_SharedSecretHandle shared_secret, + DDS_Security_SecurityException *ex) +{ + remote_datawriter_crypto *writer_crypto; + dds_security_crypto_key_factory_impl *implementation = + (dds_security_crypto_key_factory_impl *)instance; + local_datareader_crypto *local_reader; + remote_participant_crypto *remote_participant; + + DDSRT_UNUSED_ARG(shared_secret); + + if ((remote_participant_crypto_handle == DDS_SECURITY_HANDLE_NIL) || + (local_datareader_crypto_handle == DDS_SECURITY_HANDLE_NIL)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + remote_participant = (remote_participant_crypto *)crypto_object_table_find(implementation->crypto_objects, remote_participant_crypto_handle); + if (!remote_participant) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + local_reader = (local_datareader_crypto *)crypto_object_table_find(implementation->crypto_objects, local_datareader_crypto_handle); + if (!local_reader) + { + CRYPTO_OBJECT_RELEASE(remote_participant); + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + writer_crypto = crypto_remote_datawriter_crypto__new(remote_participant, local_reader->metadata_protectionKind, + local_reader->data_protectionKind, local_datareader_crypto_handle); + + /* check if the writer is BuiltinParticipantVolatileMessageSecureWriter */ + if (local_reader->is_builtin_participant_volatile_message_secure_reader) + { + participant_key_material *key_material; + endpoint_relation *relation; + + key_material = (participant_key_material *)crypto_object_table_find(remote_participant->key_material, CRYPTO_OBJECT_HANDLE(local_reader->participant)); + assert(key_material); + + writer_crypto->reader2writer_key_material = (master_key_material *)CRYPTO_OBJECT_KEEP(key_material->P2P_kx_key_material); + writer_crypto->writer2reader_key_material[0] = (master_key_material *)CRYPTO_OBJECT_KEEP(key_material->P2P_kx_key_material); + writer_crypto->writer2reader_key_material[1] = (master_key_material *)CRYPTO_OBJECT_KEEP(key_material->P2P_kx_key_material); + writer_crypto->reader_session = (session_key_material *)CRYPTO_OBJECT_KEEP(key_material->P2P_reader_session); + writer_crypto->is_builtin_participant_volatile_message_secure_writer = true; + + relation = crypto_endpoint_relation_new(DDS_SECURITY_DATAWRITER_SUBMESSAGE, 0, (CryptoObject *)local_reader, (CryptoObject *)writer_crypto); + crypto_object_table_insert(key_material->endpoint_relations, (CryptoObject *)relation); + CRYPTO_OBJECT_RELEASE(relation); + CRYPTO_OBJECT_RELEASE(key_material); + } + else if (local_reader->metadata_protectionKind != DDS_SECURITY_PROTECTION_KIND_NONE) + { + writer_crypto->reader2writer_key_material = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_NONE); + crypto_master_key_material_set(writer_crypto->reader2writer_key_material, local_reader->reader_key_material); + + if (local_reader->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION + || local_reader->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION) + { + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(writer_crypto->reader2writer_key_material->transformation_kind); + if (RAND_bytes(writer_crypto->reader2writer_key_material->master_receiver_specific_key, (int)key_bytes) < 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_CODE, 0, + DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_MESSAGE); + goto err_random_generation; + } + writer_crypto->reader2writer_key_material->receiver_specific_key_id = ddsrt_atomic_inc32_ov(&implementation->next_key_id); + writer_crypto->reader_session = (session_key_material *)CRYPTO_OBJECT_KEEP(local_reader->reader_session); + } + } + crypto_object_table_insert(implementation->crypto_objects, (CryptoObject *)writer_crypto); + CRYPTO_OBJECT_RELEASE(remote_participant); + CRYPTO_OBJECT_RELEASE(local_reader); + CRYPTO_OBJECT_RELEASE(writer_crypto); + return DATAREADER_CRYPTO_HANDLE(writer_crypto); + +err_random_generation: + CRYPTO_OBJECT_RELEASE(writer_crypto); + CRYPTO_OBJECT_RELEASE(remote_participant); + CRYPTO_OBJECT_RELEASE(local_reader); +err_invalid_parameter: + return DDS_SECURITY_HANDLE_NIL; +} + +static DDS_Security_boolean +unregister_participant( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle participant_crypto_handle, + DDS_Security_SecurityException *ex) +{ + DDS_Security_boolean result = false; + CryptoObject *obj; + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + + if ((obj = crypto_object_table_find(implementation->crypto_objects, participant_crypto_handle)) != NULL) + { + if ((obj->kind == CRYPTO_OBJECT_KIND_LOCAL_CRYPTO) || (obj->kind == CRYPTO_OBJECT_KIND_REMOTE_CRYPTO)) + { + crypto_object_table_remove_object(implementation->crypto_objects, obj); + result = true; + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + } + CRYPTO_OBJECT_RELEASE(obj); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + } + + return result; +} + +static DDS_Security_boolean +unregister_datawriter( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatawriterCryptoHandle datawriter_crypto_handle, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + DDS_Security_boolean result = false; + CryptoObject *obj; + + /* check if the handle is applicable*/ + if ((obj = crypto_object_table_find(implementation->crypto_objects, datawriter_crypto_handle)) != NULL) + { + if ((obj->kind == CRYPTO_OBJECT_KIND_LOCAL_WRITER_CRYPTO) || (obj->kind == CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO)) + { + if (obj->kind == CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO) + remove_remote_writer_relation(implementation, (remote_datawriter_crypto *)obj); + crypto_object_table_remove_object(implementation->crypto_objects, obj); + result = true; + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + } + CRYPTO_OBJECT_RELEASE(obj); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + } + + return result; +} + +static DDS_Security_boolean +unregister_datareader( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatareaderCryptoHandle datareader_crypto_handle, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + DDS_Security_boolean result = false; + CryptoObject *obj; + + /* check if the handle is applicable*/ + if ((obj = crypto_object_table_find(implementation->crypto_objects, datareader_crypto_handle)) != NULL) + { + if ((obj->kind == CRYPTO_OBJECT_KIND_LOCAL_READER_CRYPTO) || (obj->kind == CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO)) + { + if (obj->kind == CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO) + remove_remote_reader_relation(implementation, (remote_datareader_crypto *)obj); + crypto_object_table_remove_object(implementation->crypto_objects, obj); + result = true; + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + } + CRYPTO_OBJECT_RELEASE(obj); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + } + + return result; +} + +dds_security_crypto_key_factory * +dds_security_crypto_key_factory__alloc( + const dds_security_cryptography *crypto) +{ + dds_security_crypto_key_factory_impl *instance = ddsrt_malloc(sizeof(*instance)); + + ddsrt_mutex_init(&instance->lock); + + instance->crypto = crypto; + instance->base.register_local_participant = ®ister_local_participant; + instance->base.register_matched_remote_participant = ®ister_matched_remote_participant; + instance->base.register_local_datawriter = ®ister_local_datawriter; + instance->base.register_matched_remote_datareader = ®ister_matched_remote_datareader; + instance->base.register_local_datareader = ®ister_local_datareader; + instance->base.register_matched_remote_datawriter = ®ister_matched_remote_datawriter; + instance->base.unregister_participant = &unregister_participant; + instance->base.unregister_datawriter = &unregister_datawriter; + instance->base.unregister_datareader = &unregister_datareader; + + /* init implementation specific members */ + instance->crypto_objects = crypto_object_table_new(NULL, NULL, NULL); + + ddsrt_atomic_st32 (&instance->next_key_id, 1); + + return (dds_security_crypto_key_factory *)instance; +} + +void dds_security_crypto_key_factory__dealloc(dds_security_crypto_key_factory *instance) +{ + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + ddsrt_mutex_destroy (&implementation->lock); + crypto_object_table_free(implementation->crypto_objects); + ddsrt_free(implementation); +} + +bool +crypto_factory_get_participant_crypto_tokens( + const dds_security_crypto_key_factory *factory, + DDS_Security_ParticipantCryptoHandle local_id, + DDS_Security_ParticipantCryptoHandle remote_id, + participant_key_material **pp_key_material, + DDS_Security_ProtectionKind *protection_kind, + + DDS_Security_SecurityException *ex) +{ + assert (pp_key_material != NULL); + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_participant_crypto *remote_crypto = (remote_participant_crypto *)crypto_object_table_find(impl->crypto_objects, remote_id); + bool result = false; + if (!remote_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_remote; + } + else if (!CRYPTO_OBJECT_VALID(remote_crypto, CRYPTO_OBJECT_KIND_REMOTE_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_remote; + } + + if (!(*pp_key_material = (participant_key_material *)crypto_object_table_find(remote_crypto->key_material, local_id))) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_remote; + } + if (protection_kind != NULL) + *protection_kind = remote_crypto->rtps_protection_kind; + result = true; + +err_remote: + CRYPTO_OBJECT_RELEASE(remote_crypto); +err_no_remote: + return result; +} + +bool +crypto_factory_set_participant_crypto_tokens( + const dds_security_crypto_key_factory *factory, + const DDS_Security_ParticipantCryptoHandle local_id, + const DDS_Security_ParticipantCryptoHandle remote_id, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *remote_key_mat, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_participant_crypto *remote_crypto; + participant_key_material *key_material; + bool result = false; + + remote_crypto = (remote_participant_crypto *)crypto_object_table_find(impl->crypto_objects, remote_id); + if (!remote_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_remote; + } + else if (!CRYPTO_OBJECT_VALID(remote_crypto, CRYPTO_OBJECT_KIND_REMOTE_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + + key_material = (participant_key_material *)crypto_object_table_find(remote_crypto->key_material, local_id); + if (key_material) + { + if (!key_material->remote_key_material) + key_material->remote_key_material = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_NONE); + crypto_token_copy(key_material->remote_key_material, remote_key_mat); + CRYPTO_OBJECT_RELEASE(key_material); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + result = true; + +err_inv_remote: + CRYPTO_OBJECT_RELEASE(remote_crypto); +err_no_remote: + return result; +} + +bool +crypto_factory_get_datawriter_crypto_tokens( + const dds_security_crypto_key_factory *factory, + DDS_Security_DatawriterCryptoHandle local_writer_handle, + DDS_Security_DatareaderCryptoHandle remote_reader_handle, + master_key_material **key_mat, + uint32_t *num_key_mat, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_datareader_crypto *remote_reader_crypto; + uint32_t index = 0; + bool result = false; + + assert(factory); + assert(local_writer_handle != DDS_SECURITY_HANDLE_NIL); + assert(remote_reader_handle != DDS_SECURITY_HANDLE_NIL); + assert(key_mat); + assert(num_key_mat); + assert((*num_key_mat) == 2); + + remote_reader_crypto = (remote_datareader_crypto *)crypto_object_table_find(impl->crypto_objects, remote_reader_handle); + if (!remote_reader_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_remote; + } + else if (!CRYPTO_OBJECT_VALID(remote_reader_crypto, CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + + if (remote_reader_crypto->local_writer_handle != local_writer_handle) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + + if (remote_reader_crypto->writer2reader_key_material_message) + key_mat[index++] = (master_key_material *)CRYPTO_OBJECT_KEEP(remote_reader_crypto->writer2reader_key_material_message); + + if (remote_reader_crypto->writer2reader_key_material_payload) + key_mat[index++] = (master_key_material *)CRYPTO_OBJECT_KEEP(remote_reader_crypto->writer2reader_key_material_payload); + + *num_key_mat = index; + result = true; + +err_inv_remote: + CRYPTO_OBJECT_RELEASE(remote_reader_crypto); +err_no_remote: + return result; +} + +bool +crypto_factory_set_datawriter_crypto_tokens( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle local_reader_handle, + const DDS_Security_DatareaderCryptoHandle remote_writer_handle, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *key_mat, + const uint32_t num_key_mat, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + bool result = false; + remote_datawriter_crypto *remote_writer_crypto; + local_datareader_crypto *local_reader_crypto; + master_key_material *writer_master_key[2] = {NULL, NULL}; + participant_key_material *keys; + endpoint_relation *relation; + uint32_t key_id, i; + + remote_writer_crypto = (remote_datawriter_crypto *)crypto_object_table_find(impl->crypto_objects, remote_writer_handle); + if (!remote_writer_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_remote; + } + else if (!CRYPTO_OBJECT_VALID(remote_writer_crypto, CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + + local_reader_crypto = (local_datareader_crypto *)crypto_object_table_find(impl->crypto_objects, local_reader_handle); + if (!local_reader_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_local; + } + else if (!CRYPTO_OBJECT_VALID(local_reader_crypto, CRYPTO_OBJECT_KIND_LOCAL_READER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_local; + } + + if (remote_writer_crypto->local_reader_handle != local_reader_handle) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_local; + } + + for (i = 0; i < num_key_mat; i++) + { + writer_master_key[i] = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_NONE); + crypto_token_copy(writer_master_key[i], &key_mat[i]); + } + + remove_remote_writer_relation(impl, remote_writer_crypto); + CRYPTO_OBJECT_RELEASE(remote_writer_crypto->writer2reader_key_material[0]); + CRYPTO_OBJECT_RELEASE(remote_writer_crypto->writer2reader_key_material[1]); + + remote_writer_crypto->writer2reader_key_material[0] = writer_master_key[0]; + if (writer_master_key[1]) + remote_writer_crypto->writer2reader_key_material[1] = writer_master_key[1]; + else + remote_writer_crypto->writer2reader_key_material[1] = (master_key_material *)CRYPTO_OBJECT_KEEP(writer_master_key[0]); + + keys = (participant_key_material *)crypto_object_table_find( + remote_writer_crypto->participant->key_material, CRYPTO_OBJECT_HANDLE(local_reader_crypto->participant)); + assert(keys); + + key_id = remote_writer_crypto->writer2reader_key_material[0]->sender_key_id; + + relation = crypto_endpoint_relation_new(DDS_SECURITY_DATAWRITER_SUBMESSAGE, key_id, (CryptoObject *)local_reader_crypto, (CryptoObject *)remote_writer_crypto); + crypto_object_table_insert(keys->endpoint_relations, (CryptoObject *)relation); + CRYPTO_OBJECT_RELEASE(relation); + CRYPTO_OBJECT_RELEASE(keys); + result = true; + +err_inv_local: + CRYPTO_OBJECT_RELEASE(local_reader_crypto); +err_inv_remote: + CRYPTO_OBJECT_RELEASE(remote_writer_crypto); +err_no_remote: + return result; +} + +bool +crypto_factory_get_datareader_crypto_tokens( + const dds_security_crypto_key_factory *factory, + DDS_Security_DatawriterCryptoHandle local_reader_handle, + DDS_Security_DatareaderCryptoHandle remote_writer_handle, + master_key_material **key_mat, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_datawriter_crypto *remote_writer_crypto; + bool result = false; + + assert(factory); + assert(local_reader_handle != DDS_SECURITY_HANDLE_NIL); + assert(remote_writer_handle != DDS_SECURITY_HANDLE_NIL); + assert(key_mat); + + remote_writer_crypto = (remote_datawriter_crypto *)crypto_object_table_find(impl->crypto_objects, remote_writer_handle); + if (!remote_writer_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_remote; + } + else if (!CRYPTO_OBJECT_VALID(remote_writer_crypto, CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + + if (remote_writer_crypto->local_reader_handle != local_reader_handle) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + + if (remote_writer_crypto->reader2writer_key_material) + *key_mat = (master_key_material *)CRYPTO_OBJECT_KEEP(remote_writer_crypto->reader2writer_key_material); + else + *key_mat = NULL; /* there is no key material to return, because of no encryption for submessages in AccessControl */ + result = true; + +err_inv_remote: + CRYPTO_OBJECT_RELEASE(remote_writer_crypto); +err_no_remote: + return result; +} + +bool +crypto_factory_set_datareader_crypto_tokens( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle local_writer_handle, + const DDS_Security_DatareaderCryptoHandle remote_reader_handle, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *key_mat, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + bool result = false; + remote_datareader_crypto *remote_reader_crypto; + local_datawriter_crypto *local_writer_crypto; + participant_key_material *keys; + endpoint_relation *relation; + uint32_t key_id; + + remote_reader_crypto = (remote_datareader_crypto *)crypto_object_table_find(impl->crypto_objects, remote_reader_handle); + if (!remote_reader_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + else if (!CRYPTO_OBJECT_VALID(remote_reader_crypto, CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + + local_writer_crypto = (local_datawriter_crypto *)crypto_object_table_find(impl->crypto_objects, local_writer_handle); + if (!local_writer_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_local; + } + else if (!CRYPTO_OBJECT_VALID(local_writer_crypto, CRYPTO_OBJECT_KIND_LOCAL_WRITER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_local; + } + + if (remote_reader_crypto->local_writer_handle != local_writer_handle) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_local; + } + + remove_remote_reader_relation(impl, remote_reader_crypto); + CRYPTO_OBJECT_RELEASE(remote_reader_crypto->reader2writer_key_material); + + remote_reader_crypto->reader2writer_key_material = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_NONE); + crypto_token_copy(remote_reader_crypto->reader2writer_key_material, key_mat); + + keys = (participant_key_material *)crypto_object_table_find( + remote_reader_crypto->participant->key_material, CRYPTO_OBJECT_HANDLE(local_writer_crypto->participant)); + assert(keys); + + key_id = remote_reader_crypto->reader2writer_key_material->sender_key_id; + + relation = crypto_endpoint_relation_new(DDS_SECURITY_DATAREADER_SUBMESSAGE, key_id, (CryptoObject *)local_writer_crypto, (CryptoObject *)remote_reader_crypto); + crypto_object_table_insert(keys->endpoint_relations, (CryptoObject *)relation); + CRYPTO_OBJECT_RELEASE(relation); + CRYPTO_OBJECT_RELEASE(keys); + result = true; + +err_inv_local: + CRYPTO_OBJECT_RELEASE(local_writer_crypto); +err_inv_remote: + CRYPTO_OBJECT_RELEASE(remote_reader_crypto); + + return result; +} + +static bool +get_local_volatile_sec_writer_key_material( + dds_security_crypto_key_factory_impl *factory, + const DDS_Security_DatareaderCryptoHandle reader_id, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + bool result = false; + remote_datareader_crypto *reader_crypto; + + reader_crypto = (remote_datareader_crypto *)crypto_object_table_find(factory->crypto_objects, reader_id); + if (!reader_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE " %"PRIx64, reader_id); + goto err_no_crypto; + } + else if (!CRYPTO_OBJECT_VALID(reader_crypto, CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(reader_crypto->writer_session); + *protection_kind = reader_crypto->metadata_protectionKind; + result = true; + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(reader_crypto); +err_no_crypto: + return result; +} + +static bool +get_local_volatile_sec_reader_key_material( + dds_security_crypto_key_factory_impl *factory, + const DDS_Security_DatawriterCryptoHandle writer_id, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + bool result = false; + remote_datawriter_crypto *writer_crypto; + + writer_crypto = (remote_datawriter_crypto *)crypto_object_table_find(factory->crypto_objects, writer_id); + if (!writer_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_crypto; + } + else if (!CRYPTO_OBJECT_VALID(writer_crypto, CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE " %"PRIx64, writer_id); + goto err_inv_crypto; + } + + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(writer_crypto->reader_session); + *protection_kind = writer_crypto->metadata_protectionKind; + result = true; + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(writer_crypto); +err_no_crypto: + return result; +} + +bool +crypto_factory_get_local_participant_data_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_ParticipantCryptoHandle local_id, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + local_participant_crypto *participant_crypto; + bool result = false; + + participant_crypto = (local_participant_crypto *)crypto_object_table_find(impl->crypto_objects, local_id); + if (!(participant_crypto)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_crypto; + } + else if (!CRYPTO_OBJECT_VALID(participant_crypto, CRYPTO_OBJECT_KIND_LOCAL_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(participant_crypto->session); + *protection_kind = participant_crypto->rtps_protection_kind; + result = true; + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(CRYPTO_OBJECT(participant_crypto)); +err_no_crypto: + return result; +} + +bool +crypto_factory_get_writer_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle writer_id, + const DDS_Security_DatareaderCryptoHandle reader_id, + bool payload, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + local_datawriter_crypto *writer_crypto = NULL; + bool result = false; + + writer_crypto = (local_datawriter_crypto *)crypto_object_table_find(impl->crypto_objects, writer_id); + if (!writer_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE " %"PRIx64, writer_id); + goto err_remote; + } + if (!CRYPTO_OBJECT_VALID(writer_crypto, CRYPTO_OBJECT_KIND_LOCAL_WRITER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + if (!writer_crypto->is_builtin_participant_volatile_message_secure_writer) + { + if (payload) + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(writer_crypto->writer_session_payload); + else + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(writer_crypto->writer_session_message); + + if (protection_kind) + *protection_kind = writer_crypto->metadata_protectionKind; + result = true; + } + else if (!payload) + { + result = get_local_volatile_sec_writer_key_material(impl, reader_id, session_key, protection_kind, ex); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + } + +err_inv_remote: + CRYPTO_OBJECT_RELEASE(writer_crypto); +err_remote: + return result; +} + +bool +crypto_factory_get_reader_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle reader_id, + const DDS_Security_DatawriterCryptoHandle writer_id, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + local_datareader_crypto *reader_crypto; + bool result = false; + + reader_crypto = (local_datareader_crypto *)crypto_object_table_find(impl->crypto_objects, reader_id); + if (!reader_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE " %"PRIx64, reader_id); + goto err_no_crypto; + } + else if (!CRYPTO_OBJECT_VALID(reader_crypto, CRYPTO_OBJECT_KIND_LOCAL_READER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + else if (!reader_crypto->is_builtin_participant_volatile_message_secure_reader) + { + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(reader_crypto->reader_session); + if (protection_kind) + *protection_kind = reader_crypto->metadata_protectionKind; + result = true; + } + else + { + result = get_local_volatile_sec_reader_key_material(impl, writer_id, session_key, protection_kind, ex); + } + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(reader_crypto); +err_no_crypto: + return result; +} + +bool +crypto_factory_get_remote_writer_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle reader_id, + const DDS_Security_DatawriterCryptoHandle writer_id, + uint32_t key_id, + master_key_material **master_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_BasicProtectionKind *basic_protection_kind, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_datawriter_crypto *writer_crypto; + bool result = false; + + writer_crypto = (remote_datawriter_crypto *)crypto_object_table_find(impl->crypto_objects, writer_id); + if (!writer_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_crypto; + } + if (!CRYPTO_OBJECT_VALID(writer_crypto, CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + if (writer_crypto->local_reader_handle != reader_id) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + + if (writer_crypto->writer2reader_key_material[0]->sender_key_id == key_id) + { + *master_key = (master_key_material *)CRYPTO_OBJECT_KEEP(writer_crypto->writer2reader_key_material[0]); + } + else if (writer_crypto->writer2reader_key_material[1]->sender_key_id == key_id) + { + *master_key = (master_key_material *)CRYPTO_OBJECT_KEEP(writer_crypto->writer2reader_key_material[1]); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + if (protection_kind) + *protection_kind = writer_crypto->metadata_protectionKind; + if (basic_protection_kind) + *basic_protection_kind = writer_crypto->data_protectionKind; + result = true; + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(writer_crypto); +err_no_crypto: + return result; +} + +bool +crypto_factory_get_remote_reader_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle writer_id, + const DDS_Security_DatareaderCryptoHandle reader_id, + uint32_t key_id, + master_key_material **master_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_datareader_crypto *reader_crypto; + bool result = false; + + reader_crypto = (remote_datareader_crypto *)crypto_object_table_find(impl->crypto_objects, reader_id); + if (!reader_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_crypto; + } + if (!CRYPTO_OBJECT_VALID(reader_crypto, CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO)) + { + CRYPTO_OBJECT_RELEASE(reader_crypto); + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + if (reader_crypto->local_writer_handle != writer_id) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + if (reader_crypto->reader2writer_key_material->sender_key_id == key_id) + { + *master_key = (master_key_material *)CRYPTO_OBJECT_KEEP(reader_crypto->reader2writer_key_material); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + if (protection_kind) + *protection_kind = reader_crypto->metadata_protectionKind; + result = true; + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(reader_crypto); +err_no_crypto: + return result; +} + +bool +crypto_factory_get_remote_writer_sign_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle writer_id, + master_key_material **key_material, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_datawriter_crypto *writer_crypto; + bool result = false; + + assert(key_material); + assert(session_key); + assert(protection_kind); + + writer_crypto = (remote_datawriter_crypto *)crypto_object_table_find(impl->crypto_objects, writer_id); + if (!writer_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_crypto; + } + else if (!CRYPTO_OBJECT_VALID(writer_crypto, CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + + *key_material = (master_key_material *)CRYPTO_OBJECT_KEEP(writer_crypto->reader2writer_key_material); + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(writer_crypto->reader_session); + *protection_kind = writer_crypto->metadata_protectionKind; + result = true; + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(writer_crypto); +err_no_crypto: + return result; +} + +bool +crypto_factory_get_remote_reader_sign_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle reader_id, + master_key_material **key_material, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_datareader_crypto *reader_crypto; + bool result = false; + + assert(key_material); + assert(session_key); + assert(protection_kind); + + reader_crypto = (remote_datareader_crypto *)crypto_object_table_find(impl->crypto_objects, reader_id); + if (!reader_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_crypto; + } + else if (!CRYPTO_OBJECT_VALID(reader_crypto, CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + + *key_material = (master_key_material *)CRYPTO_OBJECT_KEEP(reader_crypto->writer2reader_key_material_message); + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(reader_crypto->writer_session); + *protection_kind = reader_crypto->metadata_protectionKind; + result = true; + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(reader_crypto); +err_no_crypto: + return result; +} + +struct collect_remote_participant_keys_args +{ + uint32_t key_id; + endpoint_relation *relation; +}; + +/* Currently only collecting the first only */ +static int +collect_remote_participant_keys( + CryptoObject *obj, + void *arg) +{ + participant_key_material *keys = (participant_key_material *)obj; + struct collect_remote_participant_keys_args *info = arg; + + info->relation = crypto_endpoint_relation_find_by_key(keys->endpoint_relations, info->key_id); + return (info->relation) ? 0 : 1; +} + +bool +crypto_factory_get_endpoint_relation( + const dds_security_crypto_key_factory *factory, + DDS_Security_ParticipantCryptoHandle local_participant_handle, + DDS_Security_ParticipantCryptoHandle remote_participant_handle, + uint32_t key_id, + DDS_Security_Handle *remote_handle, + DDS_Security_Handle *local_handle, + DDS_Security_SecureSubmessageCategory_t *category, + DDS_Security_SecurityException *ex) +{ + bool result = false; + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_participant_crypto *remote_pp_crypto; + local_participant_crypto *local_pp_crypto = NULL; + participant_key_material *keys = NULL; + endpoint_relation *relation = NULL; + + remote_pp_crypto = (remote_participant_crypto *)crypto_object_table_find(impl->crypto_objects, remote_participant_handle); + if (!remote_pp_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto invalid_handle; + } + else if (!CRYPTO_OBJECT_VALID(remote_pp_crypto, CRYPTO_OBJECT_KIND_REMOTE_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto invalid_handle; + } + + if (local_participant_handle != DDS_SECURITY_HANDLE_NIL) + { + local_pp_crypto = (local_participant_crypto *)crypto_object_table_find(impl->crypto_objects, local_participant_handle); + if (!local_pp_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto invalid_handle; + } + else if (!CRYPTO_OBJECT_VALID(local_pp_crypto, CRYPTO_OBJECT_KIND_LOCAL_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto invalid_handle; + } + keys = (participant_key_material *)crypto_object_table_find(remote_pp_crypto->key_material, local_participant_handle); + } + + if (keys) + { + relation = crypto_endpoint_relation_find_by_key(keys->endpoint_relations, key_id); + CRYPTO_OBJECT_RELEASE(keys); + } + else + { + struct collect_remote_participant_keys_args args = {key_id, NULL}; + /* FIXME: Returning arbitrary local-remote relation will not work in Cyclone, + * because participants can have different security settings */ + crypto_object_table_walk(remote_pp_crypto->key_material, collect_remote_participant_keys, &args); + relation = args.relation; + } + + if (!relation) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE " key_id=%u", key_id); + goto invalid_handle; + } + + *category = relation->kind; + *remote_handle = CRYPTO_OBJECT_HANDLE(relation->remote_crypto); + *local_handle = CRYPTO_OBJECT_HANDLE(relation->local_crypto); + result = true; + +invalid_handle: + CRYPTO_OBJECT_RELEASE(relation); + CRYPTO_OBJECT_RELEASE(local_pp_crypto); + CRYPTO_OBJECT_RELEASE(remote_pp_crypto); + + return result; +} diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.h b/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.h new file mode 100644 index 0000000..5818b37 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.h @@ -0,0 +1,146 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTO_KEY_FACTORY_H +#define CRYPTO_KEY_FACTORY_H + +#include "dds/security/dds_security_api.h" +#include "crypto_objects.h" + +/** + * @brief Allocation function for implementer structure (with internal variables) transparently. + */ +dds_security_crypto_key_factory * +dds_security_crypto_key_factory__alloc( + const dds_security_cryptography *crypto); + +void dds_security_crypto_key_factory__dealloc( + dds_security_crypto_key_factory *instance); + +int generate_key_pairs( + char **private_key, + char **public_key); + +bool crypto_factory_get_participant_crypto_tokens( + const dds_security_crypto_key_factory *factory, + DDS_Security_ParticipantCryptoHandle local_id, + DDS_Security_ParticipantCryptoHandle remote_id, + participant_key_material **pp_key_material, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_set_participant_crypto_tokens( + const dds_security_crypto_key_factory *factory, + const DDS_Security_ParticipantCryptoHandle local_id, + const DDS_Security_ParticipantCryptoHandle remote_id, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *remote_key_mat, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_datawriter_crypto_tokens( + const dds_security_crypto_key_factory *factory, + DDS_Security_DatawriterCryptoHandle local_writer_handle, + DDS_Security_DatareaderCryptoHandle remote_reader_handle, + master_key_material **key_mat, + uint32_t *num_key_mat, + DDS_Security_SecurityException *ex); + +bool crypto_factory_set_datawriter_crypto_tokens( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle local_reader_handle, + const DDS_Security_DatareaderCryptoHandle remote_writer_handle, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *key_mat, + const uint32_t num_key_mat, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_datareader_crypto_tokens( + const dds_security_crypto_key_factory *factory, + DDS_Security_DatawriterCryptoHandle local_reader_handle, + DDS_Security_DatareaderCryptoHandle remote_writer_handle, + master_key_material **key_mat, + DDS_Security_SecurityException *ex); + +bool crypto_factory_set_datareader_crypto_tokens( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle local_writer_handle, + const DDS_Security_DatareaderCryptoHandle remote_reader_handle, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *key_mat, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_writer_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle writer_id, + const DDS_Security_DatareaderCryptoHandle reader_id, + bool payload, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_reader_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle reader_id, + const DDS_Security_DatawriterCryptoHandle writer_id, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_remote_writer_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle reader_id, + const DDS_Security_DatawriterCryptoHandle writer_id, + uint32_t key_id, + master_key_material **master_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_BasicProtectionKind *basic_protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_local_participant_data_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_ParticipantCryptoHandle local_id, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_remote_reader_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle writer_id, + const DDS_Security_DatareaderCryptoHandle reader_id, + uint32_t key_id, + master_key_material **master_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_remote_writer_sign_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle writer_id, + master_key_material **key_material, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_remote_reader_sign_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle reader_id, + master_key_material **key_material, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_endpoint_relation( + const dds_security_crypto_key_factory *factory, + DDS_Security_ParticipantCryptoHandle local_participant_handle, + DDS_Security_ParticipantCryptoHandle remote_participant_handle, + uint32_t key_id, + DDS_Security_Handle *remote_handle, + DDS_Security_Handle *local_handle, + DDS_Security_SecureSubmessageCategory_t *category, + DDS_Security_SecurityException *ex); + +#endif /* CRYPTO_KEY_FACTORY_H */ diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_objects.c b/src/security/builtin_plugins/cryptographic/src/crypto_objects.c new file mode 100644 index 0000000..8fa9a06 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_objects.c @@ -0,0 +1,593 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/hopscotch.h" +#include "dds/ddsrt/types.h" +#include "crypto_objects.h" +#include "crypto_utils.h" + +bool crypto_object_valid(CryptoObject *obj, CryptoObjectKind_t kind) +{ + return (obj && obj->kind == kind && obj->handle == (int64_t)(uintptr_t)obj); +} + +static uint32_t crypto_object_hash(const void *obj) +{ + const CryptoObject *object = obj; + const uint64_t c = UINT64_C (16292676669999574021); + const uint32_t x = (uint32_t)object->handle; + return (uint32_t)((x * c) >> 32); +} + +static int crypto_object_equal(const void *ha, const void *hb) +{ + const CryptoObject *la = ha; + const CryptoObject *lb = hb; + return la->handle == lb->handle; +} + +void crypto_object_init(CryptoObject *obj, CryptoObjectKind_t kind, CryptoObjectDestructor destructor) +{ + assert(obj); + obj->kind = kind; + obj->handle = (int64_t)(uintptr_t)obj; + obj->destructor = destructor; + ddsrt_atomic_st32 (&obj->refcount, 1); +} + +static void crypto_object_deinit(CryptoObject *obj) +{ + assert(obj); + obj->handle = DDS_SECURITY_HANDLE_NIL; + obj->kind = CRYPTO_OBJECT_KIND_UNKNOWN; + obj->destructor = NULL; +} + +void crypto_object_free(CryptoObject *obj) +{ + if (obj && obj->destructor) + obj->destructor(obj); +} + +CryptoObject * crypto_object_keep(CryptoObject *obj) +{ + if (obj) + ddsrt_atomic_inc32(&obj->refcount); + return obj; +} + +void crypto_object_release(CryptoObject *obj) +{ + if (obj && ddsrt_atomic_dec32_nv(&obj->refcount) == 0) + crypto_object_free(obj); +} + +static uint32_t participant_key_material_hash(const void *obj) +{ + const participant_key_material *object = obj; + return (uint32_t)object->pp_local_handle; +} + +static int participant_key_material_equal(const void *ha, const void *hb) +{ + const participant_key_material *la = ha; + const participant_key_material *lb = hb; + return la->pp_local_handle == lb->pp_local_handle; +} + +static CryptoObject * participant_key_material_find(const struct CryptoObjectTable *table, const void *arg) +{ + struct participant_key_material template; + template.pp_local_handle = *(int64_t *)arg; + return crypto_object_table_find_by_template(table, &template); +} + +CryptoObject * crypto_object_table_find_by_template(const struct CryptoObjectTable *table, const void *template) +{ + return (CryptoObject *)ddsrt_hh_lookup(table->htab, template); +} + +static CryptoObject * default_crypto_table_find(const struct CryptoObjectTable *table, const void *arg) +{ + struct CryptoObject template; + template.handle = *(int64_t *)arg; + return crypto_object_table_find_by_template(table, &template); +} + +struct CryptoObjectTable * crypto_object_table_new(CryptoObjectHashFunction hashfnc, CryptoObjectEqualFunction equalfnc, CryptoObjectFindFunction findfnc) +{ + struct CryptoObjectTable *table; + if (!hashfnc) + hashfnc = crypto_object_hash; + if (!equalfnc) + equalfnc = crypto_object_equal; + table = ddsrt_malloc(sizeof(*table)); + table->htab = ddsrt_hh_new(32, hashfnc, equalfnc); + ddsrt_mutex_init(&table->lock); + table->findfnc = findfnc ? findfnc : default_crypto_table_find; + return table; +} + +void crypto_object_table_free(struct CryptoObjectTable *table) +{ + struct ddsrt_hh_iter it; + CryptoObject *obj; + + if (!table) + return; + + ddsrt_mutex_lock(&table->lock); + for (obj = ddsrt_hh_iter_first(table->htab, &it); obj; obj = ddsrt_hh_iter_next(&it)) + { + ddsrt_hh_remove(table->htab, obj); + crypto_object_release(obj); + } + ddsrt_hh_free(table->htab); + ddsrt_mutex_unlock(&table->lock); + ddsrt_mutex_destroy(&table->lock); + ddsrt_free(table); +} + +CryptoObject * crypto_object_table_insert(struct CryptoObjectTable *table, CryptoObject *object) +{ + CryptoObject *cur; + + assert(table); + assert(object); + + ddsrt_mutex_lock(&table->lock); + if (!(cur = crypto_object_keep (table->findfnc(table, &object->handle)))) + ddsrt_hh_add(table->htab, crypto_object_keep(object)); + else + crypto_object_release(cur); + ddsrt_mutex_unlock(&table->lock); + + return cur; +} + +void crypto_object_table_remove_object(struct CryptoObjectTable *table, CryptoObject *object) +{ + assert (table); + assert (object); + + ddsrt_mutex_lock (&table->lock); + ddsrt_hh_remove (table->htab, object); + ddsrt_mutex_unlock (&table->lock); + + crypto_object_release (object); +} + +CryptoObject * crypto_object_table_remove(struct CryptoObjectTable *table, int64_t handle) +{ + CryptoObject *object; + assert (table); + ddsrt_mutex_lock (&table->lock); + if ((object = crypto_object_keep (table->findfnc(table, &handle)))) + { + ddsrt_hh_remove (table->htab, object); + crypto_object_release (object); + } + ddsrt_mutex_unlock (&table->lock); + + return object; +} + +CryptoObject * crypto_object_table_find(struct CryptoObjectTable *table, int64_t handle) +{ + CryptoObject *object; + assert (table); + ddsrt_mutex_lock (&table->lock); + object = crypto_object_keep (table->findfnc(table, &handle)); + ddsrt_mutex_unlock (&table->lock); + + return object; +} + +void crypto_object_table_walk(struct CryptoObjectTable *table, CryptoObjectTableCallback callback, void *arg) +{ + struct ddsrt_hh_iter it; + CryptoObject *obj; + int r = 1; + + assert(table); + assert(callback); + ddsrt_mutex_lock (&table->lock); + for (obj = ddsrt_hh_iter_first (table->htab, &it); r && obj; obj = ddsrt_hh_iter_next (&it)) + r = callback(obj, arg); + ddsrt_mutex_unlock(&table->lock); +} + +static void master_key_material__free(CryptoObject *obj) +{ + master_key_material *keymat = (master_key_material *)obj; + if (obj) + { + CHECK_CRYPTO_OBJECT_KIND(obj, CRYPTO_OBJECT_KIND_KEY_MATERIAL); + if (CRYPTO_TRANSFORM_HAS_KEYS(keymat->transformation_kind)) + { + ddsrt_free (keymat->master_salt); + ddsrt_free (keymat->master_sender_key); + ddsrt_free (keymat->master_receiver_specific_key); + } + crypto_object_deinit ((CryptoObject *)keymat); + memset (keymat, 0, sizeof (*keymat)); + ddsrt_free (keymat); + } +} + +master_key_material * crypto_master_key_material_new(DDS_Security_CryptoTransformKind_Enum transform_kind) +{ + master_key_material *keymat = ddsrt_calloc (1, sizeof(*keymat)); + crypto_object_init((CryptoObject *)keymat, CRYPTO_OBJECT_KIND_KEY_MATERIAL, master_key_material__free); + keymat->transformation_kind = transform_kind; + if (CRYPTO_TRANSFORM_HAS_KEYS(transform_kind)) + { + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(keymat->transformation_kind); + keymat->master_salt = ddsrt_calloc(1, key_bytes); + keymat->master_sender_key = ddsrt_calloc(1, key_bytes); + keymat->master_receiver_specific_key = ddsrt_calloc(1, key_bytes); + } + return keymat; +} + +void crypto_master_key_material_set(master_key_material *dst, const master_key_material *src) +{ + if (CRYPTO_TRANSFORM_HAS_KEYS(dst->transformation_kind) && !CRYPTO_TRANSFORM_HAS_KEYS(src->transformation_kind)) + { + ddsrt_free(dst->master_salt); + ddsrt_free(dst->master_sender_key); + ddsrt_free(dst->master_receiver_specific_key); + } + else if (CRYPTO_TRANSFORM_HAS_KEYS(src->transformation_kind)) + { + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(src->transformation_kind); + if (!CRYPTO_TRANSFORM_HAS_KEYS(dst->transformation_kind)) + { + dst->master_salt = ddsrt_calloc(1, key_bytes); + dst->master_sender_key = ddsrt_calloc(1, key_bytes); + dst->master_receiver_specific_key = ddsrt_calloc(1, key_bytes); + } + memcpy (dst->master_salt, src->master_salt, key_bytes); + dst->sender_key_id = src->sender_key_id; + memcpy (dst->master_sender_key, src->master_sender_key, key_bytes); + /* Fixme: set the receiver specific key? */ + dst->receiver_specific_key_id = 0; + } + dst->transformation_kind = src->transformation_kind; +} + +static bool generate_session_key(session_key_material *session, DDS_Security_SecurityException *ex) +{ + session->id++; + session->block_counter = 0; + return crypto_calculate_session_key(&session->key, session->id, session->master_key_material->master_salt, session->master_key_material->master_sender_key, session->master_key_material->transformation_kind, ex); +} + +static void session_key_material__free(CryptoObject *obj) +{ + session_key_material *session = (session_key_material *)obj; + if (obj) + { + CHECK_CRYPTO_OBJECT_KIND(obj, CRYPTO_OBJECT_KIND_SESSION_KEY_MATERIAL); + CRYPTO_OBJECT_RELEASE(session->master_key_material); + crypto_object_deinit((CryptoObject *)session); + memset (session, 0, sizeof (*session)); + ddsrt_free(session); + } +} + +session_key_material * crypto_session_key_material_new(master_key_material *master_key) +{ + session_key_material *session = ddsrt_malloc(sizeof(*session)); + crypto_object_init((CryptoObject *)session, CRYPTO_OBJECT_KIND_SESSION_KEY_MATERIAL, session_key_material__free); + memset (session->key.data, 0, CRYPTO_KEY_SIZE_MAX); + session->block_size = CRYPTO_CIPHER_BLOCK_SIZE; + session->key_size = crypto_get_key_size(master_key->transformation_kind); + session->id = crypto_get_random_uint32(); + session->init_vector_suffix = crypto_get_random_uint64(); + session->max_blocks_per_session = INT64_MAX; /* FIXME: should be a config parameter */ + session->block_counter = session->max_blocks_per_session; + session->master_key_material = (master_key_material *)CRYPTO_OBJECT_KEEP(master_key); + + return session; +} + +bool crypto_session_key_material_update(session_key_material *session, uint32_t size, DDS_Security_SecurityException *ex) +{ + if (session->block_counter + (size / session->block_size) >= session->max_blocks_per_session) + return generate_session_key(session, ex); + return true; +} + +static void local_participant_crypto__free(CryptoObject *obj) +{ + local_participant_crypto *participant_crypto = (local_participant_crypto *)obj; + if (participant_crypto) + { + CHECK_CRYPTO_OBJECT_KIND (obj, CRYPTO_OBJECT_KIND_LOCAL_CRYPTO); + CRYPTO_OBJECT_RELEASE (participant_crypto->session); + CRYPTO_OBJECT_RELEASE (participant_crypto->key_material); + crypto_object_deinit ((CryptoObject *)participant_crypto); + ddsrt_free (participant_crypto); + } +} + +local_participant_crypto * crypto_local_participant_crypto__new(DDS_Security_IdentityHandle participant_identity) +{ + assert (participant_identity); + assert (sizeof(DDS_Security_ParticipantCryptoHandle) == 8); + local_participant_crypto *participant_crypto = ddsrt_calloc (1, sizeof(*participant_crypto)); + participant_crypto->identity_handle = participant_identity; + crypto_object_init ((CryptoObject *)participant_crypto, CRYPTO_OBJECT_KIND_LOCAL_CRYPTO, local_participant_crypto__free); + return participant_crypto; +} + +static void remote_participant_crypto__free(CryptoObject *obj) +{ + remote_participant_crypto *participant_crypto = (remote_participant_crypto *)obj; + + CHECK_CRYPTO_OBJECT_KIND (obj, CRYPTO_OBJECT_KIND_REMOTE_CRYPTO); + if (participant_crypto) + { + CRYPTO_OBJECT_RELEASE (participant_crypto->session); + crypto_object_table_free (participant_crypto->key_material); + crypto_object_deinit ((CryptoObject *)participant_crypto); + ddsrt_free(participant_crypto); + } +} + +remote_participant_crypto * crypto_remote_participant_crypto__new(DDS_Security_IdentityHandle participant_identity) +{ + assert (participant_identity); + remote_participant_crypto *participant_crypto = ddsrt_calloc (1, sizeof(*participant_crypto)); + crypto_object_init ((CryptoObject *)participant_crypto, CRYPTO_OBJECT_KIND_REMOTE_CRYPTO, remote_participant_crypto__free); + participant_crypto->identity_handle = participant_identity; + participant_crypto->key_material = crypto_object_table_new (participant_key_material_hash, participant_key_material_equal, participant_key_material_find); + + return participant_crypto; +} + + +static void participant_key_material_free(CryptoObject *obj) +{ + participant_key_material *keymaterial = (participant_key_material *)obj; + CHECK_CRYPTO_OBJECT_KIND(obj, CRYPTO_OBJECT_KIND_PARTICIPANT_KEY_MATERIAL); + if (keymaterial) + { + CRYPTO_OBJECT_RELEASE(keymaterial->P2P_writer_session); + CRYPTO_OBJECT_RELEASE(keymaterial->P2P_reader_session); + CRYPTO_OBJECT_RELEASE(keymaterial->P2P_kx_key_material); + CRYPTO_OBJECT_RELEASE(keymaterial->local_P2P_key_material); + CRYPTO_OBJECT_RELEASE(keymaterial->remote_key_material); + crypto_object_table_free(keymaterial->endpoint_relations); + crypto_object_deinit((CryptoObject *)keymaterial); + ddsrt_free(keymaterial); + } +} + +participant_key_material * crypto_participant_key_material_new(const local_participant_crypto *pplocal) +{ + participant_key_material *keymaterial = ddsrt_calloc(1, sizeof(*keymaterial)); + crypto_object_init((CryptoObject *)keymaterial, CRYPTO_OBJECT_KIND_PARTICIPANT_KEY_MATERIAL, participant_key_material_free); + keymaterial->pp_local_handle = pplocal->_parent.handle; + keymaterial->endpoint_relations = crypto_object_table_new(NULL, NULL, NULL); + keymaterial->local_P2P_key_material = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_NONE); + keymaterial->P2P_kx_key_material = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); /* as defined in table 67 of the DDS Security spec v1.1 */ + + return keymaterial; +} + +static void endpoint_relation_free(CryptoObject *obj) +{ + endpoint_relation *relation = (endpoint_relation *)obj; + if (relation) + { + CRYPTO_OBJECT_RELEASE(relation->local_crypto); + CRYPTO_OBJECT_RELEASE(relation->remote_crypto); + crypto_object_deinit((CryptoObject *)relation); + ddsrt_free(relation); + } +} + +endpoint_relation * crypto_endpoint_relation_new(DDS_Security_SecureSubmessageCategory_t kind, + uint32_t key_id, CryptoObject *local_crypto, CryptoObject *remote_crypto) +{ + endpoint_relation *relation = ddsrt_malloc(sizeof(*relation)); + crypto_object_init((CryptoObject *)relation, CRYPTO_OBJECT_KIND_ENDPOINT_RELATION, endpoint_relation_free); + + relation->kind = kind; + relation->key_id = key_id; + relation->local_crypto = CRYPTO_OBJECT_KEEP(local_crypto); + relation->remote_crypto = CRYPTO_OBJECT_KEEP(remote_crypto); + + return relation; +} + +static void local_datawriter_crypto__free(CryptoObject *obj) +{ + local_datawriter_crypto *datawriter_crypto = (local_datawriter_crypto *)obj; + + if (obj) + { + CHECK_CRYPTO_OBJECT_KIND(obj, CRYPTO_OBJECT_KIND_LOCAL_WRITER_CRYPTO); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->writer_session_message); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->writer_session_payload); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->writer_key_material_message); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->writer_key_material_payload); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->participant); + crypto_object_deinit((CryptoObject *)datawriter_crypto); + ddsrt_free(datawriter_crypto); + } +} + +local_datawriter_crypto * crypto_local_datawriter_crypto__new(const local_participant_crypto *participant, + DDS_Security_ProtectionKind meta_protection, DDS_Security_BasicProtectionKind data_protection) +{ + local_datawriter_crypto *writer_crypto = ddsrt_calloc(1, sizeof(*writer_crypto)); + crypto_object_init((CryptoObject *)writer_crypto, CRYPTO_OBJECT_KIND_LOCAL_WRITER_CRYPTO, local_datawriter_crypto__free); + writer_crypto->participant = (local_participant_crypto *)CRYPTO_OBJECT_KEEP(participant); + writer_crypto->metadata_protectionKind = meta_protection; + writer_crypto->data_protectionKind = data_protection; + writer_crypto->is_builtin_participant_volatile_message_secure_writer = false; + + return writer_crypto; +} + + +static void remote_datawriter_crypto__free(CryptoObject *obj) +{ + remote_datawriter_crypto *datawriter_crypto = (remote_datawriter_crypto *)obj; + if (datawriter_crypto) + { + CHECK_CRYPTO_OBJECT_KIND(obj, CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->reader_session); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->reader2writer_key_material); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->writer2reader_key_material[0]); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->writer2reader_key_material[1]); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->participant); + crypto_object_deinit((CryptoObject *)datawriter_crypto); + ddsrt_free(datawriter_crypto); + } +} + +remote_datawriter_crypto * crypto_remote_datawriter_crypto__new(const remote_participant_crypto *participant, + DDS_Security_ProtectionKind meta_protection, DDS_Security_BasicProtectionKind data_protection, DDS_Security_DatareaderCryptoHandle local_reader_handle) +{ + remote_datawriter_crypto *writer_crypto = ddsrt_calloc(1, sizeof(*writer_crypto)); + crypto_object_init((CryptoObject *)writer_crypto, CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO, remote_datawriter_crypto__free); + writer_crypto->participant = (remote_participant_crypto *)CRYPTO_OBJECT_KEEP(participant); + writer_crypto->metadata_protectionKind = meta_protection; + writer_crypto->data_protectionKind = data_protection; + writer_crypto->local_reader_handle = local_reader_handle; + writer_crypto->is_builtin_participant_volatile_message_secure_writer = false; + + return writer_crypto; +} + + +static void local_datareader_crypto__free(CryptoObject *obj) +{ + local_datareader_crypto *datareader_crypto = (local_datareader_crypto *)obj; + if (datareader_crypto) + { + CHECK_CRYPTO_OBJECT_KIND(obj, CRYPTO_OBJECT_KIND_LOCAL_READER_CRYPTO); + CRYPTO_OBJECT_RELEASE(datareader_crypto->reader_session); + CRYPTO_OBJECT_RELEASE(datareader_crypto->reader_key_material); + CRYPTO_OBJECT_RELEASE(datareader_crypto->participant); + crypto_object_deinit((CryptoObject *)datareader_crypto); + ddsrt_free(datareader_crypto); + } +} + +local_datareader_crypto * crypto_local_datareader_crypto__new(const local_participant_crypto *participant, + DDS_Security_ProtectionKind meta_protection, DDS_Security_BasicProtectionKind data_protection) +{ + local_datareader_crypto *reader_crypto = ddsrt_calloc(1, sizeof(*reader_crypto)); + crypto_object_init((CryptoObject *)reader_crypto, CRYPTO_OBJECT_KIND_LOCAL_READER_CRYPTO, local_datareader_crypto__free); + reader_crypto->participant = (local_participant_crypto *)CRYPTO_OBJECT_KEEP(participant); + reader_crypto->metadata_protectionKind = meta_protection; + reader_crypto->data_protectionKind = data_protection; + reader_crypto->is_builtin_participant_volatile_message_secure_reader = false; + + return reader_crypto; +} + + +static void remote_datareader_crypto__free(CryptoObject *obj) +{ + remote_datareader_crypto *datareader_crypto = (remote_datareader_crypto *)obj; + if (datareader_crypto) + { + CHECK_CRYPTO_OBJECT_KIND(obj, CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO); + CRYPTO_OBJECT_RELEASE(datareader_crypto->writer_session); + CRYPTO_OBJECT_RELEASE(datareader_crypto->reader2writer_key_material); + CRYPTO_OBJECT_RELEASE(datareader_crypto->writer2reader_key_material_message); + CRYPTO_OBJECT_RELEASE(datareader_crypto->writer2reader_key_material_payload); + CRYPTO_OBJECT_RELEASE(datareader_crypto->participant); + crypto_object_deinit((CryptoObject *)datareader_crypto); + ddsrt_free(datareader_crypto); + } +} + +remote_datareader_crypto *crypto_remote_datareader_crypto__new(const remote_participant_crypto *participant, DDS_Security_ProtectionKind metadata_protectionKind, + DDS_Security_BasicProtectionKind data_protectionKind, DDS_Security_DatawriterCryptoHandle local_writer_handle) +{ + remote_datareader_crypto *reader_crypto = ddsrt_calloc(1, sizeof(*reader_crypto)); + crypto_object_init((CryptoObject *)reader_crypto, CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO, remote_datareader_crypto__free); + reader_crypto->participant = (remote_participant_crypto *)CRYPTO_OBJECT_KEEP(participant); + reader_crypto->metadata_protectionKind = metadata_protectionKind; + reader_crypto->data_protectionKind = data_protectionKind; + reader_crypto->local_writer_handle = local_writer_handle; + reader_crypto->is_builtin_participant_volatile_message_secure_reader = false; + + return reader_crypto; +} + + +typedef struct endpoint_relation_find_arg +{ + CryptoObject *found; + CryptoObject *local_crypto; + CryptoObject *remote_crypto; + uint32_t key_id; +} endpoint_relation_find_arg; + +static int endpoint_relation_cmp_key(CryptoObject *obj, void *arg) +{ + const endpoint_relation *rel = (const endpoint_relation *)obj; + endpoint_relation_find_arg *find_arg = (endpoint_relation_find_arg *)arg; + + if (rel->key_id == find_arg->key_id) + { + find_arg->found = crypto_object_keep(obj); + return 0; + } + return 1; +} + +static int endpoint_relation_cmp_crypto(CryptoObject *obj, void *arg) +{ + const endpoint_relation *rel = (const endpoint_relation *)obj; + endpoint_relation_find_arg *find_arg = (endpoint_relation_find_arg *)arg; + + if ((rel->local_crypto == find_arg->local_crypto) && + (rel->remote_crypto == find_arg->remote_crypto)) + { + find_arg->found = crypto_object_keep(obj); + return 0; + } + return 1; +} + +endpoint_relation * crypto_endpoint_relation_find_by_key(struct CryptoObjectTable *table, uint32_t key_id) +{ + endpoint_relation_find_arg find_arg; + find_arg.found = NULL; + find_arg.key_id = key_id; + find_arg.local_crypto = NULL; + find_arg.remote_crypto = NULL; + crypto_object_table_walk(table, endpoint_relation_cmp_key, &find_arg); + return (endpoint_relation *)(find_arg.found); +} + +endpoint_relation * crypto_endpoint_relation_find_by_crypto(struct CryptoObjectTable *table, CryptoObject *local_crypto, CryptoObject *remote_crypto) +{ + endpoint_relation_find_arg find_arg; + find_arg.found = NULL; + find_arg.key_id = 0; + find_arg.local_crypto = local_crypto; + find_arg.remote_crypto = remote_crypto; + crypto_object_table_walk(table, endpoint_relation_cmp_crypto, &find_arg); + return (endpoint_relation *)(find_arg.found); +} diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_objects.h b/src/security/builtin_plugins/cryptographic/src/crypto_objects.h new file mode 100644 index 0000000..3edb6a4 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_objects.h @@ -0,0 +1,354 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTO_OBJECTS_H +#define CRYPTO_OBJECTS_H + +#include +#include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "crypto_defs.h" + +#ifndef NDEBUG +#define CHECK_CRYPTO_OBJECT_KIND(o, k) assert(crypto_object_valid((CryptoObject *)(o), k)) +#else +#define CHECK_CRYPTO_OBJECT_KIND(o, k) +#endif + +#define CRYPTO_OBJECT(o) ((CryptoObject *)(o)) +#define CRYPTO_OBJECT_HANDLE(o) (CRYPTO_OBJECT(o)->handle) +#define PARTICIPANT_CRYPTO_HANDLE(o) ((DDS_Security_ParticipantCryptoHandle)CRYPTO_OBJECT_HANDLE(o)) +#define DATAWRITER_CRYPTO_HANDLE(o) ((DDS_Security_DatawriterCryptoHandle)CRYPTO_OBJECT_HANDLE(o)) +#define DATAREADER_CRYPTO_HANDLE(o) ((DDS_Security_DatareaderCryptoHandle)CRYPTO_OBJECT_HANDLE(o)) + +#define CRYPTO_OBJECT_KEEP(o) crypto_object_keep((CryptoObject *)(o)) +#define CRYPTO_OBJECT_RELEASE(o) crypto_object_release((CryptoObject *)(o)) +#define CRYPTO_OBJECT_VALID(o, k) crypto_object_valid((CryptoObject *)(o), k) + +#define CRYPTO_TRANSFORM_HAS_KEYS(k) ((k) != CRYPTO_TRANSFORMATION_KIND_NONE && (k) != CRYPTO_TRANSFORMATION_KIND_INVALID) + +typedef DDS_Security_ParticipantCryptoHandle DDS_Security_LocalParticipantCryptoHandle; +typedef DDS_Security_ParticipantCryptoHandle DDS_Security_RemoteParticipantCryptoHandle; + +typedef enum +{ + CRYPTO_OBJECT_KIND_UNKNOWN, + CRYPTO_OBJECT_KIND_LOCAL_CRYPTO, + CRYPTO_OBJECT_KIND_REMOTE_CRYPTO, + CRYPTO_OBJECT_KIND_LOCAL_WRITER_CRYPTO, + CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO, + CRYPTO_OBJECT_KIND_LOCAL_READER_CRYPTO, + CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO, + CRYPTO_OBJECT_KIND_KEY_MATERIAL, + CRYPTO_OBJECT_KIND_SESSION_KEY_MATERIAL, + CRYPTO_OBJECT_KIND_PARTICIPANT_KEY_MATERIAL, + CRYPTO_OBJECT_KIND_ENDPOINT_RELATION +} CryptoObjectKind_t; + +typedef struct CryptoObject CryptoObject; +typedef void (*CryptoObjectDestructor)(CryptoObject *obj); + +struct CryptoObject +{ + int64_t handle; + ddsrt_atomic_uint32_t refcount; + CryptoObjectKind_t kind; + CryptoObjectDestructor destructor; +}; + +struct local_datawriter_crypto; +struct local_datareader_crypto; +struct remote_datawriter_crypto; +struct remote_datareader_crypto; + +typedef struct master_key_material +{ + CryptoObject _parent; + DDS_Security_CryptoTransformKind_Enum transformation_kind; + unsigned char *master_salt; + uint32_t sender_key_id; + unsigned char *master_sender_key; + uint32_t receiver_specific_key_id; + unsigned char *master_receiver_specific_key; +} master_key_material; + +typedef struct session_key_material +{ + CryptoObject _parent; + uint32_t id; + crypto_session_key_t key; + uint32_t key_size; + uint32_t block_size; + uint64_t block_counter; + uint64_t max_blocks_per_session; + uint64_t init_vector_suffix; + master_key_material *master_key_material; +} session_key_material; + +typedef struct remote_session_info +{ + uint32_t key_size; + uint32_t id; + crypto_session_key_t key; +} remote_session_info; + +typedef struct endpoint_relation +{ + CryptoObject _parent; + DDS_Security_SecureSubmessageCategory_t kind; + uint32_t key_id; + CryptoObject *local_crypto; + CryptoObject *remote_crypto; +} endpoint_relation; + +typedef struct local_participant_crypto +{ + CryptoObject _parent; + master_key_material *key_material; + DDS_Security_IdentityHandle identity_handle; + session_key_material *session; + DDS_Security_ProtectionKind rtps_protection_kind; +} local_participant_crypto; + +typedef struct participant_key_material +{ + CryptoObject _parent; + DDS_Security_ParticipantCryptoHandle pp_local_handle; + master_key_material *remote_key_material; + master_key_material *local_P2P_key_material; + master_key_material *P2P_kx_key_material; + session_key_material *P2P_writer_session; + session_key_material *P2P_reader_session; + struct CryptoObjectTable *endpoint_relations; +} participant_key_material; + +typedef struct remote_participant_crypto +{ + CryptoObject _parent; + DDS_Security_GUID_t remoteGuid; + DDS_Security_IdentityHandle identity_handle; + struct CryptoObjectTable *key_material; + session_key_material *session; + DDS_Security_ProtectionKind rtps_protection_kind; +} remote_participant_crypto; + +typedef struct local_datawriter_crypto +{ + CryptoObject _parent; + local_participant_crypto *participant; + master_key_material *writer_key_material_message; + master_key_material *writer_key_material_payload; + session_key_material *writer_session_message; + session_key_material *writer_session_payload; + DDS_Security_ProtectionKind metadata_protectionKind; + DDS_Security_BasicProtectionKind data_protectionKind; + bool is_builtin_participant_volatile_message_secure_writer; +} local_datawriter_crypto; + +typedef struct remote_datawriter_crypto +{ + CryptoObject _parent; + remote_participant_crypto *participant; + DDS_Security_ProtectionKind metadata_protectionKind; + DDS_Security_BasicProtectionKind data_protectionKind; + master_key_material *reader2writer_key_material; + master_key_material *writer2reader_key_material[2]; + session_key_material *reader_session; /* reference to the session key used by the reader */ + DDS_Security_DatareaderCryptoHandle local_reader_handle; + bool is_builtin_participant_volatile_message_secure_writer; +} remote_datawriter_crypto; + +typedef struct local_datareader_crypto +{ + CryptoObject _parent; + local_participant_crypto *participant; + master_key_material *reader_key_material; + session_key_material *reader_session; + DDS_Security_ProtectionKind metadata_protectionKind; + DDS_Security_BasicProtectionKind data_protectionKind; + bool is_builtin_participant_volatile_message_secure_reader; +} local_datareader_crypto; + +typedef struct remote_datareader_crypto +{ + CryptoObject _parent; + remote_participant_crypto *participant; + DDS_Security_ProtectionKind metadata_protectionKind; + DDS_Security_BasicProtectionKind data_protectionKind; + master_key_material *reader2writer_key_material; + master_key_material *writer2reader_key_material_message; + master_key_material *writer2reader_key_material_payload; + session_key_material *writer_session; /* reference to the session key used by the writer */ + DDS_Security_DatawriterCryptoHandle local_writer_handle; + bool is_builtin_participant_volatile_message_secure_reader; +} remote_datareader_crypto; + +master_key_material * +crypto_master_key_material_new(DDS_Security_CryptoTransformKind_Enum transform_kind); + +void crypto_master_key_material_set( + master_key_material *dst, + const master_key_material *src); + +session_key_material * +crypto_session_key_material_new( + master_key_material *master_key); + +bool crypto_session_key_material_update( + session_key_material *session, + uint32_t size, + DDS_Security_SecurityException *ex); + +local_participant_crypto * +crypto_local_participant_crypto__new( + DDS_Security_IdentityHandle participant_identity); + +remote_participant_crypto * +crypto_remote_participant_crypto__new( + DDS_Security_IdentityHandle participant_identity); + +void crypto_object_init( + CryptoObject *obj, + CryptoObjectKind_t kind, + CryptoObjectDestructor destructor); + +endpoint_relation * +crypto_endpoint_relation_new( + DDS_Security_SecureSubmessageCategory_t kind, + uint32_t key_id, + CryptoObject *local_crypto, + CryptoObject *remote_crypto); + +endpoint_relation * +crypto_endpoint_relation_find_by_key( + struct CryptoObjectTable *table, + uint32_t key_id); + +endpoint_relation * +crypto_endpoint_relation_find_by_crypto( + struct CryptoObjectTable *table, + CryptoObject *local_crypto, + CryptoObject *remote_crypto); + +bool endpoint_relation_get_locals( + const endpoint_relation *relation, + const local_participant_crypto *participant, + DDS_Security_HandleSeq *list); + +local_datawriter_crypto * +crypto_local_datawriter_crypto__new( + const local_participant_crypto *participant, + DDS_Security_ProtectionKind meta_protection, + DDS_Security_BasicProtectionKind data_protection); + +remote_datareader_crypto * +crypto_remote_datareader_crypto__new( + const remote_participant_crypto *participant, + DDS_Security_ProtectionKind metadata_protectionKind, + DDS_Security_BasicProtectionKind data_protectionKind, + DDS_Security_DatawriterCryptoHandle local_writer_handle); + +local_datareader_crypto * +crypto_local_datareader_crypto__new( + const local_participant_crypto *participant, + DDS_Security_ProtectionKind meta_protection, + DDS_Security_BasicProtectionKind data_protection); + +remote_datawriter_crypto * +crypto_remote_datawriter_crypto__new( + const remote_participant_crypto *participant, + DDS_Security_ProtectionKind meta_protection, + DDS_Security_BasicProtectionKind data_protection, + DDS_Security_DatareaderCryptoHandle local_reader_handle); + +CryptoObject * +crypto_object_keep( + CryptoObject *obj); + +void crypto_object_release( + CryptoObject *obj); + +bool crypto_object_valid( + CryptoObject *obj, + CryptoObjectKind_t kind); + +void crypto_object_free( + CryptoObject *obj); + +local_participant_crypto * +crypto_local_participant_crypto__new( + DDS_Security_IdentityHandle participant_identity); + +remote_participant_crypto * +crypto_remote_participant_crypto__new( + DDS_Security_IdentityHandle participant_identity); + +participant_key_material * +crypto_participant_key_material_new( + const local_participant_crypto *pplocal); + +struct CryptoObjectTable; + +typedef uint32_t (*CryptoObjectHashFunction)(const void *obj); +typedef int (*CryptoObjectEqualFunction)(const void *ha, const void *hb); +typedef CryptoObject *(*CryptoObjectFindFunction)(const struct CryptoObjectTable *table, const void *arg); + +struct CryptoObjectTable * +crypto_object_table_new( + CryptoObjectHashFunction hashfnc, + CryptoObjectEqualFunction equalfnc, + CryptoObjectFindFunction findfnc); + +void crypto_object_table_free( + struct CryptoObjectTable *table); + +CryptoObject * +crypto_object_table_insert( + struct CryptoObjectTable *table, + CryptoObject *object); + +void crypto_object_table_remove_object( + struct CryptoObjectTable *table, + CryptoObject *object); + +CryptoObject * +crypto_object_table_remove( + struct CryptoObjectTable *table, + int64_t handle); + +CryptoObject * +crypto_object_table_find_by_template( + const struct CryptoObjectTable *table, + const void *template); + +CryptoObject * +crypto_object_table_find( + struct CryptoObjectTable *table, + int64_t handle); + +typedef int (*CryptoObjectTableCallback)(CryptoObject *obj, void *arg); + +struct CryptoObjectTable +{ + struct ddsrt_hh *htab; + ddsrt_mutex_t lock; + CryptoObjectFindFunction findfnc; +}; + +void crypto_object_table_walk( + struct CryptoObjectTable *table, + CryptoObjectTableCallback callback, + void *arg); + +#endif /* CRYPTO_OBJECTS_H */ diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_transform.c b/src/security/builtin_plugins/cryptographic/src/crypto_transform.c new file mode 100644 index 0000000..f27ea24 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_transform.c @@ -0,0 +1,2469 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "cryptography.h" +#include "crypto_cipher.h" +#include "crypto_defs.h" +#include "crypto_key_factory.h" +#include "crypto_objects.h" +#include "crypto_transform.h" +#include "crypto_utils.h" + +#define CRYPTO_ENCRYPTION_MAX_PADDING 32 +#define CRYPTO_FOOTER_BASIC_SIZE (CRYPTO_HMAC_SIZE + sizeof(uint32_t)) +#define INFO_SRC_SIZE 24 +#define INFO_SRC_HDR_SIZE 8 +#define RTPS_HEADER_SIZE 20 + +#if OPENSSL_VERSION_NUMBER >= 0x10000000L && OPENSSL_VERSION_NUMBER < 0x10100000L +#define REMOVE_THREAD_STATE() ERR_remove_thread_state(NULL); +#elif OPENSSL_VERSION_NUMBER < 0x10000000L +#define REMOVE_THREAD_STATE() ERR_remove_state(0); +#else +#define REMOVE_THREAD_STATE() +#endif + +struct submsg_header +{ + unsigned char id; + unsigned char flags; + uint16_t length; +}; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[CRYPTO_SESSION_ID_SIZE]; + unsigned char init_vector_suffix[CRYPTO_INIT_VECTOR_SUFFIX_SIZE]; +}; + +struct crypto_contents +{ + uint32_t _length; + unsigned char _data[1]; +}; + +struct crypto_contents_ref +{ + uint32_t _length; + unsigned char *_data; +}; + +struct receiver_specific_mac +{ + DDS_Security_CryptoTransformKeyId receiver_mac_key_id; + crypto_hmac_t receiver_mac; +}; + +struct receiver_specific_mac_seq +{ + uint32_t _length; + struct receiver_specific_mac _buffer[1]; +}; + +struct crypto_footer +{ + crypto_hmac_t common_mac; + struct receiver_specific_mac_seq receiver_specific_macs; +}; + +struct encrypted_data +{ + uint32_t length; + unsigned char data[1]; +}; + +/* +const DDS_octet INFO_SRC_HDR[] = + { + RTPS_Message_Type_INFO_SRC, + 0x00, // BIG ENDIAN + 0x14, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 + }; +*/ + + +/** + * Implementation structure for storing encapsulated members of the instance + * while giving only the interface definition to user + */ +typedef struct dds_security_crypto_transform_impl +{ + dds_security_crypto_transform base; + const dds_security_cryptography *crypto; +} dds_security_crypto_transform_impl; + +static bool +is_encryption_required( + uint32_t transform_kind) +{ + return ((transform_kind == CRYPTO_TRANSFORMATION_KIND_AES256_GCM) || + (transform_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM)); +} + +static bool +is_authentication_required( + uint32_t transform_kind) +{ + return ((transform_kind == CRYPTO_TRANSFORMATION_KIND_AES256_GMAC) || + (transform_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC)); +} + +static bool +is_encryption_expected( + DDS_Security_ProtectionKind protection_kind) +{ + return ((protection_kind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT) || + (protection_kind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION)); +} + +static bool +is_authentication_expected( + DDS_Security_ProtectionKind protection_kind) +{ + return ((protection_kind == DDS_SECURITY_PROTECTION_KIND_SIGN) || + (protection_kind == DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION)); +} + +static bool +has_origin_authentication( + DDS_Security_ProtectionKind kind) +{ + return ((kind == DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION) || (kind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION)); +} + +static inline bool +crypto_buffer_read_uint32( + uint32_t *value, + unsigned char **ptr, + uint32_t *remain) +{ + if ((*remain) < sizeof(uint32_t)) + return false; + + *value = ddsrt_fromBE4u(*(uint32_t *)(*ptr)); + (*ptr) += sizeof(uint32_t); + (*remain) -= (uint32_t)sizeof(uint32_t); + + return true; +} + +static inline bool +crypto_buffer_read_bytes( + unsigned char *bytes, + uint32_t num, + unsigned char **ptr, + uint32_t *remain) +{ + if ((*remain) < num) + return false; + memcpy(bytes, *ptr, num); + (*ptr) += num; + (*remain) -= num; + + return true; +} + + +/** + * Increase the length of the submessage + * When the buffer does not contain enough memory the + * buffer is reallocated with the increased size. + * The function returns the submessage which may + * be reallocated in memory. + */ +static struct submsg_header * +append_submessage( + DDS_Security_OctetSeq *seq, + struct submsg_header *msg, + size_t size) +{ + assert ((size_t)msg->length + size <= UINT16_MAX); + if (size + seq->_length > seq->_maximum) + { + size_t l = seq->_length + size; + unsigned char *ptr = seq->_buffer; + size_t offset = (size_t)(((unsigned char *)msg) - ptr); + + seq->_buffer = ddsrt_realloc(ptr, l); + seq->_maximum = (DDS_Security_unsigned_long)l; + msg = (struct submsg_header *)&seq->_buffer[offset]; + } + seq->_length += (uint32_t)size; + msg->length = (uint16_t)(msg->length + size); + + return msg; +} + +/** + * Add a new submessage to the tail of the supplied buffer. + * When the supplied buffer does not contain enough memory + * it will be reallocated. + * The buffer's maximum indicated the total size of the + * buffer. The buffer's length indicates the used size. + * + * @param[in] seq Buffer + * @param[in] id Submessage id + * @param[in] flags Indicates big or little endian + * @param[in] size The octetToNextSubmessage + */ +static struct submsg_header * +add_submessage( + DDS_Security_OctetSeq *seq, + unsigned char id, + unsigned char flags, + size_t size) +{ + struct submsg_header *msg; + size_t len = sizeof(struct submsg_header) + size; + assert (size <= UINT16_MAX); + + if (len + seq->_length > seq->_maximum) + { + size_t l = len + seq->_length; + unsigned char *ptr = seq->_buffer; + seq->_buffer = ddsrt_realloc (ptr, l); + seq->_maximum = (DDS_Security_unsigned_long)l; + } + + msg = (struct submsg_header *)&seq->_buffer[seq->_length]; + msg->id = id; + msg->flags = flags; + msg->length = (uint16_t)size; + seq->_length += (uint32_t)len; + + return msg; +} + +/** + * @brief Adds info_src content after info_src header and returns next available location + */ +static bool +add_info_src( + DDS_Security_OctetSeq *seq, + unsigned char *rtps_header, + unsigned char flags) +{ + struct submsg_header *info_src_hdr = add_submessage(seq, SMID_SRTPS_INFO_SRC_KIND, + flags, INFO_SRC_SIZE - sizeof(struct submsg_header)); + unsigned char *ptr = (unsigned char *)(info_src_hdr + 1); + memset(ptr, 0, 4); /* skip unused bytes */ + memcpy(ptr + 4, rtps_header + 4, INFO_SRC_SIZE - sizeof(struct submsg_header) - 4); + return true; +} + +static bool +read_rtps_header( + DDS_Security_OctetSeq *rtps_header, + unsigned char **ptr, + uint32_t *remain) +{ + if ((*remain) > RTPS_HEADER_SIZE) + { + rtps_header->_buffer = *ptr; + rtps_header->_length = rtps_header->_maximum = RTPS_HEADER_SIZE; + (*ptr) += RTPS_HEADER_SIZE; + (*remain) -= RTPS_HEADER_SIZE; + return true; + } + + return false; +} + +/** + * Initialize the remote session info which is used + * to decode a received message. It will calculate the + * session key from the received crypto_header. + * + * @param[in,out] info The remote session information which is determined by this function + * @param[in] header The received crypto_header + * @param[in] master_salt The master_salt associated with the remote entity + * @param[in] master_key The master_key associated with the remote entity + * @param[in] transformation_kind The transformation kind (to determine key and salt size) + * @param[in,out] ex Security exception + */ +static bool +initialize_remote_session_info( + remote_session_info *info, + struct crypto_header *header, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + DDS_Security_SecurityException *ex) +{ + info->key_size = crypto_get_key_size (transformation_kind); + info->id = CRYPTO_TRANSFORM_ID(header->session_id); + return crypto_calculate_session_key(&info->key, info->id, master_salt, master_key, transformation_kind, ex); +} + +static bool transform_kind_valid(DDS_Security_CryptoTransformKind_Enum kind) +{ + return ((kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC) || + (kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM) || + (kind == CRYPTO_TRANSFORMATION_KIND_AES256_GMAC) || + (kind == CRYPTO_TRANSFORMATION_KIND_AES256_GCM)); +} + +/** + * @brief Read the crypto_header from the received data buffer + * + * @param[in] header The returned crypto_header + * @param[in,out] ptr Current read pointer in the received buffer + * @param[in,out] remain Remaining size in the received buffer + */ +static bool +read_crypto_header( + struct crypto_header *header, + unsigned char **ptr, + uint32_t *remain) +{ + return crypto_buffer_read_bytes((unsigned char *)header, sizeof(*header), ptr, remain); +} + +/** + * @brief Read the payload from the received data buffer + * + * @param[in,out] contents The returned payload + * @param[in] ptr Current read pointer in the received buffer + * @param[in] size Remaining size in the received buffer + */ +static DDS_Security_boolean +read_crypto_contents( + struct crypto_contents_ref *contents, + unsigned char *ptr, + uint32_t size) +{ + bool result = false; + + if (crypto_buffer_read_uint32(&contents->_length, &ptr, &size)) + { + contents->_data = ptr; + if (size == contents->_length) + result = true; + } + return result; +} + +/** + * Read the crypto_footer from the received data buffer + * The size of the footer depends on the number of + * receiver specific macs present in the message. + * + * @param[in,out] footer The returned crypto_footer + * @param[in,out] ptr Current read pointer in the received buffer + * @param[in,out] remain Remaining size in the received buffer + */ +static bool +read_crypto_footer( + struct crypto_footer **footer, + unsigned char **ptr, + uint32_t *remain) +{ + uint32_t len; + size_t sz; + struct crypto_footer *ft; + crypto_hmac_t common_mac; + + if (!crypto_buffer_read_bytes(common_mac.data, CRYPTO_HMAC_SIZE, ptr, remain) || + !crypto_buffer_read_uint32(&len, ptr, remain)) + return false; + + if (len > (*remain)) + return false; + + sz = CRYPTO_HMAC_SIZE + sizeof(uint32_t) + len * sizeof(struct receiver_specific_mac); + ft = ddsrt_malloc(sz); + + memcpy(ft->common_mac.data, common_mac.data, CRYPTO_HMAC_SIZE); + ft->receiver_specific_macs._length = len; + + if (len > 0) + { + sz = len * sizeof(struct receiver_specific_mac); + if (!crypto_buffer_read_bytes((unsigned char *)&ft->receiver_specific_macs._buffer[0], (uint32_t)sz, ptr, remain)) + { + ddsrt_free(ft); + *footer = NULL; + return false; + } + } + + *footer = ft; + return true; +} + +/** + * @brief Read the submessage header from the received data buffer + * + * @param[in,out] submsg The returned submessage header + * @param[in,out] ptr Current read pointer in the received buffer + * @param[in,out] remain Remaining size in the received buffer + */ +static bool +read_submsg_header( + struct submsg_header *submsg, + unsigned char **ptr, + uint32_t *remain) +{ + int swap; + bool result = crypto_buffer_read_bytes((unsigned char *)submsg, sizeof(*submsg), ptr, remain); + if (result) + { + if ((submsg->flags & 0x01) == 0) + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + submsg->length = swap ? ddsrt_bswap2u(submsg->length) : submsg->length; + if ((uint32_t)(submsg->length) > (*remain)) + result = false; + } + + return result; +} + +/** + * @brief Used by the decode_serialized_payload function to split the received message in the composed components: + * + * @param[in] payload The received serialized payload + * @param[in] header The crypto_header contained in the payload + * @param[in,out] payload_ptr The actual payload (either encoded or plain) + * @param[in,out] payload_len Length of the payload + * @param[in,out] footer The crypto_footer contained in the payload + */ +static bool +split_encoded_serialized_payload( + const DDS_Security_OctetSeq *payload, + struct crypto_header *header, + unsigned char **payload_ptr, + uint32_t *payload_len, + struct crypto_footer **footer) +{ + /* For data, the footer is always the same length. */ + const uint32_t footer_len = CRYPTO_HMAC_SIZE + sizeof(uint32_t); + unsigned char *ptr = payload->_buffer; + uint32_t remain = payload->_length; + + /* Get header. */ + if (read_crypto_header(header, &ptr, &remain)) + { + if (remain >= footer_len) + { + /* Get contents. */ + *payload_ptr = ptr; + *payload_len = remain - footer_len; + /* Get footer. */ + ptr = (*payload_ptr) + (*payload_len); + remain = footer_len; + if (read_crypto_footer(footer, &ptr, &remain)) + return true; + } + } + + return false; +} + +/** + * @brief Read the SEC_PREFIX submessage from a received message + * + * @param[in,out] prefix The contents of the SEC_PREFIX submessage header + * @param[in,out] header The crypto_header contained in the SEC_PREFIX submessage + * @param[in,out] ptr Current read pointer in the received buffer + * @param[in,out] remain Remaining size in the received buffer + * @param[in] expected Expected submessage kind + */ +static bool +read_prefix_submessage( + struct submsg_header *prefix, + struct crypto_header *header, + unsigned char **ptr, + uint32_t *remain, + enum SecureSubmsgKind_t expected) +{ + uint32_t datalen; + + if (!read_submsg_header(prefix, ptr, remain)) + return false; + + if (prefix->id != expected) + return false; + + datalen = prefix->length; + if (datalen != sizeof(struct crypto_header)) + return false; + + if (!read_crypto_header(header, ptr, remain)) + return false; + + return true; +} + +/** + * @brief Read the SEC_POSTFIX submessage from a received message + * + * @param[in,out] postfix The contents of the SEC_POSTFIX submessage header + * @param[in,out] footer The crypto_footer contained in the SEC_POSTFIX submessage + * @param[in,out] ptr Current read pointer in the received buffer + * @param[in,out] remain Remaining size in the received buffer + * @param[in] expected Expected submessage kind + */ +static bool +read_postfix_submessage( + struct submsg_header *postfix, + struct crypto_footer **footer, + unsigned char **ptr, + uint32_t *remain, + enum SecureSubmsgKind_t expected) +{ + uint32_t datalen; + size_t sz; + + if (!read_submsg_header(postfix, ptr, remain)) + return false; + + if (postfix->id != expected) + return false; + + datalen = postfix->length; + + if (!read_crypto_footer(footer, ptr, remain)) + return false; + + sz = CRYPTO_FOOTER_BASIC_SIZE + (*footer)->receiver_specific_macs._length * sizeof(struct receiver_specific_mac); + + if (datalen != sz) + { + ddsrt_free(*footer); + *footer = NULL; + return false; + } + + return true; +} + +/** + * Read the body submessage from a received message + * The message received may be encoded or not. When encoded + * a SEC_BODY submessage is present otherwise the original + * submessage is present. When a SEC_BODY submessage is present + * the contents will be set to the contents of the SEC_BODY otherwise + * the contents will be set to the submessage itself. + * + * @param[in,out] body The contents of the body submessage header + * @param[in,out] contents The contents of the SEC_BODY submessage or the submessage itself + * @param[in,out] ptr Current read pointer in the received buffer + * @param[in,out] remain Remaining size in the received buffer + */ +static bool +read_body_submessage( + struct submsg_header *body, + struct crypto_contents_ref *contents, + unsigned char **ptr, + uint32_t *remain) +{ + uint32_t datalen; + struct encrypted_data *encrypted; + + contents->_data = *ptr; + + if (!read_submsg_header(body, ptr, remain)) + return false; + + datalen = body->length; + if (body->id == SMID_SEC_BODY_KIND) + { + encrypted = (struct encrypted_data *)*ptr; + contents->_length = ddsrt_fromBE4u(encrypted->length); + contents->_data = encrypted->data; + if (contents->_length > datalen) + return false; + } + else + { + contents->_length = datalen + (uint32_t)sizeof(struct submsg_header); + } + + if ((*remain) < datalen) + return false; + + (*ptr) += datalen; + (*remain) -= datalen; + + return true; +} + +/** + * body is invalid if not encrypted + * info_src is invalid if encrypted + */ +static bool +read_rtps_body( + struct submsg_header *body, + struct crypto_contents_ref *contents, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + unsigned char **ptr, + uint32_t *remain) +{ + uint32_t datalen; + struct submsg_header submessage_header; + + if (is_encryption_required(transformation_kind)) + { /*read sec body */ + if (!read_body_submessage(body, contents, ptr, remain) || body->id != SMID_SEC_BODY_KIND) + return false; + } + else + { + unsigned char *body_start_with_info = *ptr; + bool arrived_to_postfix = false; + + if (!read_submsg_header(&submessage_header, ptr, remain) || submessage_header.id != SMID_SRTPS_INFO_SRC_KIND) + return false; + + (*ptr) += submessage_header.length; + (*remain) -= submessage_header.length; + + while (*remain > sizeof(struct submsg_header) && !arrived_to_postfix) + { + if (!read_submsg_header(&submessage_header, ptr, remain)) + return false; + + if (submessage_header.id != SMID_SRTPS_POSTFIX_KIND) + { + (*ptr) += submessage_header.length; + (*remain) -= submessage_header.length; + } + else + { + /*revert last read*/ + (*ptr) -= sizeof(struct submsg_header); + (*remain) += (uint32_t)sizeof(struct submsg_header); + arrived_to_postfix = true; + } + } + + if (!arrived_to_postfix) + return false; + + datalen = (uint32_t)(*ptr - body_start_with_info); /* rtps submessage + info_src + body data*/ + contents->_data = body_start_with_info; + contents->_length = datalen; + } + + return true; +} + +/** + * @brief Split a received message is the various components + * + * @param[in] data Buffer containing the received message + * @param[in] prefix The SEC_PREFIX submessage header + * @param[in] body The body submessage, either SEC_BODY or the not encoded submessage + * @param[in] postfix The SEC_POSTFIX submessage header + * @param[in] header Crypto_header contained in the SEC_PREFIX submessage + * @param[in] contents Crypto contents + * @param[in,out] footer Crypto_footer contained in the SEC_POSTFIX submessage + */ +static bool +split_encoded_submessage( + const DDS_Security_OctetSeq *data, + struct submsg_header *prefix, + struct submsg_header *body, + struct submsg_header *postfix, + struct crypto_header *header, + struct crypto_contents_ref *contents, + struct crypto_footer **footer) +{ + unsigned char *ptr = data->_buffer; + uint32_t remain = data->_length; + *footer = NULL; + + return (read_prefix_submessage(prefix, header, &ptr, &remain, SMID_SEC_PREFIX_KIND) && + read_body_submessage(body, contents, &ptr, &remain) && + read_postfix_submessage(postfix, footer, &ptr, &remain, SMID_SEC_POSTFIX_KIND)); +} + +static bool +split_encoded_rtps_message( + const DDS_Security_OctetSeq *data, + DDS_Security_OctetSeq *rtps_header, + struct submsg_header *prefix, + struct submsg_header *body, + struct submsg_header *postfix, + struct crypto_header *header, + struct crypto_contents_ref *contents, + struct crypto_footer **footer) +{ + unsigned char *ptr = data->_buffer; + uint32_t remain = data->_length; + uint32_t transform_kind; + *footer = NULL; + if (rtps_header->_buffer) + return false; + if (!read_rtps_header(rtps_header, &ptr, &remain)) + return false; + if (!read_prefix_submessage(prefix, header, &ptr, &remain, SMID_SRTPS_PREFIX_KIND)) + return false; + + transform_kind = CRYPTO_TRANSFORM_KIND(header->transform_identifier.transformation_kind); + + if (!read_rtps_body(body, contents, transform_kind, &ptr, &remain)) + return false; + if (!read_postfix_submessage(postfix, footer, &ptr, &remain, SMID_SRTPS_POSTFIX_KIND)) + return false; + + return true; +} + +/** + * @brief Initialize the crypto_header + */ +static void +set_crypto_header( + struct crypto_header *header, + uint32_t transform_kind, + uint32_t transform_id, + uint32_t session_id, + uint64_t init_vector_suffx) +{ + struct + { + uint32_t tkind; + uint32_t tid; + uint32_t sid; + uint32_t ivh; + uint32_t ivl; + } s; + uint64_t ivs = ddsrt_toBE8u(init_vector_suffx); + + s.tkind = ddsrt_toBE4u(transform_kind); + s.tid = ddsrt_toBE4u(transform_id); + s.sid = ddsrt_toBE4u(session_id); + s.ivh = (uint32_t)(ivs >> 32); + s.ivl = (uint32_t)ivs; + + memcpy(header, &s, sizeof(*header)); +} + +/* + * Function implementations + */ + +static DDS_Security_boolean +encode_serialized_payload( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_buffer, + DDS_Security_OctetSeq *extra_inline_qos, + const DDS_Security_OctetSeq *plain_buffer, + const DDS_Security_DatawriterCryptoHandle writer_id, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + dds_security_crypto_key_factory *factory; + session_key_material *session; + struct crypto_header *header; + struct crypto_contents *contents = NULL; + struct crypto_footer *footer; + unsigned char *buffer; + unsigned char *payload; + crypto_hmac_t hmac; + uint32_t payload_len; + uint32_t transform_kind, transform_id; + size_t size, offset; + + DDSRT_UNUSED_ARG(extra_inline_qos); + + memset(hmac.data, 0, sizeof(crypto_hmac_t)); + + if (!instance || !encoded_buffer || !plain_buffer || plain_buffer->_length == 0 || writer_id == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_serialized_payload: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_inv_arg; + } + + /* check if the payload is aligned on a 4 byte boundary */ + if ((plain_buffer->_length % 4) != 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_DATA_NOT_ALIGNED_CODE, 0, + "encode_serialized_payload: " DDS_SECURITY_ERR_INVALID_CRYPTO_DATA_NOT_ALIGNED_MESSAGE); + goto fail_inv_arg; + } + + /* Retrieve key material from sending_datawriter_crypto from factory */ + factory = cryptography_get_crypto_key_factory(impl->crypto); + if (!crypto_factory_get_writer_key_material(factory, writer_id, 0, true, &session, NULL, ex)) + goto fail_inv_arg; + + if (!session) + { + DDS_Security_OctetSeq_copy(encoded_buffer, plain_buffer); + return true; + } + + transform_kind = session->master_key_material->transformation_kind; + transform_id = session->master_key_material->sender_key_id; + + if (!is_encryption_required(transform_kind) && !is_authentication_required(transform_kind)) + { + DDS_Security_OctetSeq_copy(encoded_buffer, plain_buffer); + CRYPTO_OBJECT_RELEASE(session); + return true; + } + + /* update sessionKey when needed */ + if (!crypto_session_key_material_update(session, plain_buffer->_length, ex)) + goto fail_update_key; + + /* increment init_vector_suffix */ + session->init_vector_suffix++; + + /* + * allocate buffer for encoded data, size includes: + * - CryptoHeader + * if (encrypted) { + * - CryptoContents : size of the data + cypher block_size + 1 + * } else { + * - Plain payload + * } + * - CryptoFooter + * See spec: 9.5.3.3.4.4 Result from encode_serialized_payload + * Make sure to allocate enough memory for both options. + */ + size = sizeof(*header) + sizeof(*contents) + sizeof(*footer) + plain_buffer->_length + session->block_size + 1; + buffer = ddsrt_malloc(size); + header = (struct crypto_header *)buffer; + payload = &buffer[sizeof(*header)]; + + /* create CryptoHeader */ + set_crypto_header(header, transform_kind, transform_id, session->id, session->init_vector_suffix); + + /* if the transformation_kind indicates encryption then encrypt the buffer */ + payload_len = 0; + if (is_encryption_required(transform_kind)) + { + contents = (struct crypto_contents *)payload; + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, plain_buffer->_buffer, plain_buffer->_length, NULL, 0, contents->_data, &payload_len, &hmac, ex)) + goto fail_encrypt; + contents->_length = ddsrt_toBE4u(payload_len); + payload_len += (uint32_t)sizeof(uint32_t); + } + else if (is_authentication_required(transform_kind)) + { + /* the transformation_kind indicates only indicates authentication the determine HMAC */ + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, NULL, 0, plain_buffer->_buffer, plain_buffer->_length, NULL, NULL, &hmac, ex)) + goto fail_encrypt; + memcpy(payload, plain_buffer->_buffer, plain_buffer->_length); + payload_len = plain_buffer->_length; + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_serialized_payload: unknown transform_kind %d", (int)transform_kind); + goto fail_encrypt; + } + + /* create CryptoFooter */ + offset = sizeof(*header) + payload_len; + footer = (struct crypto_footer *)(buffer + offset); + memset(footer, 0, sizeof(*footer)); + memcpy(footer->common_mac.data, hmac.data, CRYPTO_HMAC_SIZE); + + size = offset + CRYPTO_HMAC_SIZE + sizeof(uint32_t); + + encoded_buffer->_length = encoded_buffer->_maximum = (uint32_t)size; + encoded_buffer->_buffer = buffer; + + CRYPTO_OBJECT_RELEASE(session); + + return true; + +fail_encrypt: + ddsrt_free(buffer); +fail_update_key: + CRYPTO_OBJECT_RELEASE(session); +fail_inv_arg: + return false; +} + +static bool +add_reader_specific_mac( + DDS_Security_OctetSeq *data, + struct submsg_header *postfix, + master_key_material *key_material, + session_key_material *session, + DDS_Security_ProtectionKind protection_kind, + DDS_Security_SecurityException *ex) +{ + bool result = true; + struct submsg_header *prefix; + struct crypto_header *header; + struct crypto_footer *footer; + crypto_session_key_t key; + crypto_hmac_t hmac; + + if (has_origin_authentication(protection_kind)) + { + uint32_t index; + + postfix = append_submessage(data, postfix, sizeof(struct receiver_specific_mac)); + /* determine header crypto header because the append operation may have changed the buffer location */ + prefix = (struct submsg_header *)data->_buffer; + header = (struct crypto_header *)(prefix + 1); + footer = (struct crypto_footer *)(postfix + 1); + index = ddsrt_fromBE4u(footer->receiver_specific_macs._length); + + if (!crypto_calculate_receiver_specific_key(&key, session->id, key_material->master_salt, key_material->master_receiver_specific_key, key_material->transformation_kind, ex) || + !crypto_cipher_encrypt_data(&key, session->key_size, header->session_id, NULL, 0, footer->common_mac.data, CRYPTO_HMAC_SIZE, NULL, NULL, &hmac, ex)) + { + result = false; + } + else + { + uint32_t key_id = ddsrt_toBE4u(key_material->receiver_specific_key_id); + memcpy(footer->receiver_specific_macs._buffer[index].receiver_mac.data, hmac.data, CRYPTO_HMAC_SIZE); + memcpy(footer->receiver_specific_macs._buffer[index].receiver_mac_key_id, &key_id, sizeof(key_id)); + footer->receiver_specific_macs._length = ddsrt_toBE4u(++index); + } + } + + return result; +} + +static bool +add_crypto_reader_specific_mac( + dds_security_crypto_key_factory *factory, + DDS_Security_OctetSeq *data, + DDS_Security_DatareaderCryptoHandle reader_crypto, + struct submsg_header *postfix, + DDS_Security_SecurityException *ex) +{ + bool result = true; + master_key_material *key_material = NULL; + session_key_material *session = NULL; + DDS_Security_ProtectionKind protection_kind; + + if (!crypto_factory_get_remote_reader_sign_key_material(factory, reader_crypto, &key_material, &session, &protection_kind, ex)) + return false; + + result = add_reader_specific_mac(data, postfix, key_material, session, protection_kind, ex); + + CRYPTO_OBJECT_RELEASE(session); + CRYPTO_OBJECT_RELEASE(key_material); + + return result; +} + +static bool +add_receiver_specific_mac( + dds_security_crypto_key_factory *factory, + DDS_Security_OctetSeq *data, + DDS_Security_DatareaderCryptoHandle sending_participant_crypto, + DDS_Security_DatareaderCryptoHandle receiving_participant_crypto, + struct submsg_header *postfix, + DDS_Security_SecurityException *ex) +{ + bool result = true; + session_key_material *session = NULL; + struct submsg_header *prefix; + struct crypto_header *header; + struct crypto_footer *footer; + DDS_Security_ProtectionKind local_protection_kind; + DDS_Security_ProtectionKind remote_protection_kind; + crypto_session_key_t key; + crypto_hmac_t hmac; + participant_key_material *pp_key_material; + + /* get local crypto and session*/ + if (!crypto_factory_get_local_participant_data_key_material(factory, sending_participant_crypto, &session, &local_protection_kind, ex)) + return false; + + /* get remote crypto tokens */ + if (!crypto_factory_get_participant_crypto_tokens(factory, sending_participant_crypto, receiving_participant_crypto, &pp_key_material, &remote_protection_kind, ex)) + { + CRYPTO_OBJECT_RELEASE(session); + return false; + } + + if (has_origin_authentication(remote_protection_kind)) + { + uint32_t index; + + postfix = append_submessage(data, postfix, sizeof(struct receiver_specific_mac)); + /* determine header crypto header because the append operation may have changed the buffer location */ + prefix = (struct submsg_header *)(data->_buffer + RTPS_HEADER_SIZE); + header = (struct crypto_header *)(prefix + 1); + footer = (struct crypto_footer *)(postfix + 1); + index = ddsrt_fromBE4u(footer->receiver_specific_macs._length); + + if (!crypto_calculate_receiver_specific_key(&key, session->id, pp_key_material->local_P2P_key_material->master_salt, + pp_key_material->local_P2P_key_material->master_receiver_specific_key, pp_key_material->local_P2P_key_material->transformation_kind, ex) || + !crypto_cipher_encrypt_data(&key, session->key_size, header->session_id, NULL, 0, footer->common_mac.data, CRYPTO_HMAC_SIZE, NULL, NULL, &hmac, ex)) + { + result = false; + } + else + { + uint32_t key_id = ddsrt_toBE4u(pp_key_material->local_P2P_key_material->receiver_specific_key_id); + memcpy(footer->receiver_specific_macs._buffer[index].receiver_mac.data, hmac.data, CRYPTO_HMAC_SIZE); + memcpy(footer->receiver_specific_macs._buffer[index].receiver_mac_key_id, &key_id, sizeof(key_id)); + footer->receiver_specific_macs._length = ddsrt_toBE4u(++index); + } + } + CRYPTO_OBJECT_RELEASE(pp_key_material); + CRYPTO_OBJECT_RELEASE(session); + return result; +} + +static DDS_Security_boolean +encode_datawriter_submessage_sign ( + dds_security_crypto_key_factory *factory, + DDS_Security_OctetSeq *encoded_submsg, + const DDS_Security_DatareaderCryptoHandleSeq *reader_crypto_list, + int32_t *index, + DDS_Security_SecurityException *ex +) +{ + DDS_Security_boolean result; + struct submsg_header *prefix = (struct submsg_header *)encoded_submsg->_buffer; + struct submsg_header *body = (struct submsg_header *)(((unsigned char *)prefix) + prefix->length + sizeof(struct submsg_header)); + struct submsg_header *postfix = (struct submsg_header *)(((unsigned char *)body) + body->length + sizeof(struct submsg_header)); + + result = add_crypto_reader_specific_mac(factory, encoded_submsg, reader_crypto_list->_buffer[*index], postfix, ex); + if (result) + (*index)++; + + return result; +} + +static DDS_Security_boolean +encode_datawriter_submessage_encrypt ( + dds_security_crypto_key_factory *factory, + DDS_Security_OctetSeq *encoded_submsg, + const DDS_Security_OctetSeq *plain_submsg, + const DDS_Security_DatawriterCryptoHandle writer_crypto, + const DDS_Security_DatareaderCryptoHandleSeq *reader_crypto_list, + int32_t *index, + DDS_Security_SecurityException *ex +) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto = 0; + DDS_Security_OctetSeq data; + session_key_material *session = NULL; + DDS_Security_ProtectionKind protection_kind; + unsigned char flags; + unsigned char *contents; + crypto_hmac_t hmac; + uint32_t payload_len; + size_t size; + struct submsg_header *prefix; + struct crypto_header *header; + struct submsg_header *postfix; + struct submsg_header *body; + struct crypto_footer *footer; + uint32_t transform_kind, transform_id; + DDS_Security_boolean result = false; + + if (reader_crypto_list->_length > 0) + reader_crypto = reader_crypto_list->_buffer[0]; + + if (!crypto_factory_get_writer_key_material(factory, writer_crypto, reader_crypto, false, &session, &protection_kind, ex)) + goto enc_dw_submsg_fail_keymat; + + /* Determine the size of the buffer + * When no encryption + * - submsg header SEC_PREFIX + * - crypto header + * - size of the plain_submsg + * - submsg header SEC_POSTFIX + * - crypto footer based on the size of the receiving_datareader_crypto_list + * When encryption is required: + * - submsg header SEC_PREFIX + * - crypto header + * - submsg header SEC_BODY + * - estimated size of the encoded submessage (size of the plain_submsg + some extra for possible padding + * - submsg header SEC_POSTFIX + * - crypto footer based on the size of the receiving_datareader_crypto_list + */ + + size = 2 * sizeof(struct submsg_header) + sizeof(struct crypto_header) + sizeof(struct crypto_footer) + ALIGN4(plain_submsg->_length); + size += reader_crypto_list->_length * CRYPTO_HMAC_SIZE; + /* assure that the buffer contains enough memory to accommodate the encrypted payload */ + if (is_encryption_required(session->master_key_material->transformation_kind)) + size += sizeof(struct submsg_header) + sizeof(uint32_t) + CRYPTO_ENCRYPTION_MAX_PADDING; + + flags = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN) ? 0x01 : 0x00; + + /* allocate a buffer to store the encoded submessage */ + data._buffer = ddsrt_malloc(size); + data._length = 0; + data._maximum = (uint32_t)size; + + /* Set the SEC_PREFIX and associated CryptoHeader */ + prefix = add_submessage(&data, SMID_SEC_PREFIX_KIND, flags, sizeof(struct crypto_header)); + header = (struct crypto_header *)(prefix + 1); + contents = (unsigned char *)(header + 1); + + /* update sessionKey when needed */ + if (!crypto_session_key_material_update(session, plain_submsg->_length, ex)) + goto enc_dw_submsg_fail; + + /* increment init_vector_suffix */ + session->init_vector_suffix++; + + transform_kind = session->master_key_material->transformation_kind; + transform_id = session->master_key_material->sender_key_id; + + set_crypto_header(header, transform_kind, transform_id, session->id, session->init_vector_suffix); + + if (is_encryption_required(transform_kind)) + { + struct encrypted_data *encrypted; + size_t submsg_len = plain_submsg->_length + sizeof(uint32_t); + if (submsg_len > UINT16_MAX) + goto enc_dw_submsg_fail; + + /* add SEC_BODY submessage */ + body = add_submessage(&data, SMID_SEC_BODY_KIND, flags, submsg_len); + encrypted = (struct encrypted_data *)(body + 1); + contents = encrypted->data; + + /* encrypt submessage */ + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, plain_submsg->_buffer, plain_submsg->_length, NULL, 0, contents, &payload_len, &hmac, ex)) + goto enc_dw_submsg_fail; + + /* adjust the length of the body submessage when needed */ + encrypted->length = ddsrt_toBE4u(payload_len); + if (payload_len + sizeof(encrypted->length) > plain_submsg->_length) + { + size_t inc = payload_len + sizeof(encrypted->length) - plain_submsg->_length; + body->length = (uint16_t)(body->length + inc); + data._length += (uint32_t)inc; + } + } + else if (is_authentication_required(transform_kind)) + { + /* the transformation_kind indicates only indicates authentication the determine HMAC */ + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, NULL, 0, plain_submsg->_buffer, plain_submsg->_length, NULL, NULL, &hmac, ex)) + goto enc_dw_submsg_fail; + + /* copy submessage */ + body = (struct submsg_header *)contents; + memcpy(contents, plain_submsg->_buffer, plain_submsg->_length); + payload_len = plain_submsg->_length; + data._length += payload_len; + } + else + { + goto enc_dw_submsg_fail; + } + + postfix = add_submessage(&data, SMID_SEC_POSTFIX_KIND, flags, CRYPTO_FOOTER_BASIC_SIZE); + footer = (struct crypto_footer *)(postfix + 1); + + /* Set initial SEC_POSTFIX and CryptoFooter containing the common_mac + * Note that the length of the postfix may increase when reader specific macs are added */ + memcpy(footer->common_mac.data, hmac.data, CRYPTO_HMAC_SIZE); + footer->receiver_specific_macs._length = 0; + + *encoded_submsg = data; + if (has_origin_authentication(protection_kind)) + { + if (reader_crypto_list->_length != 0) + { + if (!add_crypto_reader_specific_mac(factory, encoded_submsg, reader_crypto_list->_buffer[0], postfix, ex)) + goto enc_dw_submsg_fail; + (*index)++; + } + } + else + { + *index = (int32_t) reader_crypto_list->_length; + } + result = true; + +enc_dw_submsg_fail: + CRYPTO_OBJECT_RELEASE(session); + if (!result) + { + ddsrt_free(data._buffer); + encoded_submsg->_buffer = NULL; + encoded_submsg->_length = 0; + encoded_submsg->_maximum = 0; + } +enc_dw_submsg_fail_keymat: + return result; +} + +static DDS_Security_boolean +encode_datawriter_submessage( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_submsg, + const DDS_Security_OctetSeq *plain_submsg, + const DDS_Security_DatawriterCryptoHandle writer_crypto, + const DDS_Security_DatareaderCryptoHandleSeq *reader_crypto_list, + int32_t *index, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_boolean result = false; + + /* check arguments */ + if (!instance || !encoded_submsg || (writer_crypto == 0) || !reader_crypto_list || + (reader_crypto_list->_length == 0) || (reader_crypto_list->_length > INT32_MAX) || + !index || ((*index) >= (int32_t)reader_crypto_list->_length)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_datawriter_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_dw_submsg_inv_args; + } + + if (*index == 0) + { + if (!plain_submsg || (plain_submsg->_length == 0)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_datawriter_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_dw_submsg_inv_args; + } + } + else + { + if (encoded_submsg->_length == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_datawriter_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_dw_submsg_inv_args; + } + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + if (*index == 0) + { + /* When the index is 0 then retrieve the key material of the writer */ + result = encode_datawriter_submessage_encrypt (factory, encoded_submsg, plain_submsg, + writer_crypto, reader_crypto_list, index, ex); + } + else + { + /* When the index is not 0 then add a signature for the specific reader */ + result = encode_datawriter_submessage_sign (factory, encoded_submsg, reader_crypto_list, index, ex); + } + +enc_dw_submsg_inv_args: + return result; +} + +static bool +add_writer_specific_mac( + dds_security_crypto_key_factory *factory, + DDS_Security_OctetSeq *data, + DDS_Security_DatawriterCryptoHandle writer_crypto, + struct submsg_header *postfix, + DDS_Security_SecurityException *ex) +{ + bool result = true; + master_key_material *key_material = NULL; + session_key_material *session = NULL; + DDS_Security_ProtectionKind protection_kind; + + if (!crypto_factory_get_remote_writer_sign_key_material(factory, writer_crypto, &key_material, &session, &protection_kind, ex)) + return false; + + result = add_reader_specific_mac(data, postfix, key_material, session, protection_kind, ex); + + CRYPTO_OBJECT_RELEASE(session); + CRYPTO_OBJECT_RELEASE(key_material); + + return result; +} + +static DDS_Security_boolean +encode_datareader_submessage( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_submsg, + const DDS_Security_OctetSeq *plain_submsg, + const DDS_Security_DatareaderCryptoHandle reader_crypto, + const DDS_Security_DatawriterCryptoHandleSeq *writer_crypto_list, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_DatawriterCryptoHandle writer_crypto = 0; + DDS_Security_OctetSeq data; + struct submsg_header *prefix; + struct crypto_header *header; + struct submsg_header *postfix; + struct submsg_header *body; + struct crypto_footer *footer; + session_key_material *session = NULL; + DDS_Security_ProtectionKind protection_kind; + unsigned char flags; + unsigned char *contents; + crypto_hmac_t hmac; + uint32_t payload_len; + size_t size; + DDS_Security_boolean result = false; + uint32_t transform_kind, transform_id; + + /* check arguments */ + if (!instance || !encoded_submsg || (reader_crypto == 0) || + !plain_submsg || (plain_submsg->_length == 0) || + !writer_crypto_list || (writer_crypto_list->_length == 0)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_datawriter_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_dr_submsg_inv_args; + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + if (writer_crypto_list->_length > 0) + writer_crypto = writer_crypto_list->_buffer[0]; + + if (!crypto_factory_get_reader_key_material(factory, reader_crypto, writer_crypto, &session, &protection_kind, ex)) + goto enc_dr_submsg_fail_keymat; + + /* Determine the size of the buffer + * When no encryption + * - submsg header SEC_PREFIX + * - crypto header + * - size of the plain_submsg + * - submsg header SEC_POSTFIX + * - crypto footer based on the size of the receiving_datareader_crypto_list + * When encryption is required: + * - submsg header SEC_PREFIX + * - crypto header + * - submsg header SEC_BODY + * - estimated size of the encoded submessage (size of the plain_submsg + some extra for possible padding + * - submsg header SEC_POSTFIX + * - crypto footer based on the size of the receiving_datareader_crypto_list + */ + + size = 2 * sizeof(struct submsg_header) + sizeof(struct crypto_header) + sizeof(struct crypto_footer) + ALIGN4(plain_submsg->_length); + size += writer_crypto_list->_length * CRYPTO_HMAC_SIZE; + /* assure that the buffer contains enough memory to accommodate the encrypted payload */ + if (is_encryption_required(session->master_key_material->transformation_kind)) + size += sizeof(struct submsg_header) + sizeof(uint32_t) + CRYPTO_ENCRYPTION_MAX_PADDING; + + flags = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN) ? 0x01 : 0x00; + + /* allocate a buffer to store the encoded submessage */ + data._buffer = ddsrt_malloc(size); + data._length = 0; + data._maximum = (uint32_t)size; + + /* Set the SEC_PREFIX and associated CryptoHeader */ + + prefix = add_submessage(&data, SMID_SEC_PREFIX_KIND, flags, sizeof(struct crypto_header)); + header = (struct crypto_header *)(prefix + 1); + contents = (unsigned char *)(header + 1); + + /* update sessionKey when needed */ + if (!crypto_session_key_material_update(session, plain_submsg->_length, ex)) + goto enc_dr_submsg_fail; + + /* increment init_vector_suffix */ + session->init_vector_suffix++; + + transform_kind = session->master_key_material->transformation_kind; + transform_id = session->master_key_material->sender_key_id; + + set_crypto_header(header, transform_kind, transform_id, session->id, session->init_vector_suffix); + + if (is_encryption_required(transform_kind)) + { + struct encrypted_data *encrypted; + size_t submsg_len = plain_submsg->_length + sizeof (uint32_t); + if (submsg_len > UINT16_MAX) + goto enc_dr_submsg_fail; + + /* add SEC_BODY submessage */ + body = add_submessage(&data, SMID_SEC_BODY_KIND, flags, submsg_len); + encrypted = (struct encrypted_data *)(body + 1); + contents = encrypted->data; + + /* encrypt submessage */ + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, plain_submsg->_buffer, plain_submsg->_length, NULL, 0, contents, &payload_len, &hmac, ex)) + goto enc_dr_submsg_fail; + + /* adjust the length of the body submessage when needed */ + encrypted->length = ddsrt_toBE4u(payload_len); + if (payload_len + sizeof(encrypted->length) > plain_submsg->_length) + { + size_t inc = payload_len + sizeof(encrypted->length) - plain_submsg->_length; + body->length = (uint16_t)(body->length + inc); + data._length += (uint32_t)inc; + } + } + else if (is_authentication_required(transform_kind)) + { + /* the transformation_kind indicates only indicates authentication the determine HMAC */ + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, NULL, 0, plain_submsg->_buffer, plain_submsg->_length, NULL, NULL, &hmac, ex)) + goto enc_dr_submsg_fail; + + /* copy submessage */ + body = (struct submsg_header *)contents; + memcpy(contents, plain_submsg->_buffer, plain_submsg->_length); + payload_len = plain_submsg->_length; + data._length += payload_len; + } + else + { + goto enc_dr_submsg_fail; + } + + postfix = add_submessage(&data, SMID_SEC_POSTFIX_KIND, flags, CRYPTO_FOOTER_BASIC_SIZE); + footer = (struct crypto_footer *)(postfix + 1); + + /* Set initial SEC_POSTFIX and CryptoFooter containing the common_mac + * Note that the length of the postfix may increase when writer specific macs are added */ + memcpy(footer->common_mac.data, hmac.data, CRYPTO_HMAC_SIZE); + footer->receiver_specific_macs._length = 0; + + if (has_origin_authentication(protection_kind)) + { + for (uint32_t i = 0; i < writer_crypto_list->_length; i++) + { + if (!add_writer_specific_mac(factory, &data, writer_crypto_list->_buffer[i], postfix, ex)) + goto enc_dr_submsg_fail; + } + } + *encoded_submsg = data; + result = true; + +enc_dr_submsg_fail: + CRYPTO_OBJECT_RELEASE(session); + if (!result) + { + ddsrt_free(data._buffer); + encoded_submsg->_buffer = NULL; + encoded_submsg->_maximum = 0; + encoded_submsg->_length = 0; + } +enc_dr_submsg_fail_keymat: +enc_dr_submsg_inv_args: + return result; +} + +static DDS_Security_boolean +check_reader_specific_mac( + struct crypto_header *header, + struct crypto_footer *footer, + master_key_material *key_material, + const char *context, + DDS_Security_SecurityException *ex) +{ + uint32_t session_id; + crypto_session_key_t key; + crypto_hmac_t *href = NULL; + crypto_hmac_t hmac; + uint32_t i; + + if (key_material->receiver_specific_key_id == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_RECEIVER_SIGN_CODE, 0, + "%s: don't have receiver key material to check specific mac", context); + return false; + } + + session_id = CRYPTO_TRANSFORM_ID(header->session_id); + for (i = 0; !href && (i < footer->receiver_specific_macs._length); i++) + { + uint32_t id = CRYPTO_TRANSFORM_ID(footer->receiver_specific_macs._buffer[i].receiver_mac_key_id); + + if (id == key_material->receiver_specific_key_id) + href = &footer->receiver_specific_macs._buffer[i].receiver_mac; + } + + if (!href) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_RECEIVER_SIGN_CODE, 0, + "%s: message does not contain receiver specific mac", context); + return false; + } + + if (!crypto_calculate_receiver_specific_key(&key, session_id, key_material->master_salt, key_material->master_receiver_specific_key, key_material->transformation_kind, ex)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_RECEIVER_SIGN_CODE, 0, + "%s: failed to calculate receiver specific session key", context); + return false; + } + + if (!crypto_cipher_encrypt_data(&key, crypto_get_key_size(key_material->transformation_kind), header->session_id, NULL, 0, footer->common_mac.data, CRYPTO_HMAC_SIZE, NULL, NULL, &hmac, ex)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_RECEIVER_SIGN_CODE, 0, + "%s: failed to calculate receiver specific hmac", context); + return false; + } + + if (memcmp(hmac.data, href->data, CRYPTO_HMAC_SIZE) != 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_RECEIVER_SIGN_CODE, 0, + "%s: message does not contain a valid receiver specific mac", context); + return false; + } + return true; +} + +static DDS_Security_boolean encode_rtps_message_sign ( + dds_security_crypto_key_factory *factory, + DDS_Security_OctetSeq *encoded_rtps_message, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + int32_t *receiving_participant_crypto_list_index, + DDS_Security_ParticipantCryptoHandle remote_id, + DDS_Security_SecurityException *ex +) +{ + size_t length_to_postfix, remaining = encoded_rtps_message->_length; + unsigned char *ptr; + DDS_Security_boolean result; + struct submsg_header *prefix = (struct submsg_header *)(encoded_rtps_message->_buffer + RTPS_HEADER_SIZE); + struct crypto_header *header = (struct crypto_header *)(prefix + 1); + struct submsg_header *submessage_header = (struct submsg_header *)(header + 1); + struct submsg_header *postfix = (struct submsg_header *)(((unsigned char *)submessage_header) + submessage_header->length + sizeof(struct submsg_header)); + + if (submessage_header->id == SMID_SRTPS_INFO_SRC_KIND) /* not encrypted */ + { + /* skip INFO_SRC_HDR to RTPS submessage header */ + ptr = ((unsigned char *)submessage_header + sizeof(struct submsg_header) + submessage_header->length); + remaining = (size_t) (encoded_rtps_message->_buffer + encoded_rtps_message->_length - ptr); + /* There may be multiple RTPS submessages until postfix */ + while (remaining - sizeof(struct submsg_header) > 0) + { + submessage_header = (struct submsg_header *)ptr; + length_to_postfix = submessage_header->length + sizeof(struct submsg_header); + postfix = (struct submsg_header *)(((unsigned char *)submessage_header) + length_to_postfix); + if (postfix->id == SMID_SRTPS_POSTFIX_KIND) + break; + remaining -= length_to_postfix; + ptr += length_to_postfix; + } + } + + result = add_receiver_specific_mac(factory, encoded_rtps_message, sending_participant_crypto, remote_id, postfix, ex); + if (result) + (*receiving_participant_crypto_list_index)++; + + return result; +} + +static DDS_Security_boolean encode_rtps_message_encrypt ( + dds_security_crypto_key_factory *factory, + DDS_Security_OctetSeq *encoded_rtps_message, + const DDS_Security_OctetSeq *plain_rtps_message, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + const DDS_Security_ParticipantCryptoHandleSeq *receiving_participant_crypto_list, + int32_t *receiving_participant_crypto_list_index, + DDS_Security_ParticipantCryptoHandle remote_id, + DDS_Security_SecurityException *ex +) +{ + session_key_material *session = NULL; + DDS_Security_ProtectionKind protection_kind; + DDS_Security_OctetSeq data; + DDS_Security_OctetSeq secure_body_plain; + struct submsg_header *prefix; + struct crypto_header *header; + struct submsg_header *postfix; + struct submsg_header *body; + struct crypto_footer *footer; + DDS_Security_boolean result = false; + unsigned char *contents; + crypto_hmac_t hmac; + uint32_t payload_len; + size_t size; + uint32_t transform_kind, transform_id; + unsigned char flags = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN) ? 0x01 : 0x00; + unsigned char *rtps_body = plain_rtps_message->_buffer + RTPS_HEADER_SIZE; + unsigned rtps_body_size = plain_rtps_message->_length - RTPS_HEADER_SIZE; + unsigned secure_body_plain_size = rtps_body_size + INFO_SRC_SIZE; + + /* get local crypto and session*/ + if (!crypto_factory_get_local_participant_data_key_material(factory, sending_participant_crypto, &session, &protection_kind, ex)) + goto enc_rtps_inv_keymat; + + secure_body_plain._buffer = ddsrt_malloc(secure_body_plain_size); + secure_body_plain._maximum = secure_body_plain_size; + secure_body_plain._length = 0; + + /* info_src and body */ + if (!add_info_src(&secure_body_plain, plain_rtps_message->_buffer, flags)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_rtps_message: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_rtps_fail; + } + memcpy(secure_body_plain._buffer + secure_body_plain._length, rtps_body, rtps_body_size); /* rtps message body */ + secure_body_plain._length += rtps_body_size; + + /* Determine the size of the buffer + * When no encryption + * - rtps header + * - submsg header SEC_PREFIX + * - crypto header + * - INFO_SRC (24) + * - size of the plain_rtps body + * - submsg header SEC_POSTFIX + * - crypto footer based on the size of the receiving_participant_crypto_list + * When encryption is required: + * - rtps header + * - submsg header SEC_PREFIX + * - crypto header + * - submsg header SEC_BODY + * - INFO_SRC (24) + * - estimated size of the encoded submessage (size of the plain_rtps_message + some extra for possible padding + * - submsg header SEC_POSTFIX + * - crypto footer based on the size of the receiving_participant_crypto_list + */ + + size = RTPS_HEADER_SIZE; /* RTPS Header */ + size += 2 * sizeof(struct submsg_header) + sizeof(struct crypto_header) + sizeof(struct crypto_footer) + ALIGN4(plain_rtps_message->_length); + size += receiving_participant_crypto_list->_length * CRYPTO_HMAC_SIZE; + size += sizeof(struct submsg_header) + RTPS_HEADER_SIZE; /* INFO_SRC */ + + if (is_encryption_required(session->master_key_material->transformation_kind)) + size += sizeof(struct submsg_header) + sizeof(uint32_t); + + /* allocate a buffer to store the encoded message */ + data._buffer = ddsrt_malloc(size); + data._length = 0; + data._maximum = (uint32_t)size; + + /* Add RTPS header */ + memcpy(data._buffer, plain_rtps_message->_buffer, RTPS_HEADER_SIZE); + data._length += RTPS_HEADER_SIZE; + + /* Set the SEC_PREFIX and associated CryptoHeader */ + prefix = add_submessage(&data, SMID_SRTPS_PREFIX_KIND, flags, sizeof(struct crypto_header)); + header = (struct crypto_header *)(prefix + 1); + contents = (unsigned char *)(header + 1); + + /* update sessionKey when needed */ + if (!crypto_session_key_material_update(session, secure_body_plain_size, ex)) + goto enc_rtps_fail_data; + + /* increment init_vector_suffix */ + session->init_vector_suffix++; + + transform_kind = session->master_key_material->transformation_kind; + transform_id = session->master_key_material->sender_key_id; + set_crypto_header(header, transform_kind, transform_id, session->id, session->init_vector_suffix); + + if (is_encryption_required(transform_kind)) + { + struct encrypted_data *encrypted; + size_t submsg_len = secure_body_plain_size + sizeof (uint32_t); + if (submsg_len > UINT16_MAX) + goto enc_rtps_fail_data; + + /* add SEC_BODY submessage */ + body = add_submessage(&data, SMID_SEC_BODY_KIND, flags, submsg_len); + encrypted = (struct encrypted_data *)(body + 1); + contents = encrypted->data; + + /* encrypt message */ + /* FIXME: improve performance by not copying plain_rtps_message to a new buffer (crypto_cipher_encrypt_data should allow encrypting parts of a message) */ + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, secure_body_plain._buffer, secure_body_plain_size, NULL, 0, contents, &payload_len, &hmac, ex)) + goto enc_rtps_fail_data; + + encrypted->length = ddsrt_toBE4u(payload_len); + if (payload_len + sizeof(encrypted->length) > secure_body_plain_size) + { + size_t inc = payload_len + sizeof(encrypted->length) - secure_body_plain_size; + body->length = (uint16_t)(body->length + inc); + data._length += (uint32_t)inc; + } + } + else if (is_authentication_required(transform_kind)) + { + /* the transformation_kind indicates only indicates authentication the determine HMAC */ + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, NULL, 0, secure_body_plain._buffer, secure_body_plain_size, NULL, NULL, &hmac, ex)) + goto enc_rtps_fail_data; + + /* copy submessage */ + memcpy(contents, secure_body_plain._buffer, secure_body_plain_size); + payload_len = secure_body_plain_size; + data._length += payload_len; + } + else + { + goto enc_rtps_fail_data; + } + + postfix = add_submessage(&data, SMID_SRTPS_POSTFIX_KIND, flags, CRYPTO_FOOTER_BASIC_SIZE); + footer = (struct crypto_footer *)(postfix + 1); + + /* Set initial SEC_POSTFIX and CryptoFooter containing the common_mac + * Note that the length of the postfix may increase when reader specific macs are added */ + memcpy(footer->common_mac.data, hmac.data, CRYPTO_HMAC_SIZE); + footer->receiver_specific_macs._length = 0; + *encoded_rtps_message = data; + if (has_origin_authentication(protection_kind)) + { + if (receiving_participant_crypto_list->_length != 0) + { + if (!add_receiver_specific_mac(factory, encoded_rtps_message, sending_participant_crypto, remote_id, postfix, ex)) + goto enc_rtps_fail_data; + (*receiving_participant_crypto_list_index)++; + } + } + else + { + *receiving_participant_crypto_list_index = (int32_t) receiving_participant_crypto_list->_length; + } + result = true; + +enc_rtps_fail_data: + if (!result) + { + ddsrt_free(data._buffer); + encoded_rtps_message->_buffer = NULL; + encoded_rtps_message->_length = 0; + encoded_rtps_message->_maximum = 0; + } +enc_rtps_fail: + CRYPTO_OBJECT_RELEASE(session); + ddsrt_free(secure_body_plain._buffer); +enc_rtps_inv_keymat: + return result; +} + +static DDS_Security_boolean +encode_rtps_message(dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_rtps_message, + const DDS_Security_OctetSeq *plain_rtps_message, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + const DDS_Security_ParticipantCryptoHandleSeq *receiving_participant_crypto_list, + int32_t *receiving_participant_crypto_list_index, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_ParticipantCryptoHandle remote_id; + DDS_Security_boolean result = false; + + /* check arguments */ + if (!instance || !encoded_rtps_message || sending_participant_crypto == 0 || !receiving_participant_crypto_list || + !receiving_participant_crypto_list_index || receiving_participant_crypto_list->_length == 0 || + (*receiving_participant_crypto_list_index) > (int32_t)receiving_participant_crypto_list->_length || + receiving_participant_crypto_list->_length > INT32_MAX) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_rtps_message: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_rtps_inv_arg; + } + + if (*receiving_participant_crypto_list_index == 0) + { + if (!plain_rtps_message || plain_rtps_message->_length == 0 || !plain_rtps_message->_buffer) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_rtps_message: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_rtps_inv_arg; + } + } + else + { + if (encoded_rtps_message->_length == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_rtps_message: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_rtps_inv_arg; + } + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + /* get remote participant handle */ + remote_id = receiving_participant_crypto_list->_buffer[*receiving_participant_crypto_list_index]; + + /* When the receiving_participant_crypto_list_index is 0 then retrieve the key material of the writer */ + if (*receiving_participant_crypto_list_index == 0) + { + result = encode_rtps_message_encrypt (factory, encoded_rtps_message, plain_rtps_message, sending_participant_crypto, + receiving_participant_crypto_list, receiving_participant_crypto_list_index, remote_id, ex); + } + else + { + /* When the receiving_participant_crypto_list_index is not 0 then add a signature for the specific reader */ + result = encode_rtps_message_sign (factory, encoded_rtps_message, sending_participant_crypto, + receiving_participant_crypto_list_index, remote_id, ex); + } + +enc_rtps_inv_arg: + return result; +} + + + +static DDS_Security_boolean +decode_rtps_message(dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_buffer, + const DDS_Security_OctetSeq *encoded_buffer, + const DDS_Security_ParticipantCryptoHandle receiving_participant_crypto, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + dds_security_crypto_key_factory *factory; + uint32_t transform_kind; + remote_session_info remote_session; + DDS_Security_OctetSeq rtps_header; + struct submsg_header prefix; + struct crypto_header header; + struct submsg_header postfix; + struct submsg_header body; + struct crypto_footer *footer; + struct crypto_contents_ref contents = {0, NULL}; + unsigned char *decoded_body; + uint32_t decoded_body_size; + static const char *context = "decode_rtps_message"; + participant_key_material *pp_key_material; + DDS_Security_ProtectionKind remote_protection_kind; + bool result = false; + + /* FIXME: when decoding a message the message is split in several parts (header, body, footer, etc) and for this + * memory is allocated which is probably not necessary. Performance should be improved by removing these allocations + * and use pointer to the data instead. */ + + /* check arguments */ + if (!instance || !encoded_buffer || sending_participant_crypto == 0 || receiving_participant_crypto == 0 || + encoded_buffer->_length == 0 || !encoded_buffer->_buffer || !plain_buffer) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_rtps_message: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_invalid_input; + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + memset(&rtps_header, 0, sizeof(DDS_Security_OctetSeq)); + + /* split the encoded submessage in the corresponding parts */ + if (!split_encoded_rtps_message(encoded_buffer, &rtps_header, &prefix, &body, &postfix, &header, &contents, &footer)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_rtps_message: invalid message"); + goto fail_invalid_input; + } + + transform_kind = CRYPTO_TRANSFORM_KIND(header.transform_identifier.transformation_kind); + + /* Retrieve key material from sending_participant_crypto and receiving_participant_crypto from factory */ + if (!crypto_factory_get_participant_crypto_tokens(factory, receiving_participant_crypto, sending_participant_crypto, &pp_key_material, &remote_protection_kind, ex)) + goto fail_tokens; + + if (!pp_key_material->remote_key_material) + goto fail_remote_keys_not_ready; + + if (has_origin_authentication(remote_protection_kind)) + { /* default governance value */ + if (!check_reader_specific_mac(&header, footer, pp_key_material->remote_key_material, context, ex)) + goto fail_reader_mac; + } + + /* calculate the session key */ + decoded_body = DDS_Security_OctetSeq_allocbuf(contents._length); + if (!initialize_remote_session_info(&remote_session, &header, pp_key_material->remote_key_material->master_salt, + pp_key_material->remote_key_material->master_sender_key, pp_key_material->remote_key_material->transformation_kind, ex)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_rtps_message: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_decrypt; + } + + if (is_encryption_required(transform_kind)) + { + if (!is_encryption_expected(remote_protection_kind)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_rtps_submessage: message is encrypted, which is unexpected"); + goto fail_decrypt; + } + + /* When the CryptoHeader indicates that encryption is performed then decrypt the submessage body */ + /* check if the body is a SEC_BODY submessage */ + if (body.id != SMID_SEC_BODY_KIND) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_rtps_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_decrypt; + } + + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, contents._data, contents._length, NULL, 0, + decoded_body, &decoded_body_size, &footer->common_mac, ex)) + { + goto fail_decrypt; + } + } + else if (is_authentication_required(transform_kind)) + { + if (!is_authentication_expected(remote_protection_kind)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_rtps_message: message is signed, which is unexpected"); + goto fail_decrypt; + } + /* When the CryptoHeader indicates that authentication is performed then calculate the HMAC */ + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, NULL, 0, contents._data, contents._length, NULL, 0, &footer->common_mac, ex)) + goto fail_decrypt; + decoded_body_size = contents._length; + memcpy(decoded_body, contents._data, contents._length); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_CODE, 0, + "decode_rtps_message: " DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_MESSAGE); + goto fail_decrypt; + } + + plain_buffer->_buffer = DDS_Security_OctetSeq_allocbuf(decoded_body_size - 4); /* INFO_SRC removed, "RTPS" prefix added */ + plain_buffer->_length = plain_buffer->_maximum = decoded_body_size - 4; /* INFO_SRC removed, "RTPS" prefix added */ + memcpy(plain_buffer->_buffer, "RTPS", 4); /* ADD RTPS */ + memcpy(plain_buffer->_buffer + 4, decoded_body + 8, decoded_body_size - 8); /* remove INFO_SRC */ + result = true; + +fail_decrypt: + ddsrt_free(decoded_body); +fail_remote_keys_not_ready: +fail_reader_mac: + CRYPTO_OBJECT_RELEASE(pp_key_material); +fail_tokens: + ddsrt_free(footer); +fail_invalid_input: + return result; +} + +static DDS_Security_boolean +preprocess_secure_submsg( + dds_security_crypto_transform *instance, + DDS_Security_DatawriterCryptoHandle *datawriter_crypto, + DDS_Security_DatareaderCryptoHandle *datareader_crypto, + DDS_Security_SecureSubmessageCategory_t *secure_submessage_category, + const DDS_Security_OctetSeq *encoded_rtps_submessage, + const DDS_Security_ParticipantCryptoHandle receiving_participant_crypto, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_Handle remote_handle; + DDS_Security_Handle local_handle; + DDS_Security_boolean result; + struct submsg_header submsg; + struct crypto_header cheader; + uint32_t transform_kind, key_id; + unsigned char *pdata; + uint32_t remain; + + if (!instance || !datawriter_crypto || !datareader_crypto || sending_participant_crypto == 0 || + !secure_submessage_category || !encoded_rtps_submessage || encoded_rtps_submessage->_length == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "preprocess_secure_submsg: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + pdata = encoded_rtps_submessage->_buffer; + remain = encoded_rtps_submessage->_length; + + if (!read_submsg_header(&submsg, &pdata, &remain)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "preprocess_secure_submsg: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + if (submsg.id != SMID_SEC_PREFIX_KIND) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "preprocess_secure_submsg: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + if (!read_crypto_header(&cheader, &pdata, &remain)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "preprocess_secure_submsg: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + transform_kind = CRYPTO_TRANSFORM_KIND(cheader.transform_identifier.transformation_kind); + key_id = CRYPTO_TRANSFORM_ID(cheader.transform_identifier.transformation_key_id); + + if (!transform_kind_valid(transform_kind)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "preprocess_secure_submsg: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + /* Lookup the end point information associated with the transform id */ + result = crypto_factory_get_endpoint_relation( + factory, receiving_participant_crypto, sending_participant_crypto, + key_id, &remote_handle, &local_handle, secure_submessage_category, ex); + + if (result) + { + if (*secure_submessage_category == DDS_SECURITY_DATAWRITER_SUBMESSAGE) + { + *datawriter_crypto = (DDS_Security_DatawriterCryptoHandle)remote_handle; + *datareader_crypto = (DDS_Security_DatareaderCryptoHandle)local_handle; + } + else + { + *datareader_crypto = (DDS_Security_DatareaderCryptoHandle)remote_handle; + *datawriter_crypto = (DDS_Security_DatawriterCryptoHandle)local_handle; + } + } + + return result; +} + +static DDS_Security_boolean +decode_datawriter_submessage( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_submsg, + const DDS_Security_OctetSeq *encoded_submsg, + const DDS_Security_DatareaderCryptoHandle reader_crypto, + const DDS_Security_DatawriterCryptoHandle writer_crypto, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + static const char *context = "decode_datawriter_submessage"; + dds_security_crypto_key_factory *factory; + uint32_t transform_kind, transform_id; + master_key_material *writer_master_key; + DDS_Security_ProtectionKind protection_kind; + remote_session_info remote_session; + struct submsg_header prefix; + struct crypto_header header; + struct submsg_header postfix; + struct submsg_header body; + struct crypto_footer *footer; + struct crypto_contents_ref contents; + + /* check arguments */ + if (!instance || writer_crypto == 0 || reader_crypto == 0 || !encoded_submsg || + encoded_submsg->_length == 0 || !encoded_submsg->_buffer || !plain_submsg) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datawriter_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + memset(plain_submsg, 0, sizeof(*plain_submsg)); + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + /* split the encoded submessage in the corresponding parts */ + if (!split_encoded_submessage(encoded_submsg, &prefix, &body, &postfix, &header, &contents, &footer)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datawriter_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + transform_kind = CRYPTO_TRANSFORM_KIND(header.transform_identifier.transformation_kind); + transform_id = CRYPTO_TRANSFORM_ID(header.transform_identifier.transformation_key_id); + + /* Retrieve key material from sending_datawriter_crypto from factory */ + if (!crypto_factory_get_remote_writer_key_material(factory, reader_crypto, writer_crypto, transform_id, &writer_master_key, &protection_kind, NULL, ex)) + goto fail_invalid_arg; + + if (has_origin_authentication(protection_kind)) + { + if (!check_reader_specific_mac(&header, footer, writer_master_key, context, ex)) + goto fail_reader_mac; + } + + /* calculate the session key */ + if (!initialize_remote_session_info(&remote_session, &header, writer_master_key->master_salt, writer_master_key->master_sender_key, writer_master_key->transformation_kind, ex)) + goto fail_decrypt; + + if (is_encryption_required(transform_kind)) + { + if (!is_encryption_expected(protection_kind)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datawriter_submessage: submessage is encrypted, which is unexpected (%d vs %d)", + (int)transform_kind, (int)protection_kind); + goto fail_decrypt; + } + /* When the CryptoHeader indicates that encryption is performed then decrypt the submessage body */ + /* check if the body is a SEC_BODY submessage */ + if (body.id != SMID_SEC_BODY_KIND) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datawriter_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_decrypt; + } + + plain_submsg->_buffer = DDS_Security_OctetSeq_allocbuf(contents._length); + plain_submsg->_length = plain_submsg->_maximum = contents._length; + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, contents._data, contents._length, NULL, 0, + plain_submsg->_buffer, &plain_submsg->_length, &footer->common_mac, ex)) + { + goto fail_decrypt; + } + } + else if (is_authentication_required(transform_kind)) + { + if (!is_authentication_expected(protection_kind)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datawriter_submessage: submessage is signed, which is unexpected"); + goto fail_decrypt; + } + /* When the CryptoHeader indicates that authentication is performed then calculate the HMAC */ + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, NULL, 0, contents._data, contents._length, NULL, 0, &footer->common_mac, ex)) + goto fail_decrypt; + plain_submsg->_buffer = DDS_Security_OctetSeq_allocbuf(contents._length); + plain_submsg->_length = plain_submsg->_maximum = contents._length; + memcpy(plain_submsg->_buffer, contents._data, contents._length); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_CODE, 0, + "decode_serialized_payload: " DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_MESSAGE); + goto fail_decrypt; + } + + ddsrt_free(footer); + CRYPTO_OBJECT_RELEASE(writer_master_key); + return true; + + +fail_decrypt: + DDS_Security_OctetSeq_deinit(plain_submsg); +fail_reader_mac: + CRYPTO_OBJECT_RELEASE(writer_master_key); +fail_invalid_arg: + ddsrt_free(footer); + return false; +} + +static DDS_Security_boolean +decode_datareader_submessage( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_submsg, + const DDS_Security_OctetSeq *encoded_submsg, + const DDS_Security_DatawriterCryptoHandle writer_crypto, + const DDS_Security_DatareaderCryptoHandle reader_crypto, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + static const char *context = "decode_datareader_submessage"; + dds_security_crypto_key_factory *factory; + uint32_t transform_kind, transform_id; + master_key_material *reader_master_key; + DDS_Security_ProtectionKind protection_kind; + remote_session_info remote_session; + struct submsg_header prefix; + struct crypto_header header; + struct submsg_header postfix; + struct submsg_header body; + struct crypto_footer *footer; + struct crypto_contents_ref contents; + + /* check arguments */ + if (!instance || writer_crypto == 0 || reader_crypto == 0 || !encoded_submsg || + encoded_submsg->_length == 0 || !encoded_submsg->_buffer || !plain_submsg) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datareader_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + memset(plain_submsg, 0, sizeof(*plain_submsg)); + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + /* split the encoded submessage in the corresponding parts */ + if (!split_encoded_submessage(encoded_submsg, &prefix, &body, &postfix, &header, &contents, &footer)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datareader_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + transform_kind = CRYPTO_TRANSFORM_KIND(header.transform_identifier.transformation_kind); + transform_id = CRYPTO_TRANSFORM_ID(header.transform_identifier.transformation_key_id); + + /* Retrieve key material from sending_datareader_crypto from factory */ + if (!crypto_factory_get_remote_reader_key_material(factory, writer_crypto, reader_crypto, transform_id, &reader_master_key, &protection_kind, ex)) + goto fail_invalid_arg; + + if (has_origin_authentication(protection_kind)) + { + if (!check_reader_specific_mac(&header, footer, reader_master_key, context, ex)) + goto fail_reader_mac; + } + + /* calculate the session key */ + if (!initialize_remote_session_info(&remote_session, &header, reader_master_key->master_salt, reader_master_key->master_sender_key, reader_master_key->transformation_kind, ex)) + goto fail_decrypt; + + if (is_encryption_required(transform_kind)) + { + if (!is_encryption_expected(protection_kind)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datareader_submessage: submessage is encrypted, which is unexpected"); + goto fail_decrypt; + } + /* When the CryptoHeader indicates that encryption is performed then decrypt the submessage body */ + /* check if the body is a SEC_BODY submessage */ + if (body.id != SMID_SEC_BODY_KIND) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datareader_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_decrypt; + } + + plain_submsg->_buffer = DDS_Security_OctetSeq_allocbuf(contents._length); + plain_submsg->_length = plain_submsg->_maximum = contents._length; + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, contents._data, contents._length, NULL, 0, + plain_submsg->_buffer, &plain_submsg->_length, &footer->common_mac, ex)) + { + goto fail_decrypt; + } + } + else if (is_authentication_required(transform_kind)) + { + if (!is_authentication_expected(protection_kind)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datareader_submessage: submessage is signed, which is unexpected"); + goto fail_decrypt; + } + /* When the CryptoHeader indicates that authentication is performed then calculate the HMAC */ + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, NULL, 0, contents._data, contents._length, NULL, 0, &footer->common_mac, ex)) + goto fail_decrypt; + plain_submsg->_buffer = DDS_Security_OctetSeq_allocbuf(contents._length); + plain_submsg->_length = plain_submsg->_maximum = contents._length; + memcpy(plain_submsg->_buffer, contents._data, contents._length); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_CODE, 0, + "decode_datareader_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_MESSAGE); + goto fail_decrypt; + } + ddsrt_free(footer); + CRYPTO_OBJECT_RELEASE(reader_master_key); + return true; + +fail_decrypt: + DDS_Security_OctetSeq_deinit(plain_submsg); +fail_reader_mac: + CRYPTO_OBJECT_RELEASE(reader_master_key); +fail_invalid_arg: + ddsrt_free(footer); + return false; +} + +static DDS_Security_boolean +decode_serialized_payload( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_buffer, + const DDS_Security_OctetSeq *encoded_buffer, + const DDS_Security_OctetSeq *inline_qos, + const DDS_Security_DatareaderCryptoHandle reader_id, + const DDS_Security_DatawriterCryptoHandle writer_id, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_BasicProtectionKind basic_protection_kind; + master_key_material *writer_master_key; + remote_session_info remote_session; + uint32_t transform_kind, transform_id; + struct crypto_header header; + unsigned char *payload_ptr; + uint32_t payload_len; + struct crypto_footer *footer = NULL; + + DDSRT_UNUSED_ARG(inline_qos); + + if (!instance || !encoded_buffer || !plain_buffer || reader_id == 0 || writer_id == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_serialized_payload: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_inv_arg; + } + + if ((plain_buffer->_buffer != NULL) || (plain_buffer->_length != 0)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_serialized_payload: given plain_buffer not empty"); + goto fail_inv_arg; + } + + /* Retrieve key material from sending_datawriter_crypto from factory */ + factory = cryptography_get_crypto_key_factory(impl->crypto); + + /* determine CryptoHeader, CryptoContent and CryptoFooter*/ + if (!split_encoded_serialized_payload(encoded_buffer, &header, &payload_ptr, &payload_len, &footer)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_serialized_payload: Invalid syntax of encoded payload"); + goto fail_split; + } + + if (footer->receiver_specific_macs._length != 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_serialized_payload: Received specific_macs"); + goto fail_prepare; + } + + transform_kind = CRYPTO_TRANSFORM_KIND(header.transform_identifier.transformation_kind); + transform_id = CRYPTO_TRANSFORM_ID(header.transform_identifier.transformation_key_id); + + if (!crypto_factory_get_remote_writer_key_material(factory, reader_id, writer_id, transform_id, &writer_master_key, NULL, &basic_protection_kind, ex)) + goto fail_prepare; + + /* calculate the session key */ + if (!initialize_remote_session_info(&remote_session, &header, writer_master_key->master_salt, writer_master_key->master_sender_key, writer_master_key->transformation_kind, ex)) + goto fail_decrypt; + + /* + * Depending on encryption, the payload part between Header and Footer is + * either CryptoContent or the original plain payload. + * See spec: 9.5.3.3.4.4 Result from encode_serialized_payload + */ + if (is_encryption_required(transform_kind)) + { + struct crypto_contents_ref contents; + /* Is encryption expected? */ + if (basic_protection_kind != DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_serialized_payload: payload is encrypted, which is unexpected"); + goto fail_decrypt; + } + /* When encrypted, the content payload starts with a length: update contents. */ + if (read_crypto_contents(&contents, payload_ptr, payload_len)) + { + /* When the CryptoHeader indicates that encryption is performed then decrypt the payload */ + plain_buffer->_buffer = DDS_Security_OctetSeq_allocbuf(contents._length); + plain_buffer->_length = plain_buffer->_maximum = contents._length; + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, contents._data, contents._length, NULL, 0, plain_buffer->_buffer, &plain_buffer->_length, &footer->common_mac, ex)) + { + goto fail_decrypt; + } + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_CODE, 0, + "decode_serialized_payload: invalid payload format"); + goto fail_decrypt; + } + } + else if (is_authentication_required(transform_kind)) + { + /* Is signing expected? */ + if (basic_protection_kind != DDS_SECURITY_BASICPROTECTION_KIND_SIGN) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_serialized_payload: payload is signed, which is unexpected"); + goto fail_decrypt; + } + /* When the CryptoHeader indicates that authentication is performed then calculate the HMAC */ + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, NULL, 0, payload_ptr, payload_len, NULL, 0, &footer->common_mac, ex)) + { + goto fail_decrypt; + } + plain_buffer->_buffer = DDS_Security_OctetSeq_allocbuf(payload_len); + plain_buffer->_length = plain_buffer->_maximum = payload_len; + memcpy(plain_buffer->_buffer, payload_ptr, payload_len); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_CODE, 0, + "decode_serialized_payload: " DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_MESSAGE); + goto fail_decrypt; + } + ddsrt_free(footer); + CRYPTO_OBJECT_RELEASE(writer_master_key); + return true; + +fail_decrypt: + DDS_Security_OctetSeq_deinit(plain_buffer); + CRYPTO_OBJECT_RELEASE(writer_master_key); +fail_prepare: + ddsrt_free(footer); +fail_split: +fail_inv_arg: + return false; +} + +dds_security_crypto_transform * +dds_security_crypto_transform__alloc( + const dds_security_cryptography *crypto) +{ + dds_security_crypto_transform_impl *instance; + instance = (dds_security_crypto_transform_impl *)ddsrt_malloc( + sizeof(dds_security_crypto_transform_impl)); + + instance->crypto = crypto; + instance->base.encode_datawriter_submessage = &encode_datawriter_submessage; + instance->base.encode_datareader_submessage = &encode_datareader_submessage; + instance->base.encode_rtps_message = &encode_rtps_message; + instance->base.encode_serialized_payload = &encode_serialized_payload; + instance->base.decode_rtps_message = &decode_rtps_message; + instance->base.preprocess_secure_submsg = &preprocess_secure_submsg; + instance->base.decode_datawriter_submessage = &decode_datawriter_submessage; + instance->base.decode_datareader_submessage = &decode_datareader_submessage; + instance->base.decode_serialized_payload = &decode_serialized_payload; + + OpenSSL_add_all_algorithms(); + OpenSSL_add_all_ciphers(); + OpenSSL_add_all_digests(); + ERR_load_BIO_strings(); + ERR_load_crypto_strings(); + + return (dds_security_crypto_transform *)instance; +} + +void dds_security_crypto_transform__dealloc( + dds_security_crypto_transform *instance) +{ + RAND_cleanup(); + EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); + REMOVE_THREAD_STATE(); + ERR_free_strings(); + + ddsrt_free((dds_security_crypto_transform_impl *)instance); +} diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_transform.h b/src/security/builtin_plugins/cryptographic/src/crypto_transform.h new file mode 100644 index 0000000..7a73075 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_transform.h @@ -0,0 +1,28 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTO_TRANSFORM_H +#define CRYPTO_TRANSFORM_H + +#include "dds/security/dds_security_api.h" + +/** + * @brief Allocation function for implementer structure (with internal variables) transparently. + */ +dds_security_crypto_transform * +dds_security_crypto_transform__alloc( + const dds_security_cryptography *crypto); + +void +dds_security_crypto_transform__dealloc( + dds_security_crypto_transform *instance); + +#endif /* CRYPTO_TRANSFORM_H */ diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_utils.c b/src/security/builtin_plugins/cryptographic/src/crypto_utils.c new file mode 100644 index 0000000..36e9f75 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_utils.c @@ -0,0 +1,153 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include +#include +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "crypto_defs.h" +#include "crypto_utils.h" + +char *crypto_openssl_error_message(void) +{ + BIO *bio = BIO_new(BIO_s_mem()); + char *msg; + char *buf = NULL; + size_t len; + + if (!bio) + return ddsrt_strdup ("BIO_new failed"); + + ERR_print_errors(bio); + len = (size_t) BIO_get_mem_data(bio, &buf); + msg = ddsrt_malloc(len + 1); + memset(msg, 0, len + 1); + memcpy(msg, buf, len); + BIO_free(bio); + return msg; +} + +static bool +crypto_calculate_key_impl( + const char *prefix, + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + DDS_Security_SecurityException *ex) +{ + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(transformation_kind); + uint32_t id = ddsrt_toBE4u(session_id); + size_t sz = strlen(prefix) + key_bytes + sizeof(id); + unsigned char *buffer = ddsrt_malloc (sz); + unsigned char md[EVP_MAX_MD_SIZE]; + + memcpy(buffer, prefix, strlen(prefix)); + memcpy(&buffer[strlen(prefix)], master_salt, key_bytes); + memcpy(&buffer[strlen(prefix) + key_bytes], &id, sizeof(id)); + if (HMAC(EVP_sha256(), master_key, (int)key_bytes, buffer, sz, md, NULL) == NULL) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "HMAC failed: "); + ddsrt_free (buffer); + return false; + } + memcpy (session_key->data, md, key_bytes); + ddsrt_free (buffer); + return true; +} + +bool +crypto_calculate_session_key( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + DDS_Security_SecurityException *ex) +{ + return crypto_calculate_key_impl("SessionKey", session_key, session_id, master_salt, master_key, transformation_kind, ex); +} + +bool +crypto_calculate_receiver_specific_key( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + DDS_Security_SecurityException *ex) +{ + return crypto_calculate_key_impl("SessionReceiverKey", session_key, session_id, master_salt, master_key, transformation_kind, ex); +} + +uint32_t +crypto_get_key_size( + DDS_Security_CryptoTransformKind_Enum kind) +{ + switch (kind) + { + case CRYPTO_TRANSFORMATION_KIND_AES128_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES128_GCM: + return 128; + case CRYPTO_TRANSFORMATION_KIND_AES256_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES256_GCM: + return 256; + default: + return 0; + } +} + +uint32_t +crypto_get_random_uint32(void) +{ + uint32_t val; + RAND_bytes((unsigned char *)&val, sizeof(uint32_t)); + return val; +} + +uint64_t +crypto_get_random_uint64(void) +{ + uint64_t val; + RAND_bytes((unsigned char *)&val, sizeof(uint64_t)); + return val; +} + +unsigned char * +crypto_hmac256( + const unsigned char *key, + uint32_t key_size, + const unsigned char *data, + uint32_t data_size, + DDS_Security_SecurityException *ex) +{ + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned char *result; + + assert (key_size <= INT32_MAX); + if (HMAC(EVP_sha256(), key, (int) key_size, data, data_size, md, NULL) == NULL) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, 0, "Failed to init hashing context: "); + return NULL; + } + result = ddsrt_malloc(key_size); + memcpy (result, md, key_size); + return result; +} diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_utils.h b/src/security/builtin_plugins/cryptographic/src/crypto_utils.h new file mode 100644 index 0000000..b9ef5b9 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_utils.h @@ -0,0 +1,95 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTO_UTILS_H +#define CRYPTO_UTILS_H + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/types.h" +#include "dds/security/export.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_types.h" +#include "crypto_defs.h" + +#define CRYPTO_TRANSFORM_KIND(k) ddsrt_fromBE4u((*(uint32_t *)&((k)[0]))) +#define CRYPTO_TRANSFORM_ID(k) ddsrt_fromBE4u((*(uint32_t *)&((k)[0]))) +#define CRYPTO_KEY_SIZE_BYTES(kind) (crypto_get_key_size(kind) >> 3) + +#define ALIGN4(x) (((x) + 3) & (uint32_t)(-4)) + +struct init_vector_suffix +{ + uint32_t high; + uint32_t low; +}; + +/** + * Return a string that contains an openssl error description + * When a openssl function returns an error this function can be + * used to retrieve a descriptive error string. + * Note that the returned string should be freed. + */ +char *crypto_openssl_error_message(void); + +/** + * @param[in,out] session_key Session key + * @param[in] session_id Session Id + * @param[in] master_salt Master salt + * @param[in] master_key Master key + * @param[in] transformation_kind Transformation kind + * @param[in,out] ex Security exception + */ +SECURITY_EXPORT bool crypto_calculate_session_key( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + DDS_Security_SecurityException *ex); + +/** + * @param[in,out] session_key Session key + * @param[in] session_id Session Id + * @param[in] master_salt Master salt + * @param[in] master_key Master key + * @param[in] transformation_kind Transformation kind + * @param[in,out] ex Security exception + */ +SECURITY_EXPORT bool crypto_calculate_receiver_specific_key( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + DDS_Security_SecurityException *ex); + +SECURITY_EXPORT uint32_t crypto_get_key_size(DDS_Security_CryptoTransformKind_Enum kind); +SECURITY_EXPORT uint32_t crypto_get_random_uint32(void); +SECURITY_EXPORT uint64_t crypto_get_random_uint64(void); + +/** + * @brief Compute a HMAC256 on the provided data. + * + * @param[in] key The key used to compute the HMAC256 result + * @param[in] key_size The size of the key (128 or 256 bits) + * @param[in] data The data on which the HMAC is computed + * @param[in] data_size The size of the data + * @param[in,out] ex Security exception + */ +SECURITY_EXPORT unsigned char *crypto_hmac256( + const unsigned char *key, + uint32_t key_size, + const unsigned char *data, + uint32_t data_size, + DDS_Security_SecurityException *ex); + +#endif /* CRYPTO_UTILS_H */ diff --git a/src/security/builtin_plugins/cryptographic/src/cryptography.c b/src/security/builtin_plugins/cryptographic/src/cryptography.c new file mode 100644 index 0000000..a8aee67 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/cryptography.c @@ -0,0 +1,98 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "cryptography.h" +#include "crypto_key_exchange.h" +#include "crypto_key_factory.h" +#include "crypto_transform.h" + +/** + * Implementation structure for storing encapsulated members of the instance + * while giving only the interface definition to user + */ + +typedef struct dds_security_cryptography_impl { + dds_security_cryptography base; +} dds_security_cryptography_impl; + +dds_security_crypto_key_factory *cryptography_get_crypto_key_factory (const struct dds_security_cryptography *crypto) +{ + const dds_security_cryptography_impl *instance = (dds_security_cryptography_impl *) crypto; + return instance->base.crypto_key_factory; +} + +dds_security_crypto_key_exchange *cryptography_get_crypto_key_exchange (const struct dds_security_cryptography *crypto) +{ + const dds_security_cryptography_impl *instance = (dds_security_cryptography_impl *) crypto; + return instance->base.crypto_key_exchange; +} + +dds_security_crypto_transform *cryptography_get_crypto_transform (const struct dds_security_cryptography *crypto) +{ + const dds_security_cryptography_impl *instance = (dds_security_cryptography_impl *) crypto; + return instance->base.crypto_transform; +} + + +int init_crypto (const char *argument, void **context) +{ + dds_security_cryptography_impl *cryptography; + dds_security_crypto_key_exchange *crypto_key_exchange; + dds_security_crypto_key_factory *crypto_key_factory; + dds_security_crypto_transform *crypto_transform; + + DDSRT_UNUSED_ARG (argument); + + /* allocate new instance */ + cryptography = ddsrt_malloc (sizeof(*cryptography)); + + /* assign the sub components */ + crypto_key_exchange = dds_security_crypto_key_exchange__alloc ((dds_security_cryptography *)cryptography); + if (!crypto_key_exchange) goto err_exchange; + + crypto_key_factory = dds_security_crypto_key_factory__alloc ((dds_security_cryptography *)cryptography); + if (!crypto_key_factory) goto err_factory; + + crypto_transform = dds_security_crypto_transform__alloc ((dds_security_cryptography *)cryptography); + if (!crypto_transform) goto err_transform; + + cryptography->base.crypto_key_exchange = crypto_key_exchange; + cryptography->base.crypto_key_factory = crypto_key_factory; + cryptography->base.crypto_transform = crypto_transform; + + /* return the instance */ + *context = cryptography; + return DDS_SECURITY_SUCCESS; + +err_transform: + dds_security_crypto_key_factory__dealloc (crypto_key_factory); +err_factory: + dds_security_crypto_key_exchange__dealloc (crypto_key_exchange); +err_exchange: + ddsrt_free (cryptography); + *context = NULL; + return DDS_SECURITY_FAILED; +} + +int finalize_crypto (void *instance) +{ + dds_security_cryptography_impl* instance_impl = (dds_security_cryptography_impl*) instance; + /* deallocate components */ + dds_security_crypto_key_exchange__dealloc (instance_impl->base.crypto_key_exchange); + dds_security_crypto_key_factory__dealloc (instance_impl->base.crypto_key_factory); + dds_security_crypto_transform__dealloc (instance_impl->base.crypto_transform); + /* deallocate cryptography */ + ddsrt_free (instance_impl); + return DDS_SECURITY_SUCCESS; +} diff --git a/src/security/builtin_plugins/cryptographic/src/cryptography.h b/src/security/builtin_plugins/cryptographic/src/cryptography.h new file mode 100644 index 0000000..eb114d4 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/cryptography.h @@ -0,0 +1,33 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTOGRAPHY_H +#define CRYPTOGRAPHY_H + +#include "dds/security/dds_security_api.h" +#include "dds/security/export.h" + +SECURITY_EXPORT int init_crypto(const char *argument, void **context); +SECURITY_EXPORT int finalize_crypto(void *instance); + +dds_security_crypto_key_factory * +cryptography_get_crypto_key_factory( + const dds_security_cryptography *crypto); + +dds_security_crypto_key_exchange * +cryptography_get_crypto_key_exchange( + const dds_security_cryptography *crypto); + +dds_security_crypto_transform * +cryptography_get_crypto_transform( + const dds_security_cryptography *crypto); + +#endif /* CRYPTOGRAPHY_H */ diff --git a/src/security/builtin_plugins/tests/CMakeLists.txt b/src/security/builtin_plugins/tests/CMakeLists.txt index 7290ca4..226255f 100644 --- a/src/security/builtin_plugins/tests/CMakeLists.txt +++ b/src/security/builtin_plugins/tests/CMakeLists.txt @@ -10,42 +10,63 @@ # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause # include(CUnit) +find_package(OpenSSL) set(security_auth_test_sources - "validate_begin_handshake_reply/src/validate_begin_handshake_reply_utests.c" + "common/src/loader.c" + "common/src/handshake_helper.c" "get_authenticated_peer_credential_token/src/get_authenticated_peer_credential_token_utests.c" + "process_handshake/src/process_handshake_utests.c" + "validate_begin_handshake_reply/src/validate_begin_handshake_reply_utests.c" + "validate_begin_handshake_request/src/validate_begin_handshake_request_utests.c" "validate_local_identity/src/validate_local_identity_utests.c" "validate_remote_identity/src/validate_remote_identity_utests.c" - "validate_begin_handshake_request/src/validate_begin_handshake_request_utests.c" - "process_handshake/src/process_handshake_utests.c" - "common/src/handshake_helper.c" - "common/src/loader.c") +) -add_cunit_executable(cunit_security_plugins ${security_auth_test_sources}) -target_include_directories( - cunit_security_plugins PRIVATE - "$" - "$>" - "$>" - "$>" - "$" - "$" - ) +set(security_crypto_test_sources + "common/src/crypto_helper.c" + "create_local_datareader_crypto_tokens/src/create_local_datareader_crypto_tokens_utests.c" + "create_local_datawriter_crypto_tokens/src/create_local_datawriter_crypto_tokens_utests.c" + "create_local_participant_crypto_tokens/src/create_local_participant_crypto_tokens_utests.c" + "decode_datareader_submessage/src/decode_datareader_submessage_utests.c" + "decode_datawriter_submessage/src/decode_datawriter_submessage_utests.c" + "decode_rtps_message/src/decode_rtps_message_utests.c" + "decode_serialized_payload/src/decode_serialized_payload_utests.c" + "encode_datareader_submessage/src/encode_datareader_submessage_utests.c" + "encode_datawriter_submessage/src/encode_datawriter_submessage_utests.c" + "encode_rtps_message/src/encode_rtps_message_utests.c" + "encode_serialized_payload/src/encode_serialized_payload_utests.c" + "preprocess_secure_submsg/src/preprocess_secure_submsg_utests.c" + "register_local_datareader/src/register_local_datareader_utests.c" + "register_local_datawriter/src/register_local_datawriter_utests.c" + "register_local_participant/src/register_local_participant_utests.c" + "register_matched_remote_datareader/src/register_matched_remote_datareader_utests.c" + "register_matched_remote_datawriter/src/register_matched_remote_datawriter_utests.c" + "register_matched_remote_participant/src/register_matched_remote_participant_utests.c" + "set_remote_datareader_crypto_tokens/src/set_remote_datareader_crypto_tokens_utests.c" + "set_remote_datawriter_crypto_tokens/src/set_remote_datawriter_crypto_tokens_utests.c" + "set_remote_participant_crypto_tokens/src/set_remote_participant_crypto_tokens_utests.c" +) - -target_link_libraries(cunit_security_plugins PRIVATE ddsc security_api) - - -find_package(OpenSSL ) +add_cunit_executable(cunit_security_plugins ${security_auth_test_sources} ${security_crypto_test_sources}) if(OPENSSL_FOUND) target_link_libraries(cunit_security_plugins PRIVATE OpenSSL::SSL) - else() message(FATAL_ERROR "To build without openssl support, set DDSC_ENABLE_OPENSSL to OFF") endif() +target_include_directories( + cunit_security_plugins PRIVATE + "$" + "$>" + "$>" + "$>" + "$" + "$" +) + +target_link_libraries(cunit_security_plugins PRIVATE ddsc security_api dds_security_crypto) + set(CUnit_builtin_plugins_tests_dir "${CMAKE_CURRENT_LIST_DIR}") configure_file("config_env.h.in" "config_env.h") - - diff --git a/src/security/builtin_plugins/tests/common/src/crypto_helper.c b/src/security/builtin_plugins/tests/common/src/crypto_helper.c new file mode 100644 index 0000000..8497f80 --- /dev/null +++ b/src/security/builtin_plugins/tests/common/src/crypto_helper.c @@ -0,0 +1,112 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "crypto_helper.h" +#include "crypto_utils.h" + + +static bool +crypto_calculate_session_key_impl_test( + const char *prefix, + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + bool result = true; + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(transformation_kind); + uint32_t id = ddsrt_toBE4u(session_id); + size_t sz = strlen(prefix) + key_bytes + sizeof(id); + unsigned char *buffer = ddsrt_malloc (sz); + memcpy(buffer, prefix, strlen(prefix)); + memcpy(&buffer[strlen(prefix)], master_salt, key_bytes); + memcpy(&buffer[strlen(prefix) + key_bytes], &id, sizeof(id)); + if (HMAC(EVP_sha256(), master_key, (int)key_bytes, buffer, sz, session_key->data, NULL) == NULL) + { + ERR_print_errors_fp(stderr); + result = false; + } + ddsrt_free (buffer); + return result; +} + +bool +crypto_calculate_session_key_test( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + return crypto_calculate_session_key_impl_test ("SessionKey", session_key, session_id, master_salt, master_key, transformation_kind); +} + +bool calculate_receiver_specific_key_test( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + return crypto_calculate_session_key_impl_test ("SessionReceiverKey", session_key, session_id, master_salt, master_key, transformation_kind); +} + +int master_salt_not_empty(master_key_material *keymat) +{ + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(keymat->transformation_kind); + for (uint32_t i = 0; i < key_bytes; i++) + { + if (keymat->master_salt[i]) + return 1; + } + return 0; +} + +int master_key_not_empty(master_key_material *keymat) +{ + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(keymat->transformation_kind); + for (uint32_t i = 0; i < key_bytes; i++) + { + if (keymat->master_sender_key[i]) + return 1; + } + return 0; +} + +int master_receiver_specific_key_not_empty(master_key_material *keymat) +{ + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(keymat->transformation_kind); + for (uint32_t i = 0; i < key_bytes; i++) + { + if (keymat->master_receiver_specific_key[i]) + return 1; + } + return 0; +} diff --git a/src/security/builtin_plugins/tests/common/src/crypto_helper.h b/src/security/builtin_plugins/tests/common/src/crypto_helper.h new file mode 100644 index 0000000..ad64fcb --- /dev/null +++ b/src/security/builtin_plugins/tests/common/src/crypto_helper.h @@ -0,0 +1,38 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef DDS_SECURITY_BUITIN_TEST_CRYPTO_HELPER_H +#define DDS_SECURITY_BUITIN_TEST_CRYPTO_HELPER_H + +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "crypto_objects.h" + +bool +crypto_calculate_session_key_test( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind); + +bool calculate_receiver_specific_key_test( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind); + +int master_salt_not_empty(master_key_material *keymat); +int master_key_not_empty(master_key_material *keymat); +int master_receiver_specific_key_not_empty(master_key_material *keymat); + +#endif /* DDS_SECURITY_BUITIN_TEST_CRYPTO_HELPER_H */ \ No newline at end of file diff --git a/src/security/builtin_plugins/tests/create_local_datareader_crypto_tokens/src/create_local_datareader_crypto_tokens_utests.c b/src/security/builtin_plugins/tests/create_local_datareader_crypto_tokens/src/create_local_datareader_crypto_tokens_utests.c new file mode 100644 index 0000000..be6a188 --- /dev/null +++ b/src/security/builtin_plugins/tests/create_local_datareader_crypto_tokens/src/create_local_datareader_crypto_tokens_utests.c @@ -0,0 +1,501 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +#define CRYPTO_TRANSFORM_KIND(k) (*(uint32_t *)&((k)[0])) +#define CRYPTO_TRANSFORM_ID(k) (*(uint32_t *)&((k)[0])) + +static const char *CRYPTO_TOKEN_CLASS_ID = "DDS:Crypto:AES_GCM_GMAC"; +static const char *CRYPTO_TOKEN_PROPERTY_NAME = "dds.cryp.keymat"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_particpant_crypto = 0; +static DDS_Security_ParticipantCryptoHandle remote_particpant_crypto = 0; +static DDS_Security_DatawriterCryptoHandle local_reader_crypto = 0; +static DDS_Security_DatareaderCryptoHandle remote_writer_crypto = 0; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_endpoint_security_attributes(DDS_Security_EndpointSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + local_particpant_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_particpant_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_particpant_crypto ? 0 : -1; +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_particpant_crypto = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_particpant_crypto, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_particpant_crypto == 0) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_particpant_crypto ? 0 : -1; +} + +static int register_local_datareader(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + memset(&datareader_properties, 0, sizeof(datareader_properties)); + + prepare_endpoint_security_attributes(&datareader_security_attributes); + + local_reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_particpant_crypto, + &datareader_properties, + &datareader_security_attributes, + &exception); + + if (local_reader_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_reader_crypto ? 0 : -1; +} + +static int register_remote_datawriter(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + remote_writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_crypto, + remote_particpant_crypto, + shared_secret_handle, + &exception); + + if (remote_writer_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_writer_crypto ? 0 : -1; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void suite_create_local_datareader_crypto_tokens_init(void) +{ + allocate_shared_secret(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_local_datareader(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_datawriter(), 0); +} + +static void suite_create_local_datareader_crypto_tokens_fini(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + if (remote_writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, remote_writer_crypto, &exception); + reset_exception(&exception); + } + if (local_reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_reader_crypto, &exception); + reset_exception(&exception); + } + if (remote_particpant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_particpant_crypto, &exception); + reset_exception(&exception); + } + if (local_particpant_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_particpant_crypto, &exception); + reset_exception(&exception); + } + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static bool data_not_empty(unsigned char *data, uint32_t length) +{ + uint32_t i; + for (i = 0; i < length; i++) + { + if (data[i]) + return true; + } + return false; +} + +static bool check_key_material(DDS_Security_OctetSeq *data) +{ + bool status = true; + DDS_Security_Deserializer deserializer; + DDS_Security_KeyMaterial_AES_GCM_GMAC key_mat; + + deserializer = DDS_Security_Deserializer_new(data->_buffer, data->_length); + if (DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC(deserializer, &key_mat)) + { + if (CRYPTO_TRANSFORM_KIND(key_mat.transformation_kind) == CRYPTO_TRANSFORMATION_KIND_AES256_GCM) + { + printf("check_key_material: incorrect transformation_kind\n"); + status = false; + } + else if (CRYPTO_TRANSFORM_ID(key_mat.sender_key_id) == 0) + { + printf("check_key_material: incorrect sender_key_id\n"); + status = false; + } + else if (key_mat.master_salt._length != DDS_SECURITY_MASTER_SALT_SIZE_256) + { + printf("check_key_material: incorrect master_salt\n"); + status = false; + } + else if (!key_mat.master_salt._buffer) + { + printf("check_key_material: incorrect master_salt\n"); + status = false; + } + else if (!data_not_empty(key_mat.master_salt._buffer, key_mat.master_salt._length)) + { + printf("check_key_material: incorrect master_salt\n"); + status = false; + } + else if (key_mat.master_sender_key._length != DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256) + { + printf("check_key_material: incorrect master_sender_key\n"); + status = false; + } + else if (!key_mat.master_salt._buffer) + { + printf("check_key_material: incorrect master_sender_key\n"); + status = false; + } + else if (!data_not_empty(key_mat.master_sender_key._buffer, key_mat.master_sender_key._length)) + { + printf("check_key_material: incorrect master_sender_key\n"); + status = false; + } + } + else + { + status = false; + } + + DDS_Security_Deserializer_free(deserializer); + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&key_mat); + + return status; +} + +static bool check_token_validity(const DDS_Security_DatawriterCryptoTokenSeq *tokens) +{ + bool status = true; + uint32_t i; + + if (tokens->_length != 1 || tokens->_buffer == NULL) + { + status = false; + } + + for (i = 0; status && (i < tokens->_length); i++) + { + status = (tokens->_buffer[i].class_id != NULL) && + (strcmp(CRYPTO_TOKEN_CLASS_ID, tokens->_buffer[i].class_id) == 0) && + (tokens->_buffer[i].binary_properties._length == 1) && + (tokens->_buffer[i].binary_properties._buffer != NULL) && + (tokens->_buffer[i].binary_properties._buffer[0].name != NULL) && + (strcmp(CRYPTO_TOKEN_PROPERTY_NAME, tokens->_buffer[i].binary_properties._buffer[0].name) == 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._length > 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._buffer != NULL); + + if (status) + { + status = check_key_material(&tokens->_buffer[i].binary_properties._buffer[0].value); + } + } + + return status; +} + +CU_Test(ddssec_builtin_create_local_datareader_crypto_tokens, happy_day, .init = suite_create_local_datareader_crypto_tokens_init, .fini = suite_create_local_datareader_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_datareader_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("create_local_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + CU_ASSERT(check_token_validity(&tokens)); + + result = crypto->crypto_key_exchange->return_crypto_tokens(crypto->crypto_key_exchange, &tokens, &exception); + + if (!result) + { + printf("return_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_create_local_datareader_crypto_tokens, invalid_args, .init = suite_create_local_datareader_crypto_tokens_init, .fini = suite_create_local_datareader_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_datareader_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + /* invalid token seq = NULL */ + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + NULL, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("create_local_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + 0, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("create_local_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid remote_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_reader_crypto, + 0, + &exception); + + if (!result) + { + printf("create_local_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + 1, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("create_local_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid remote_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_reader_crypto, + 1, + &exception); + + if (!result) + { + printf("create_local_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); +} diff --git a/src/security/builtin_plugins/tests/create_local_datawriter_crypto_tokens/src/create_local_datawriter_crypto_tokens_utests.c b/src/security/builtin_plugins/tests/create_local_datawriter_crypto_tokens/src/create_local_datawriter_crypto_tokens_utests.c new file mode 100644 index 0000000..0913528 --- /dev/null +++ b/src/security/builtin_plugins/tests/create_local_datawriter_crypto_tokens/src/create_local_datawriter_crypto_tokens_utests.c @@ -0,0 +1,505 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +#define CRYPTO_TRANSFORM_KIND(k) (*(uint32_t *)&((k)[0])) +#define CRYPTO_TRANSFORM_ID(k) (*(uint32_t *)&((k)[0])) + +static const char *CRYPTO_TOKEN_CLASS_ID = "DDS:Crypto:AES_GCM_GMAC"; +static const char *CRYPTO_TOKEN_PROPERTY_NAME = "dds.cryp.keymat"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_particpant_crypto = 0; +static DDS_Security_ParticipantCryptoHandle remote_particpant_crypto = 0; +static DDS_Security_DatawriterCryptoHandle local_writer_crypto = 0; +static DDS_Security_DatareaderCryptoHandle remote_reader_crypto = 0; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + local_particpant_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_particpant_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_particpant_crypto ? 0 : -1; +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_particpant_crypto = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_particpant_crypto, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_particpant_crypto == 0) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_particpant_crypto ? 0 : -1; +} + +static void prepare_endpoint_security_attributes(DDS_Security_EndpointSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; +} + +static int register_local_datawriter(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + prepare_endpoint_security_attributes(&datawriter_security_attributes); + datawriter_security_attributes.is_payload_protected = true; + datawriter_security_attributes.plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + + local_writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_particpant_crypto, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + if (local_writer_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_writer_crypto ? 0 : -1; +} + +static int register_remote_datareader(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + remote_reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_crypto, + remote_particpant_crypto, + shared_secret_handle, + true, + &exception); + + if (remote_reader_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_reader_crypto ? 0 : -1; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void suite_create_local_datawriter_crypto_tokens_init(void) +{ + allocate_shared_secret(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_local_datawriter(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_datareader(), 0); +} + +static void suite_create_local_datawriter_crypto_tokens_fini(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + if (remote_reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, remote_reader_crypto, &exception); + reset_exception(&exception); + } + if (local_writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, local_writer_crypto, &exception); + reset_exception(&exception); + } + if (remote_particpant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_particpant_crypto, &exception); + reset_exception(&exception); + } + if (local_particpant_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_particpant_crypto, &exception); + reset_exception(&exception); + } + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static bool data_not_empty(unsigned char *data, uint32_t length) +{ + uint32_t i; + for (i = 0; i < length; i++) + { + if (data[i]) + return true; + } + return false; +} + +static bool check_key_material(DDS_Security_OctetSeq *data) +{ + bool status = true; + DDS_Security_Deserializer deserializer; + DDS_Security_KeyMaterial_AES_GCM_GMAC key_mat; + + deserializer = DDS_Security_Deserializer_new(data->_buffer, data->_length); + if (DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC(deserializer, &key_mat)) + { + if (CRYPTO_TRANSFORM_KIND(key_mat.transformation_kind) == CRYPTO_TRANSFORMATION_KIND_AES256_GCM) + { + printf("check_key_material: incorrect transformation_kind\n"); + status = false; + } + else if (CRYPTO_TRANSFORM_ID(key_mat.sender_key_id) == 0) + { + printf("check_key_material: incorrect sender_key_id\n"); + status = false; + } + else if (key_mat.master_salt._length != DDS_SECURITY_MASTER_SALT_SIZE_256) + { + printf("check_key_material: incorrect master_salt\n"); + status = false; + } + else if (!key_mat.master_salt._buffer) + { + printf("check_key_material: incorrect master_salt\n"); + status = false; + } + else if (!data_not_empty(key_mat.master_salt._buffer, key_mat.master_salt._length)) + { + printf("check_key_material: incorrect master_salt\n"); + status = false; + } + else if (key_mat.master_sender_key._length != DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256) + { + printf("check_key_material: incorrect master_sender_key\n"); + status = false; + } + else if (!key_mat.master_salt._buffer) + { + printf("check_key_material: incorrect master_sender_key\n"); + status = false; + } + else if (!data_not_empty(key_mat.master_sender_key._buffer, key_mat.master_sender_key._length)) + { + printf("check_key_material: incorrect master_sender_key\n"); + status = false; + } + } + else + { + status = false; + } + + DDS_Security_Deserializer_free(deserializer); + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&key_mat); + + return status; +} + +static bool check_token_validity(const DDS_Security_DatawriterCryptoTokenSeq *tokens) +{ + bool status = true; + uint32_t i; + + if (tokens->_length != 2 || tokens->_buffer == NULL) + { + status = false; + } + + for (i = 0; status && (i < tokens->_length); i++) + { + status = (tokens->_buffer[i].class_id != NULL) && + (strcmp(CRYPTO_TOKEN_CLASS_ID, tokens->_buffer[i].class_id) == 0) && + (tokens->_buffer[i].binary_properties._length == 1) && + (tokens->_buffer[i].binary_properties._buffer != NULL) && + (tokens->_buffer[i].binary_properties._buffer[0].name != NULL) && + (strcmp(CRYPTO_TOKEN_PROPERTY_NAME, tokens->_buffer[i].binary_properties._buffer[0].name) == 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._length > 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._buffer != NULL); + + if (status) + { + status = check_key_material(&tokens->_buffer[i].binary_properties._buffer[0].value); + } + } + + return status; +} + +CU_Test(ddssec_builtin_create_local_datawriter_crypto_tokens, happy_day, .init = suite_create_local_datawriter_crypto_tokens_init, .fini = suite_create_local_datawriter_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("create_local_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + CU_ASSERT(check_token_validity(&tokens)); + + result = crypto->crypto_key_exchange->return_crypto_tokens(crypto->crypto_key_exchange, &tokens, &exception); + + if (!result) + { + printf("return_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_create_local_datawriter_crypto_tokens, invalid_args, .init = suite_create_local_datawriter_crypto_tokens_init, .fini = suite_create_local_datawriter_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + /* invalid token seq = NULL */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + NULL, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("create_local_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + 0, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("create_local_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid remote_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_writer_crypto, + 0, + &exception); + + if (!result) + { + printf("create_local_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + 1, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("create_local_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid remote_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_writer_crypto, + 1, + &exception); + + if (!result) + { + printf("create_local_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); +} + diff --git a/src/security/builtin_plugins/tests/create_local_participant_crypto_tokens/src/create_local_participant_crypto_tokens_utests.c b/src/security/builtin_plugins/tests/create_local_participant_crypto_tokens/src/create_local_participant_crypto_tokens_utests.c new file mode 100644 index 0000000..d568d58 --- /dev/null +++ b/src/security/builtin_plugins/tests/create_local_participant_crypto_tokens/src/create_local_participant_crypto_tokens_utests.c @@ -0,0 +1,362 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static const char *CRYPTO_TOKEN_CLASS_ID = "DDS:Crypto:AES_GCM_GMAC"; +static const char *CRYPTO_TOKEN_PROPERTY_NAME = "dds.cryp.keymat"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_ParticipantCryptoHandle local_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle = DDS_SECURITY_HANDLE_NIL; + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(DDS_Security_octet)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int register_participants(void) +{ + int r = 0; + DDS_Security_IdentityHandle participant_identity = 5; /* valid dummy value */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; /* valid but dummy value */ + DDS_Security_PermissionsHandle remote_participant_permissions = 5; /*valid dummy value */ + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + local_crypto_handle = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_crypto_handle == DDS_SECURITY_HANDLE_NIL) + { + r = -1; + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + if (r == 0) + { + remote_crypto_handle = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_crypto_handle, + participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + if (remote_crypto_handle == DDS_SECURITY_HANDLE_NIL) + { + r = -1; + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + } + + return r; +} + +static void unregister_participants(void) +{ + DDS_Security_boolean status; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + if (local_crypto_handle) + { + status = crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_crypto_handle, &exception); + if (!status) + { + printf("unregister_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + } + + if (remote_crypto_handle) + { + status = crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_crypto_handle, &exception); + if (!status) + { + printf("unregister_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + } +} + +static void suite_create_local_participant_crypto_tokens_init(void) +{ + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + allocate_shared_secret(); + CU_ASSERT_EQUAL_FATAL (register_participants(), 0); +} + +static void suite_create_local_participant_crypto_tokens_fini(void) +{ + unregister_participants(); + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static DDS_Security_boolean check_token_validity(const DDS_Security_ParticipantCryptoTokenSeq *tokens) +{ + DDS_Security_boolean status = true; + uint32_t i; + + if (tokens->_length == 0 || tokens->_buffer == NULL) + { + status = false; + } + + for (i = 0; status && (i < tokens->_length); i++) + { + status = (tokens->_buffer[i].class_id != NULL) && + (strcmp(CRYPTO_TOKEN_CLASS_ID, tokens->_buffer[i].class_id) == 0) && + (tokens->_buffer[i].binary_properties._length == 1) && + (tokens->_buffer[i].binary_properties._buffer != NULL) && + (tokens->_buffer[i].binary_properties._buffer[0].name != NULL) && + (strcmp(CRYPTO_TOKEN_PROPERTY_NAME, tokens->_buffer[i].binary_properties._buffer[0].name) == 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._length > 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._buffer != NULL); + } + + return status; +} + +CU_Test(ddssec_builtin_create_local_participant_crypto_tokens, happy_day, .init = suite_create_local_participant_crypto_tokens_init, .fini = suite_create_local_participant_crypto_tokens_fini) +{ + DDS_Security_boolean result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_ParticipantCryptoTokenSeq tokens; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_participant_crypto_tokens != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_crypto_handle, + remote_crypto_handle, + &exception); + if (!result) + { + printf("create_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + CU_ASSERT(check_token_validity(&tokens)); + + result = crypto->crypto_key_exchange->return_crypto_tokens(crypto->crypto_key_exchange, &tokens, &exception); + + if (!result) + { + printf("return_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_create_local_participant_crypto_tokens, invalid_args, .init = suite_create_local_participant_crypto_tokens_init, .fini = suite_create_local_participant_crypto_tokens_fini) +{ + DDS_Security_boolean result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_ParticipantCryptoTokenSeq tokens; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_participant_crypto_tokens != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&tokens, 0, sizeof(tokens)); + + /* invalid token seq = NULL */ + result = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + NULL, + local_crypto_handle, + remote_crypto_handle, + &exception); + if (!result) + { + printf("create_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + 0, + remote_crypto_handle, + &exception); + if (!result) + { + printf("create_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid remote_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_crypto_handle, + 0, + &exception); + if (!result) + { + printf("create_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + 1, + remote_crypto_handle, + &exception); + if (!result) + { + printf("create_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid remote_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_crypto_handle, + 1, + &exception); + if (!result) + { + printf("create_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); +} diff --git a/src/security/builtin_plugins/tests/decode_datareader_submessage/src/decode_datareader_submessage_utests.c b/src/security/builtin_plugins/tests/decode_datareader_submessage/src/decode_datareader_submessage_utests.c new file mode 100644 index 0000000..2dab5df --- /dev/null +++ b/src/security/builtin_plugins/tests/decode_datareader_submessage/src/decode_datareader_submessage_utests.c @@ -0,0 +1,1748 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_participant_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_handle = DDS_SECURITY_HANDLE_NIL; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +struct submsg_header +{ + unsigned char id; + unsigned char flags; + uint16_t length; +}; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[4]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + unsigned char length[4]; +}; + +struct receiver_specific_mac +{ + DDS_Security_CryptoTransformKeyId receiver_mac_key_id; + unsigned char receiver_mac[CRYPTO_HMAC_SIZE]; +}; + +struct seq_number +{ + int high; + unsigned low; +}; + +struct heartbeat +{ + struct submsg_header smhdr; + uint32_t readerId; + uint32_t writerId; + struct seq_number firstSN; + struct seq_number lastSN; + int count; +}; + +static struct heartbeat heartbeat; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void initialize_heartbeat(void) +{ + heartbeat.smhdr.id = 0x07; + heartbeat.smhdr.flags = 1; + heartbeat.smhdr.length = sizeof(heartbeat) - sizeof(struct submsg_header); + heartbeat.readerId = 0xA1B2C3D4; + heartbeat.writerId = 0xE5F6A7B0; + heartbeat.firstSN.high = 0; + heartbeat.firstSN.low = 1; + heartbeat.lastSN.high = 20; + heartbeat.lastSN.low = 500; + heartbeat.count = 1021; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + memset(&participant_security_attributes, 0, sizeof(participant_security_attributes)); + + local_participant_handle = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_participant_handle ? 0 : -1; +} + +static void unregister_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (local_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_participant_handle, &exception); + local_participant_handle = DDS_SECURITY_HANDLE_NIL; + reset_exception(&exception); + } +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_participant_handle = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_handle, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_participant_handle ? 0 : -1; +} + +static void unregister_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (remote_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_participant_handle, &exception); + remote_participant_handle = DDS_SECURITY_HANDLE_NIL; + reset_exception(&exception); + } +} + +static void prepare_endpoint_security_attributes_and_properties(DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_PropertySeq *properties, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + bool is_origin_authenticated) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + + attributes->is_discovery_protected = true; + + if (properties != NULL) + { + memset(properties, 0, sizeof(DDS_Security_PropertySeq)); + properties->_maximum = properties->_length = 1; + properties->_buffer = ddsrt_malloc(sizeof(DDS_Security_Property_t)); + + properties->_buffer[0].name = ddsrt_strdup("dds.sec.crypto.keysize"); + + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC) + { + properties->_buffer[0].value = ddsrt_strdup("128"); + } + else + { + properties->_buffer[0].value = ddsrt_strdup("256"); + } + } + + switch (transformation_kind) + { + case CRYPTO_TRANSFORMATION_KIND_AES128_GCM: + case CRYPTO_TRANSFORMATION_KIND_AES256_GCM: + attributes->is_submessage_protected = true; + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + case CRYPTO_TRANSFORMATION_KIND_AES256_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES128_GMAC: + attributes->is_submessage_protected = true; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + default: + assert(0); + break; + } +} + +static DDS_Security_DatawriterCryptoHandle register_local_datawriter(DDS_Security_EndpointSecurityAttributes *datawriter_security_attributes, DDS_Security_PropertySeq *datawriter_properties) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_handle, + datawriter_properties, + datawriter_security_attributes, + &exception); + + if (writer_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static DDS_Security_DatawriterCryptoHandle register_remote_datawriter(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + reader_crypto, + remote_participant_handle, + shared_secret_handle, + &exception); + + if (writer_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static void unregister_datawriter(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, writer_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatareaderCryptoHandle register_local_datareader(DDS_Security_EndpointSecurityAttributes *datareader_security_attributes, DDS_Security_PropertySeq *datareader_properties) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + datareader_properties, + datareader_security_attributes, + &exception); + + if (reader_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static DDS_Security_DatareaderCryptoHandle register_remote_datareader(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + writer_crypto, + remote_participant_handle, + shared_secret_handle, + true, + &exception); + + if (reader_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static void unregister_datareader(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, reader_crypto, &exception); + reset_exception(&exception); + } +} + +static bool set_remote_datareader_tokens( + DDS_Security_DatareaderCryptoHandle nodeA_local_reader_crypto, + DDS_Security_DatawriterCryptoHandle nodeA_remote_writer_crypto, + DDS_Security_DatawriterCryptoHandle nodeB_local_writer_crypto, + DDS_Security_DatareaderCryptoHandle nodeB_remote_reader_crypto) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoTokenSeq tokens; + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + nodeA_local_reader_crypto, + nodeA_remote_writer_crypto, + &exception); + + if (result) + { + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + nodeB_local_writer_crypto, + nodeB_remote_reader_crypto, + &tokens, + &exception); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); + + if (result) + { + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + nodeB_local_writer_crypto, + nodeB_remote_reader_crypto, + &exception); + } + + if (result) + { + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + nodeA_local_reader_crypto, + nodeA_remote_writer_crypto, + &tokens, + &exception); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); + + return (bool)result; +} + +static void suite_decode_datareader_submessage_init(void) +{ + allocate_shared_secret(); + initialize_heartbeat(); + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); +} + +static void suite_decode_datareader_submessage_fini(void) +{ + unregister_local_participant(); + unregister_remote_participant(); + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void initialize_data_submessage(DDS_Security_OctetSeq *submsg) +{ + uint32_t length = sizeof(struct heartbeat); + unsigned char *buffer; + + buffer = ddsrt_malloc(length); + + memcpy(buffer, &heartbeat, length); + + submsg->_length = submsg->_maximum = length; + submsg->_buffer = buffer; +} + +static void set_submsg_header(struct submsg_header *submsg, unsigned char id, unsigned char flags, uint16_t length) +{ + submsg->id = id; + submsg->flags = flags; + submsg->length = length; +} + +static struct submsg_header * get_submsg(unsigned char *data, int num) +{ + struct submsg_header *submsg; + int i; + + submsg = (struct submsg_header *)data; + for (i = 0; i < num - 1; i++) + { + uint32_t hlen = submsg->length; + data += sizeof(struct submsg_header) + hlen; + submsg = (struct submsg_header *)data; + } + + return submsg; +} + +static struct crypto_header * get_crypto_header(unsigned char *data) +{ + return (struct crypto_header *)(data + sizeof(struct submsg_header)); +} + +static struct crypto_footer * get_crypto_footer(unsigned char *data) +{ + struct submsg_header *submsg; + submsg = get_submsg(data, 3); + return (struct crypto_footer *)(submsg + 1); +} + +static void decode_datareader_submessage_not_signed( + DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandle nodeA_local_reader_crypto; + DDS_Security_DatawriterCryptoHandle nodeB_local_writer_crypto; + DDS_Security_DatareaderCryptoHandle nodeB_remote_reader_crypto; + DDS_Security_DatawriterCryptoHandle nodeA_remote_writer_crypto; + DDS_Security_DatawriterCryptoHandleSeq writer_list; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datareader_submessage != NULL); + + initialize_data_submessage(&plain_buffer); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, transformation_kind, false); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, transformation_kind, false); + + nodeA_local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(nodeA_local_reader_crypto != 0); + + nodeB_local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(nodeB_local_writer_crypto != 0); + + nodeA_remote_writer_crypto = register_remote_datawriter(nodeA_local_reader_crypto); + CU_ASSERT_FATAL(nodeA_remote_writer_crypto != 0); + + nodeB_remote_reader_crypto = register_remote_datareader(nodeB_local_writer_crypto); + CU_ASSERT_FATAL(nodeB_remote_reader_crypto != 0); + + result = set_remote_datareader_tokens(nodeA_local_reader_crypto, nodeA_remote_writer_crypto, nodeB_local_writer_crypto, nodeB_remote_reader_crypto); + CU_ASSERT_FATAL(result); + + writer_list._length = writer_list._maximum = 1; + writer_list._buffer = DDS_Security_DatawriterCryptoHandleSeq_allocbuf(1); + writer_list._buffer[0] = nodeA_remote_writer_crypto; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + nodeA_local_reader_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Decrypt the datareader submessage */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + nodeB_local_writer_crypto, + nodeB_remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + if (exception.message) + { + printf("Decoding failed: %s\n", exception.message); + } + CU_ASSERT_FATAL(result); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + reset_exception(&exception); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + } + + unregister_datawriter(nodeA_remote_writer_crypto); + unregister_datareader(nodeB_remote_reader_crypto); + unregister_datareader(nodeA_local_reader_crypto); + unregister_datawriter(nodeB_local_writer_crypto); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&writer_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, encoded_256, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, encoded_128, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, not_encoded_256, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, not_encoded_128, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +static void decode_datareader_submessage_signed( + DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + const uint32_t LIST_SIZE = 4u; + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandleSeq local_writer_list; + DDS_Security_DatareaderCryptoHandleSeq remote_reader_list; + DDS_Security_DatawriterCryptoHandleSeq remote_writer_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + uint32_t i; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datareader_submessage != NULL); + + initialize_data_submessage(&plain_buffer); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, transformation_kind, true); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, transformation_kind, true); + + local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + local_writer_list._length = local_writer_list._maximum = LIST_SIZE; + local_writer_list._buffer = DDS_Security_DatawriterCryptoHandleSeq_allocbuf(LIST_SIZE); + + remote_reader_list._length = remote_reader_list._maximum = LIST_SIZE; + remote_reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(LIST_SIZE); + + remote_writer_list._length = remote_writer_list._maximum = LIST_SIZE; + remote_writer_list._buffer = DDS_Security_DatawriterCryptoHandleSeq_allocbuf(LIST_SIZE); + + for (i = 0; i < LIST_SIZE; i++) + { + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + + local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + result = set_remote_datareader_tokens(local_reader_crypto, remote_writer_crypto, local_writer_crypto, remote_reader_crypto); + CU_ASSERT_FATAL(result); + + local_writer_list._buffer[i] = local_writer_crypto; + remote_reader_list._buffer[i] = remote_reader_crypto; + remote_writer_list._buffer[i] = remote_writer_crypto; + } + + /* Encrypt the datareader submessage. */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_reader_crypto, + &remote_writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Decrypt the datareader submessage */ + for (i = 0; i < LIST_SIZE; i++) + { + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_writer_list._buffer[i], + remote_reader_list._buffer[i], + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + } + + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + } + + for (i = 0; i < LIST_SIZE; i++) + { + unregister_datareader(remote_reader_list._buffer[i]); + unregister_datawriter(remote_writer_list._buffer[i]); + unregister_datawriter(local_writer_list._buffer[i]); + local_writer_list._buffer[i] = 0; + remote_reader_list._buffer[i] = 0; + remote_writer_list._buffer[i] = 0; + } + unregister_datareader(local_reader_crypto); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&local_writer_list); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&remote_reader_list); + DDS_Security_DatawriterCryptoHandleSeq_deinit(&remote_writer_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, signed_256, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, signed_128, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, only_signed_256, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, only_signed_128, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, invalid_args, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatawriterCryptoHandleSeq writer_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq empty_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datareader_submessage != NULL); + + initialize_data_submessage(&plain_buffer); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, false); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, false); + + memset(&empty_buffer, 0, sizeof(empty_buffer)); + + local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + result = set_remote_datareader_tokens(local_reader_crypto, remote_writer_crypto, local_writer_crypto, remote_reader_crypto); + CU_ASSERT_FATAL(result); + + writer_list._length = writer_list._maximum = 1; + writer_list._buffer = DDS_Security_DatawriterCryptoHandleSeq_allocbuf(1); + writer_list._buffer[0] = remote_writer_crypto; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_reader_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* decoded buffer NULL */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + NULL, + &encoded_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* encoded buffer NULL */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + NULL, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* empty encoded buffer */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &empty_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* local writer crypto 0 */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + 0, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* local writer crypto unknown */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + 1, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* remote reader crypto 0 */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_writer_crypto, + 0, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* remote reader crypto unknown */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_writer_crypto, + 1, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + unregister_datawriter(writer_list._buffer[0]); + writer_list._buffer[0] = 0; + unregister_datareader(remote_reader_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + reset_exception(&exception); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&writer_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&empty_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, invalid_data, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatawriterCryptoHandleSeq writer_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq corrupt_buffer = {0, 0, NULL}; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datareader_submessage != NULL); + + initialize_data_submessage(&plain_buffer); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + + local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + result = set_remote_datareader_tokens(local_reader_crypto, remote_writer_crypto, local_writer_crypto, remote_reader_crypto); + CU_ASSERT_FATAL(result); + + writer_list._length = writer_list._maximum = 1; + writer_list._buffer = DDS_Security_DatawriterCryptoHandleSeq_allocbuf(1); + writer_list._buffer[0] = remote_writer_crypto; + + /* Encrypt the datareader submessage. */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_reader_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Incorrect prefix id */ + { + struct submsg_header *prefix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + prefix = get_submsg(corrupt_buffer._buffer, 1); + + set_submsg_header(prefix, 0x15, prefix->flags, prefix->length); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect prefix length */ + { + struct submsg_header *prefix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + prefix = get_submsg(corrupt_buffer._buffer, 1); + + set_submsg_header(prefix, prefix->id, 0, prefix->length); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect body id */ + { + struct submsg_header *body; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer, 2); + + set_submsg_header(body, 0x15, body->flags, body->length); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect body length */ + { + struct submsg_header *body; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer, 2); + + set_submsg_header(body, body->id, body->flags, 1000); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix id */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer, 3); + + set_submsg_header(postfix, 0x15, postfix->flags, postfix->length); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix length */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer, 3); + + set_submsg_header(postfix, postfix->id, postfix->flags, 1000); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix length */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer, 3); + + set_submsg_header(postfix, postfix->id, postfix->flags, (uint16_t)(postfix->length - 20)); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect transformation kind */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer); + header->transform_identifier.transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect session id */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer); + header->session_id[0] = (unsigned char)(header->session_id[0] + 1); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect init vector suffix */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer); + header->init_vector_suffix[0] = (unsigned char)(header->init_vector_suffix[0] + 1); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect encoded data */ + { + struct submsg_header *body; + unsigned char *data; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer, 2); + data = (unsigned char *)(body + 1); + data[0] = (unsigned char)(data[0] + 1); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect common mac */ + { + struct crypto_footer *footer; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + footer->common_mac[0]++; + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer missing reader_specific mac */ + { + struct crypto_footer *footer; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + memset(footer->length, 0, 4); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect reader_specific mac id */ + { + struct crypto_footer *footer; + struct receiver_specific_mac *rmac; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + + rmac = (struct receiver_specific_mac *)(footer + 1); + rmac->receiver_mac_key_id[0] = (unsigned char)(rmac->receiver_mac_key_id[0] + 1); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect reader_specific mac */ + { + struct crypto_footer *footer; + struct receiver_specific_mac *rmac; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + + rmac = (struct receiver_specific_mac *)(footer + 1); + rmac->receiver_mac[0] = (unsigned char)(rmac->receiver_mac[0] + 1); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + unregister_datawriter(writer_list._buffer[0]); + writer_list._buffer[0] = 0; + unregister_datareader(remote_reader_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + reset_exception(&exception); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&writer_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, volatile_sec, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatawriterCryptoHandleSeq writer_list; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datareader_submessage != NULL); + + initialize_data_submessage(&plain_buffer); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, NULL, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, false); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, NULL, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, false); + + datareader_properties._length = datareader_properties._maximum = 1; + datareader_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datareader_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datareader_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureReader"); + datareader_properties._buffer[0].propagate = false; + + datawriter_properties._length = datawriter_properties._maximum = 1; + datawriter_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datawriter_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datawriter_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureWriter"); + datawriter_properties._buffer[0].propagate = false; + + local_writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + local_reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_crypto, + remote_participant_handle, + shared_secret_handle, + &exception); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + remote_reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_crypto, + remote_participant_handle, + shared_secret_handle, + true, + &exception); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + writer_list._length = writer_list._maximum = 1; + writer_list._buffer = DDS_Security_DatawriterCryptoHandleSeq_allocbuf(1); + writer_list._buffer[0] = remote_writer_crypto; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_reader_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Decrypt the datareader submessage */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + reset_exception(&exception); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + } + + unregister_datawriter(writer_list._buffer[0]); + writer_list._buffer[0] = 0; + unregister_datareader(remote_reader_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + reset_exception(&exception); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&writer_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + + DDS_Security_PropertySeq_deinit(&datawriter_properties); + DDS_Security_PropertySeq_deinit(&datareader_properties); +} + diff --git a/src/security/builtin_plugins/tests/decode_datawriter_submessage/src/decode_datawriter_submessage_utests.c b/src/security/builtin_plugins/tests/decode_datawriter_submessage/src/decode_datawriter_submessage_utests.c new file mode 100644 index 0000000..0e700ca --- /dev/null +++ b/src/security/builtin_plugins/tests/decode_datawriter_submessage/src/decode_datawriter_submessage_utests.c @@ -0,0 +1,1771 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_participant_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_handle = DDS_SECURITY_HANDLE_NIL; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static const char *sample_test_data = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy"; + +struct submsg_header +{ + unsigned char id; + unsigned char flags; + uint16_t length; +}; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[4]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + unsigned char length[4]; +}; + +struct receiver_specific_mac +{ + DDS_Security_CryptoTransformKeyId receiver_mac_key_id; + unsigned char receiver_mac[CRYPTO_HMAC_SIZE]; +}; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + memset(&participant_security_attributes, 0, sizeof(participant_security_attributes)); + + local_participant_handle = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_participant_handle ? 0 : -1; +} + +static void prepare_endpoint_security_attributes_and_properties(DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_PropertySeq *properties, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + bool is_origin_authenticated) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + + attributes->is_discovery_protected = true; + + if (properties != NULL) + { + memset(properties, 0, sizeof(DDS_Security_PropertySeq)); + properties->_maximum = properties->_length = 1; + properties->_buffer = ddsrt_malloc(sizeof(DDS_Security_Property_t)); + + properties->_buffer[0].name = ddsrt_strdup("dds.sec.crypto.keysize"); + + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC) + { + properties->_buffer[0].value = ddsrt_strdup("128"); + } + else + { + properties->_buffer[0].value = ddsrt_strdup("256"); + } + } + + switch (transformation_kind) + { + case CRYPTO_TRANSFORMATION_KIND_AES128_GCM: + case CRYPTO_TRANSFORMATION_KIND_AES256_GCM: + attributes->is_submessage_protected = true; + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + case CRYPTO_TRANSFORMATION_KIND_AES256_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES128_GMAC: + attributes->is_submessage_protected = true; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + default: + assert(0); + break; + } +} + +static void unregister_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (local_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_participant_handle, &exception); + reset_exception(&exception); + } +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_participant_handle = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_handle, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_participant_handle ? 0 : -1; +} + +static void unregister_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (remote_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_participant_handle, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatawriterCryptoHandle register_local_datawriter(DDS_Security_EndpointSecurityAttributes *attributes, DDS_Security_PropertySeq *properties) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_handle, + properties, + attributes, + &exception); + + if (writer_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static DDS_Security_DatawriterCryptoHandle register_remote_datawriter(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + reader_crypto, + remote_participant_handle, + shared_secret_handle, + &exception); + + if (writer_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static void unregister_datawriter(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, writer_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatareaderCryptoHandle register_local_datareader(DDS_Security_EndpointSecurityAttributes *attributes, DDS_Security_PropertySeq *properties) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + properties, + attributes, + &exception); + + if (reader_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static DDS_Security_DatareaderCryptoHandle register_remote_datareader(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + writer_crypto, + remote_participant_handle, + shared_secret_handle, + true, + &exception); + + if (reader_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static void unregister_datareader(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, reader_crypto, &exception); + reset_exception(&exception); + } +} + +static bool set_remote_datawriter_tokens( + DDS_Security_DatawriterCryptoHandle nodeA_local_writer_crypto, + DDS_Security_DatareaderCryptoHandle nodeA_remote_reader_crypto, + DDS_Security_DatareaderCryptoHandle nodeB_local_reader_crypto, + DDS_Security_DatawriterCryptoHandle nodeB_remote_writer_crypto) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + nodeA_local_writer_crypto, + nodeA_remote_reader_crypto, + &exception); + + if (result) + { + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + nodeB_local_reader_crypto, + nodeB_remote_writer_crypto, + &tokens, + &exception); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); + + if (result) + { + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + nodeB_local_reader_crypto, + nodeB_remote_writer_crypto, + &exception); + } + + if (result) + { + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + nodeA_local_writer_crypto, + nodeA_remote_reader_crypto, + &tokens, + &exception); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); + + return (bool)result; +} + +static void suite_decode_datawriter_submessage_init(void) +{ + allocate_shared_secret(); + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); +} + +static void suite_decode_datawriter_submessage_fini(void) +{ + unregister_local_participant(); + unregister_remote_participant(); + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void initialize_data_submessage(DDS_Security_OctetSeq *submsg, bool be) +{ + size_t length = strlen(sample_test_data) + 1; + struct submsg_header *header; + int swap; + unsigned char *buffer, *ptr; + + if (be) + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + + buffer = ddsrt_malloc(length + sizeof(struct submsg_header)); + header = (struct submsg_header *)buffer; + header->id = 0x15; + header->flags = be ? 0x00 : 0x01; + header->length = swap ? ddsrt_bswap2u((uint16_t)length) : (uint16_t)length; + ptr = (unsigned char *)(header + 1); + + memcpy((char *)ptr, sample_test_data, length); + + submsg->_length = submsg->_maximum = (uint32_t)(length + sizeof(struct submsg_header)); + submsg->_buffer = buffer; +} + +static void set_submsg_header(struct submsg_header *submsg, unsigned char id, unsigned char flags, uint16_t length) +{ + submsg->id = id; + submsg->flags = flags; + submsg->length = length; +} + +static struct submsg_header * get_submsg(unsigned char *data, int num) +{ + struct submsg_header *submsg; + int i; + + submsg = (struct submsg_header *)data; + for (i = 0; i < num - 1; i++) + { + uint32_t hlen = submsg->length; + data += sizeof(struct submsg_header) + hlen; + submsg = (struct submsg_header *)data; + } + + return submsg; +} + +static struct crypto_header * get_crypto_header(unsigned char *data) +{ + return (struct crypto_header *)(data + sizeof(struct submsg_header)); +} + +static struct crypto_footer * get_crypto_footer(unsigned char *data) +{ + struct submsg_header *submsg; + submsg = get_submsg(data, 3); + return (struct crypto_footer *)(submsg + 1); +} + +static void decode_datawriter_submessage_not_signed(DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + int32_t index; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datawriter_submessage != NULL); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, transformation_kind, false); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, transformation_kind, false); + + initialize_data_submessage(&plain_buffer, false); + + local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + result = set_remote_datawriter_tokens(local_writer_crypto, remote_reader_crypto, local_reader_crypto, remote_writer_crypto); + CU_ASSERT_FATAL(result); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_reader_crypto; + index = 0; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Decrypt the datawriter submessage */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + reset_exception(&exception); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + } + + unregister_datareader(reader_list._buffer[0]); + reader_list._buffer[0] = 0; + + unregister_datawriter(remote_writer_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, encoded_256, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, encoded_128, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, not_encoded_256, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, not_encoded_128, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +static void decode_datawriter_submessage_signed(DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + const uint32_t LIST_SIZE = 4u; + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandleSeq local_reader_list; + DDS_Security_DatawriterCryptoHandleSeq remote_writer_list; + DDS_Security_DatareaderCryptoHandleSeq remote_reader_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq *buffer; + int32_t index; + uint32_t i; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datawriter_submessage != NULL); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, transformation_kind, true); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, transformation_kind, true); + + initialize_data_submessage(&plain_buffer, false); + + local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + local_reader_list._length = local_reader_list._maximum = LIST_SIZE; + local_reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(LIST_SIZE); + + remote_writer_list._length = remote_writer_list._maximum = LIST_SIZE; + remote_writer_list._buffer = DDS_Security_DatawriterCryptoHandleSeq_allocbuf(LIST_SIZE); + + remote_reader_list._length = remote_reader_list._maximum = LIST_SIZE; + remote_reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(LIST_SIZE); + + for (i = 0; i < LIST_SIZE; i++) + { + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + + local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + result = set_remote_datawriter_tokens(local_writer_crypto, remote_reader_crypto, local_reader_crypto, remote_writer_crypto); + CU_ASSERT_FATAL(result); + + local_reader_list._buffer[i] = local_reader_crypto; + remote_writer_list._buffer[i] = remote_writer_crypto; + remote_reader_list._buffer[i] = remote_reader_crypto; + } + + index = 0; + + /* Encrypt the datawriter submessage. */ + buffer = &plain_buffer; + while ((uint32_t)index != LIST_SIZE) + { + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + buffer, + local_writer_crypto, + &remote_reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + buffer = NULL; + } + + /* Decrypt the datawriter submessage */ + + for (i = 0; i < LIST_SIZE; i++) + { + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_reader_list._buffer[i], + remote_writer_list._buffer[i], + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + } + + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + } + + for (i = 0; i < LIST_SIZE; i++) + { + unregister_datareader(remote_reader_list._buffer[i]); + unregister_datawriter(remote_writer_list._buffer[i]); + unregister_datareader(local_reader_list._buffer[i]); + local_reader_list._buffer[i] = 0; + remote_reader_list._buffer[i] = 0; + remote_writer_list._buffer[i] = 0; + } + unregister_datawriter(local_writer_crypto); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&local_reader_list); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&remote_reader_list); + DDS_Security_DatawriterCryptoHandleSeq_deinit(&remote_writer_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, signed_256, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, signed_128, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, only_signed_256, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, only_signed_128, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, invalid_args, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq empty_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + int32_t index; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datawriter_submessage != NULL); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + + initialize_data_submessage(&plain_buffer, false); + + memset(&empty_buffer, 0, sizeof(empty_buffer)); + + local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + result = set_remote_datawriter_tokens(local_writer_crypto, remote_reader_crypto, local_reader_crypto, remote_writer_crypto); + CU_ASSERT_FATAL(result); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_reader_crypto; + index = 0; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + +#if 0 + /* */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); +#endif + + /* decoded buffer NULL */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + NULL, + &encoded_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* encoded buffer NULL */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + NULL, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* empty encoded buffer */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &empty_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* local reader crypto 0 */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + 0, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* local reader crypto unknown */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + 1, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* remote writer crypto 0 */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_reader_crypto, + 0, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* remote writer crypto unknown */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_reader_crypto, + 1, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + unregister_datareader(reader_list._buffer[0]); + reader_list._buffer[0] = 0; + unregister_datawriter(remote_writer_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + reset_exception(&exception); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&empty_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, invalid_data, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq corrupt_buffer = {0, 0, NULL}; + int32_t index; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datawriter_submessage != NULL); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + + initialize_data_submessage(&plain_buffer, false); + + local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + result = set_remote_datawriter_tokens(local_writer_crypto, remote_reader_crypto, local_reader_crypto, remote_writer_crypto); + CU_ASSERT_FATAL(result); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_reader_crypto; + index = 0; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Incorrect prefix id */ + { + struct submsg_header *prefix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + prefix = get_submsg(corrupt_buffer._buffer, 1); + + set_submsg_header(prefix, 0x15, prefix->flags, prefix->length); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect prefix length */ + { + struct submsg_header *prefix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + prefix = get_submsg(corrupt_buffer._buffer, 1); + + set_submsg_header(prefix, prefix->id, 0, prefix->length); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect body id */ + { + struct submsg_header *body; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer, 2); + + set_submsg_header(body, 0x15, body->flags, body->length); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect body length */ + { + struct submsg_header *body; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer, 2); + + set_submsg_header(body, body->id, body->flags, 1000); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix id */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer, 3); + + set_submsg_header(postfix, 0x15, postfix->flags, postfix->length); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix length */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer, 3); + + set_submsg_header(postfix, postfix->id, postfix->flags, 1000); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix length */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer, 3); + + set_submsg_header(postfix, postfix->id, postfix->flags, (uint16_t)(postfix->length - 20)); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect transformation kind */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer); + header->transform_identifier.transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect session id */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer); + header->session_id[0] = (unsigned char)(header->session_id[0] + 1); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect init vector suffix */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer); + header->init_vector_suffix[0] = (unsigned char)(header->init_vector_suffix[0] + 1); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect encoded data */ + { + struct submsg_header *body; + unsigned char *data; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer, 2); + data = (unsigned char *)(body + 1); + data[0] = (unsigned char)(data[0] + 1); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect common mac */ + { + struct crypto_footer *footer; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + footer->common_mac[0] = (unsigned char)(footer->common_mac[0] + 1); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer missing reader_specific mac */ + { + struct crypto_footer *footer; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + memset(footer->length, 0, 4); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect reader_specific mac id */ + { + struct crypto_footer *footer; + struct receiver_specific_mac *rmac; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + + rmac = (struct receiver_specific_mac *)(footer + 1); + rmac->receiver_mac_key_id[0] = (unsigned char)(rmac->receiver_mac_key_id[0] + 1); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect reader_specific mac */ + { + struct crypto_footer *footer; + struct receiver_specific_mac *rmac; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + + rmac = (struct receiver_specific_mac *)(footer + 1); + rmac->receiver_mac[0] = (unsigned char)(rmac->receiver_mac[0] + 1); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + unregister_datareader(reader_list._buffer[0]); + reader_list._buffer[0] = 0; + unregister_datawriter(remote_writer_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + reset_exception(&exception); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, volatile_sec, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + int32_t index; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datawriter_submessage != NULL); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, NULL, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, false); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, NULL, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, false); + + initialize_data_submessage(&plain_buffer, false); + + datareader_properties._length = datareader_properties._maximum = 1; + datareader_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datareader_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datareader_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureReader"); + datareader_properties._buffer[0].propagate = false; + + datawriter_properties._length = datawriter_properties._maximum = 1; + datawriter_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datawriter_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datawriter_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureWriter"); + datawriter_properties._buffer[0].propagate = false; + + local_writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + local_reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_crypto, + remote_participant_handle, + shared_secret_handle, + &exception); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + remote_reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_crypto, + remote_participant_handle, + shared_secret_handle, + true, + &exception); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_reader_crypto; + index = 0; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Decrypt the datawriter submessage */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + reset_exception(&exception); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + } + + unregister_datareader(reader_list._buffer[0]); + reader_list._buffer[0] = 0; + unregister_datawriter(remote_writer_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + reset_exception(&exception); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + + DDS_Security_PropertySeq_deinit(&datawriter_properties); + DDS_Security_PropertySeq_deinit(&datareader_properties); +} + diff --git a/src/security/builtin_plugins/tests/decode_rtps_message/src/decode_rtps_message_utests.c b/src/security/builtin_plugins/tests/decode_rtps_message/src/decode_rtps_message_utests.c new file mode 100644 index 0000000..ea8a576 --- /dev/null +++ b/src/security/builtin_plugins/tests/decode_rtps_message/src/decode_rtps_message_utests.c @@ -0,0 +1,1492 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participantA_identity = 1; +static DDS_Security_IdentityHandle local_participantB_identity = 2; +static DDS_Security_IdentityHandle remote_identities[] = {2, 3, 4, 5}; + +static DDS_Security_ParticipantCryptoHandle local_participantA_crypto = 0; +static DDS_Security_ParticipantCryptoHandle local_participantB_crypto = 0; +static DDS_Security_ParticipantCryptoHandle remote_particpantA_crypto; +static DDS_Security_ParticipantCryptoHandle remote_cryptos[4]; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static const char *sample_test_data = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy"; + +static const char *RTPS_HEADER = "RTPS abcdefghijklmno"; + +struct submsg_header +{ + unsigned char id; + unsigned char flags; + uint16_t length; +}; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[4]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + unsigned char length[4]; +}; + +struct receiver_specific_mac +{ + DDS_Security_CryptoTransformKeyId receiver_mac_key_id; + unsigned char receiver_mac[CRYPTO_HMAC_SIZE]; +}; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void print_octets(const char *msg, const unsigned char *data, uint32_t sz) +{ + uint32_t i; + printf("%s: ", msg); + for (i = 0; i < sz; i++) + { + printf("%02x", data[i]); + } + printf("\n"); +} + +static void prepare_participant_security_attributes_and_properties(DDS_Security_ParticipantSecurityAttributes *attributes, + DDS_Security_PropertySeq *properties, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + bool is_origin_authenticated) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + + attributes->is_discovery_protected = true; + + if (properties != NULL) + { + memset(properties, 0, sizeof(DDS_Security_PropertySeq)); + properties->_maximum = properties->_length = 1; + properties->_buffer = ddsrt_malloc(sizeof(DDS_Security_Property_t)); + + properties->_buffer[0].name = ddsrt_strdup("dds.sec.crypto.keysize"); + + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC) + { + properties->_buffer[0].value = ddsrt_strdup("128"); + } + else + { + properties->_buffer[0].value = ddsrt_strdup("256"); + } + } + + switch (transformation_kind) + { + case CRYPTO_TRANSFORMATION_KIND_AES128_GCM: + case CRYPTO_TRANSFORMATION_KIND_AES256_GCM: + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; + if (is_origin_authenticated) + { + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED; + } + break; + + case CRYPTO_TRANSFORMATION_KIND_AES256_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES128_GMAC: + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->is_rtps_protected = true; + if (is_origin_authenticated) + { + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED; + } + break; + + default: + assert(0); + break; + } +} + +static int register_local_participants(DDS_Security_ParticipantSecurityAttributes *participant_security_attributes, DDS_Security_PropertySeq *participant_properties) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + + local_participantA_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participantA_identity, + participant_permissions, + participant_properties, + participant_security_attributes, + &exception); + + if (local_participantA_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + local_participantB_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participantB_identity, + participant_permissions, + participant_properties, + participant_security_attributes, + &exception); + + if (local_participantA_crypto == 0 || local_participantB_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_participantA_crypto && local_participantB_crypto ? 0 : -1; +} + +static void unregister_local_participants(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (local_participantA_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_participantA_crypto, &exception); + reset_exception(&exception); + } + if (local_participantB_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_participantB_crypto, &exception); + reset_exception(&exception); + } +} + +static int register_remote_participants(DDS_Security_ParticipantCryptoHandle local_id, + DDS_Security_IdentityHandle remote_ids[4], + DDS_Security_ParticipantCryptoHandle participant_cryptos[4]) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + unsigned i; + int result = 0; + + for (i = 0; i < 4; ++i) + { + participant_cryptos[i] = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_id, + remote_ids[i], + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (participant_cryptos[i] == 0) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + result = 1; + break; + } + } + + return result; +} + +static void unregister_remote_participants(void) +{ + unsigned i; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + for (i = 0; i < 4; ++i) + { + if (remote_cryptos[i]) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_cryptos[i], &exception); + reset_exception(&exception); + } + } +} + +static int register_remote_participant_for_participantB( + DDS_Security_ParticipantCryptoHandle local_id, + DDS_Security_IdentityHandle remote_identity, + DDS_Security_ParticipantCryptoHandle *remote_participant_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + int result = 0; + + *remote_participant_crypto = crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, local_id, remote_identity, + remote_participant_permissions, shared_secret_handle, &exception); + + if (*remote_participant_crypto == 0) + { + printf("register_matched_remote_participant: %s\n", + exception.message ? exception.message : "Error message missing"); + result = 1; + } + + return result; +} + +static void unregister_remote_participant_of_participantB(DDS_Security_ParticipantCryptoHandle remote_participant_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (remote_participant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_participant_crypto, &exception); + reset_exception(&exception); + } +} + +static void set_protection_kind(DDS_Security_ParticipantCryptoHandle participant_crypto, DDS_Security_ProtectionKind protection_kind) +{ + local_participant_crypto *paricipant_crypto_impl = (local_participant_crypto *)participant_crypto; + + paricipant_crypto_impl->rtps_protection_kind = protection_kind; +} + +static bool set_remote_participant_tokens( + DDS_Security_ParticipantCryptoHandle local_participantA_crypto_handle, + DDS_Security_ParticipantCryptoHandle remote_participantB_crypto_handle, + DDS_Security_ParticipantCryptoHandle local_participantB_crypto_handle, + DDS_Security_ParticipantCryptoHandle remote_participantA_crypto_handle) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + + result = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_participantA_crypto_handle, + remote_participantB_crypto_handle, + &exception); + + if (result) + { + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_participantB_crypto_handle, + remote_participantA_crypto_handle, + &tokens, + &exception); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); + + return (bool)result; +} + +static session_key_material * get_local_participant_session(DDS_Security_ParticipantCryptoHandle participant_crypto) +{ + local_participant_crypto *participant_crypto_impl = (local_participant_crypto *)participant_crypto; + return participant_crypto_impl->session; +} + +static void suite_decode_rtps_message_init(void) +{ + allocate_shared_secret(); + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); +} + +static void suite_decode_rtps_message_fini(void) +{ + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void initialize_rtps_message(DDS_Security_OctetSeq *submsg, bool be) +{ + size_t length = strlen(sample_test_data) + 1; + struct submsg_header *header; + int swap; + unsigned char *buffer, *ptr; + + if (be) + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + + buffer = ddsrt_malloc(length + 20 + sizeof(struct submsg_header)); + memcpy(buffer, RTPS_HEADER, 20); + + header = (struct submsg_header *)(buffer + 20); + header->id = 0x15; + header->flags = be ? 0x00 : 0x01; + header->length = swap ? ddsrt_bswap2u((uint16_t)length) : (uint16_t)length; + + ptr = (unsigned char *)(header + 1); + memcpy((char *)ptr, sample_test_data, length); + + submsg->_length = submsg->_maximum = (uint32_t)(20 + length + sizeof(struct submsg_header)); + submsg->_buffer = buffer; +} + +static void set_submsg_header(struct submsg_header *submsg, unsigned char id, unsigned char flags, uint16_t length) +{ + submsg->id = id; + submsg->flags = flags; + submsg->length = length; +} + +static struct submsg_header * get_submsg(unsigned char *data, int num) +{ + struct submsg_header *submsg; + int i; + + submsg = (struct submsg_header *)data; + for (i = 0; i < num - 1; i++) + { + uint32_t hlen = submsg->length; + data += sizeof(struct submsg_header) + hlen; + submsg = (struct submsg_header *)data; + } + + return submsg; +} + +static struct crypto_header * get_crypto_header(unsigned char *data) +{ + return (struct crypto_header *)(data + sizeof(struct submsg_header)); +} + +static struct crypto_footer * get_crypto_footer(unsigned char *data) +{ + struct submsg_header *submsg; + submsg = get_submsg(data + 20, 3); + return (struct crypto_footer *)(submsg + 1); +} + +static void decode_rtps_message_not_authenticated(DDS_Security_CryptoTransformKind_Enum transformation_kind, uint32_t key_size) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + session_key_material *session_keys; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + int32_t index; + DDS_Security_ParticipantSecurityAttributes attributes; + DDS_Security_PropertySeq properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_rtps_message != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_rtps_message != NULL); + + prepare_participant_security_attributes_and_properties(&attributes, &properties, transformation_kind, true); + register_local_participants(&attributes, &properties); + + initialize_rtps_message(&plain_buffer, false); + + session_keys = get_local_participant_session(local_participantA_crypto); + session_keys->master_key_material->transformation_kind = transformation_kind; + session_keys->key_size = key_size; + + register_remote_participants(local_participantA_crypto, remote_identities, remote_cryptos); + + /* Now remote participant cypto is in remote_cryptos[0] */ + + register_remote_participant_for_participantB(local_participantB_crypto, local_participantA_identity, &remote_particpantA_crypto); + + result = set_remote_participant_tokens(local_participantA_crypto, remote_cryptos[0], local_participantB_crypto, remote_particpantA_crypto); + CU_ASSERT_FATAL(result); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_ParticipantCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_cryptos[0]; + index = 0; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_participantA_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Decrypt the datawriter submessage */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + reset_exception(&exception); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + print_octets("decoded_buffer", decoded_buffer._buffer, plain_buffer._length); + print_octets("plain_buffer", plain_buffer._buffer, plain_buffer._length); + } + + unregister_remote_participant_of_participantB(remote_particpantA_crypto); + unregister_remote_participants(); + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + DDS_Security_PropertySeq_deinit(&properties); + + unregister_local_participants(); +} + +CU_Test(ddssec_builtin_decode_rtps_message, encoded_256, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES256_GCM, 256); +} + +CU_Test(ddssec_builtin_decode_rtps_message, encoded_128, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES128_GCM, 128); +} + +CU_Test(ddssec_builtin_decode_rtps_message, not_encrypted_256, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, 256); +} + +CU_Test(ddssec_builtin_decode_rtps_message, not_encrypted_128, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC, 128); +} + +static void decode_rtps_message_authenticated(DDS_Security_CryptoTransformKind_Enum transformation_kind, uint32_t key_size, DDS_Security_ProtectionKind protection_kind) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_ParticipantCryptoHandleSeq remote_reader_list; + session_key_material *session_keys; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq *buffer; + DDS_Security_ParticipantSecurityAttributes attributes; + DDS_Security_PropertySeq properties; + int i, index; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_rtps_message != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_rtps_message != NULL); + + prepare_participant_security_attributes_and_properties(&attributes, &properties, transformation_kind, true); + register_local_participants(&attributes, &properties); + + initialize_rtps_message(&plain_buffer, false); + + session_keys = get_local_participant_session(local_participantA_crypto); + session_keys->master_key_material->transformation_kind = transformation_kind; + session_keys->key_size = key_size; + + set_protection_kind(local_participantA_crypto, protection_kind); + + register_remote_participants(local_participantA_crypto, remote_identities, remote_cryptos); + + set_protection_kind(local_participantB_crypto, protection_kind); + + register_remote_participant_for_participantB(local_participantB_crypto, local_participantA_identity, &remote_particpantA_crypto); + + result = set_remote_participant_tokens(local_participantA_crypto, remote_cryptos[0], local_participantB_crypto, remote_particpantA_crypto); + CU_ASSERT_FATAL(result); + + remote_reader_list._length = remote_reader_list._maximum = 4; + remote_reader_list._buffer = DDS_Security_ParticipantCryptoHandleSeq_allocbuf(4); + + for (i = 0; i < 4; i++) + { + remote_reader_list._buffer[i] = remote_cryptos[i]; + } + + index = 0; + + /* Encrypt the datawriter submessage. */ + buffer = &plain_buffer; + while (index != 4) + { + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + buffer, + local_participantA_crypto, + &remote_reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + buffer = NULL; + } + + /* Decrypt the datawriter submessage */ + + for (i = 0; i < 4; i++) + { + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + print_octets("decoded_buffer", decoded_buffer._buffer, plain_buffer._length); + print_octets("plain_buffer", plain_buffer._buffer, plain_buffer._length); + } + + reset_exception(&exception); + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + } + + unregister_remote_participant_of_participantB(remote_particpantA_crypto); + unregister_remote_participants(); + reset_exception(&exception); + + DDS_Security_PropertySeq_deinit(&properties); + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&remote_reader_list); +} + +CU_Test(ddssec_builtin_decode_rtps_message, authenticated_256, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_authenticated(CRYPTO_TRANSFORMATION_KIND_AES256_GCM, 256, DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION); +} + +CU_Test(ddssec_builtin_decode_rtps_message, authenticated_128, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_authenticated(CRYPTO_TRANSFORMATION_KIND_AES128_GCM, 128, DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION); +} + +CU_Test(ddssec_builtin_decode_rtps_message, only_authenticated_256, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_authenticated(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, 256, DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION); +} + +CU_Test(ddssec_builtin_decode_rtps_message, only_authenticated_128, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_authenticated(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC, 128, DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION); +} + +CU_Test(ddssec_builtin_decode_rtps_message, invalid_args, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq empty_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + int32_t index; + DDS_Security_ParticipantSecurityAttributes attributes; + DDS_Security_PropertySeq properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_rtps_message != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_rtps_message != NULL); + + prepare_participant_security_attributes_and_properties(&attributes, &properties, CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, false); + register_local_participants(&attributes, &properties); + + initialize_rtps_message(&plain_buffer, false); + + register_remote_participants(local_participantA_crypto, remote_identities, remote_cryptos); + + /* Now remote participant cypto is in remote_cryptos[0] */ + + register_remote_participant_for_participantB(local_participantB_crypto, local_participantA_identity, &remote_particpantA_crypto); + + result = set_remote_participant_tokens(local_participantA_crypto, remote_cryptos[0], local_participantB_crypto, remote_particpantA_crypto); + CU_ASSERT_FATAL(result); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_ParticipantCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_cryptos[0]; + index = 0; + + /* Encrypt */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_participantA_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* decoded buffer NULL */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + NULL, + &encoded_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* encoded buffer NULL */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + NULL, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* empty encoded buffer */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &empty_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* local reader crypto 0 */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + 0, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* local reader crypto unknown */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + 1, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* remote writer crypto 0 */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_participantB_crypto, + 0, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* remote writer crypto unknown */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_participantB_crypto, + 1, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + unregister_remote_participant_of_participantB(remote_particpantA_crypto); + unregister_remote_participants(); + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + DDS_Security_PropertySeq_deinit(&properties); + unregister_local_participants(); +} + +CU_Test(ddssec_builtin_decode_rtps_message, invalid_data, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq corrupt_buffer = {0, 0, NULL}; + session_key_material *session_keys; + int32_t index; + DDS_Security_ParticipantSecurityAttributes attributes; + DDS_Security_PropertySeq properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_rtps_message != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_rtps_message != NULL); + + prepare_participant_security_attributes_and_properties(&attributes, &properties, CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, false); + register_local_participants(&attributes, &properties); + initialize_rtps_message(&plain_buffer, false); + + session_keys = get_local_participant_session(local_participantA_crypto); + session_keys->master_key_material->transformation_kind = CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + session_keys->key_size = 256; + + set_protection_kind(local_participantA_crypto, DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION); + + register_remote_participants(local_participantA_crypto, remote_identities, remote_cryptos); + + set_protection_kind(local_participantB_crypto, DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION); + + register_remote_participant_for_participantB(local_participantB_crypto, local_participantA_identity, &remote_particpantA_crypto); + + result = set_remote_participant_tokens(local_participantA_crypto, remote_cryptos[0], local_participantB_crypto, remote_particpantA_crypto); + CU_ASSERT_FATAL(result); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_ParticipantCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_cryptos[0]; + index = 0; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_participantA_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Incorrect prefix id */ + { + struct submsg_header *prefix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + prefix = get_submsg(corrupt_buffer._buffer + 20, 1); + + set_submsg_header(prefix, 0x15, prefix->flags, prefix->length); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect prefix length */ + { + struct submsg_header *prefix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + prefix = get_submsg(corrupt_buffer._buffer + 20, 1); + + set_submsg_header(prefix, prefix->id, 0, prefix->length); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect body id */ + { + struct submsg_header *body; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer + 20, 2); + + set_submsg_header(body, 0x15, body->flags, body->length); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect body length */ + { + struct submsg_header *body; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer + 20, 2); + + set_submsg_header(body, body->id, body->flags, 1000); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix id */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer + 20, 3); + + set_submsg_header(postfix, 0x15, postfix->flags, postfix->length); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix length */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer + 20, 3); + + set_submsg_header(postfix, postfix->id, postfix->flags, 1000); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix length */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer + 20, 3); + + set_submsg_header(postfix, postfix->id, postfix->flags, (uint16_t)(postfix->length - 20)); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect transformation kind */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer + 20); + header->transform_identifier.transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect session id */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer + 20); + header->session_id[0] = (unsigned char)(header->session_id[0] + 1); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect init vector suffix */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer + 20); + header->init_vector_suffix[0] = (unsigned char)(header->init_vector_suffix[0] + 1); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect encoded data */ + { + struct submsg_header *body; + unsigned char *data; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer + 20, 2); + data = (unsigned char *)(body + 1); + data[0] = (unsigned char)(data[0] + 1); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect common mac */ + { + struct crypto_footer *footer; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + footer->common_mac[0] = (unsigned char)(footer->common_mac[0] + 1); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer missing reader_specific mac */ + { + struct crypto_footer *footer; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + memset(footer->length, 0, 4); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + +#if 0 + /* footer incorrect reader_specific mac id */ + { + struct crypto_footer *footer; + struct receiver_specific_mac *rmac; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + + rmac = (struct receiver_specific_mac *)(footer + 1); + rmac->receiver_mac_key_id[0] += 1; + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect reader_specific mac */ + { + struct crypto_footer *footer; + struct receiver_specific_mac *rmac; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + + rmac = (struct receiver_specific_mac *)(footer + 1); + rmac->receiver_mac[0] += 1; + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } +#endif + + unregister_remote_participant_of_participantB(remote_particpantA_crypto); + unregister_remote_participants(); + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + DDS_Security_PropertySeq_deinit(&properties); + unregister_local_participants(); +} + diff --git a/src/security/builtin_plugins/tests/decode_serialized_payload/src/decode_serialized_payload_utests.c b/src/security/builtin_plugins/tests/decode_serialized_payload/src/decode_serialized_payload_utests.c new file mode 100644 index 0000000..91d7e55 --- /dev/null +++ b/src/security/builtin_plugins/tests/decode_serialized_payload/src/decode_serialized_payload_utests.c @@ -0,0 +1,1119 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_participant_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_handle = DDS_SECURITY_HANDLE_NIL; + +static DDS_Security_SharedSecretHandle shared_secret_handle = DDS_SECURITY_HANDLE_NIL; + +static const char *sample_test_data = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy"; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[4]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + unsigned char length[4]; +}; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = (DDS_Security_SharedSecretHandleImpl *)shared_secret_handle; + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + local_participant_handle = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_participant_handle ? 0 : -1; +} + +static void unregister_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (local_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_participant_handle, &exception); + reset_exception(&exception); + } +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_participant_handle = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_handle, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_participant_handle ? 0 : -1; +} + +static void unregister_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (remote_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_participant_handle, &exception); + reset_exception(&exception); + } +} + +static void prepare_endpoint_security_attributes(DDS_Security_EndpointSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; +} + +static DDS_Security_DatawriterCryptoHandle register_local_datawriter(bool encrypted) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + prepare_endpoint_security_attributes(&datawriter_security_attributes); + + datawriter_security_attributes.is_payload_protected = true; + if (encrypted) + { + datawriter_security_attributes.plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + } + + writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + if (writer_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static DDS_Security_DatawriterCryptoHandle register_remote_datawriter(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + reader_crypto, + remote_participant_handle, + shared_secret_handle, + &exception); + + if (writer_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static void unregister_datawriter(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, writer_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatareaderCryptoHandle register_local_datareader(bool encrypted) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + memset(&datareader_properties, 0, sizeof(datareader_properties)); + memset(&datareader_security_attributes, 0, sizeof(datareader_security_attributes)); + datareader_security_attributes.is_payload_protected = true; + if (encrypted) + { + datareader_security_attributes.plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + } + + reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + + if (reader_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static DDS_Security_DatareaderCryptoHandle register_remote_datareader(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + writer_crypto, + remote_participant_handle, + shared_secret_handle, + true, + &exception); + + if (reader_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static void unregister_datareader(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, reader_crypto, &exception); + reset_exception(&exception); + } +} + +static bool +set_remote_datawriter_tokens( + DDS_Security_DatawriterCryptoHandle local_writer_crypto, + DDS_Security_DatareaderCryptoHandle remote_reader_crypto, + DDS_Security_DatareaderCryptoHandle local_reader_crypto, + DDS_Security_DatawriterCryptoHandle remote_writer_crypto) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (result) + { + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + (void)crypto->crypto_key_exchange->return_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + &exception); + } + + return (bool)result; +} + +static session_key_material * get_datawriter_session(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + local_datawriter_crypto *writer_crypto_impl = (local_datawriter_crypto *)writer_crypto; + + return writer_crypto_impl->writer_session_message; +} + +static bool check_writer_protection_kind(DDS_Security_DatawriterCryptoHandle writer_crypto, DDS_Security_BasicProtectionKind protection_kind) +{ + local_datawriter_crypto *writer_crypto_impl = (local_datawriter_crypto *)writer_crypto; + return (writer_crypto_impl->data_protectionKind == protection_kind); +} + +static uint32_t get_transformation_kind(uint32_t key_size, bool encoded) +{ + uint32_t kind = CRYPTO_TRANSFORMATION_KIND_INVALID; + if (key_size == 128) + { + kind = encoded ? CRYPTO_TRANSFORMATION_KIND_AES128_GCM : CRYPTO_TRANSFORMATION_KIND_AES128_GMAC; + } + else if (key_size == 256) + { + kind = encoded ? CRYPTO_TRANSFORMATION_KIND_AES256_GCM : CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; + } + CU_ASSERT_FATAL(kind != CRYPTO_TRANSFORMATION_KIND_INVALID); + return kind; +} + +static void suite_decode_serialized_payload_init(void) +{ + allocate_shared_secret(); + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); +} + +static void suite_decode_serialized_payload_fini(void) +{ + unregister_remote_participant(); + unregister_local_participant(); + unload_plugins(plugins); + deallocate_shared_secret(); +} + +static bool split_encoded_data(unsigned char *data, size_t size, struct crypto_header **header, unsigned char **contents, uint32_t *length, struct crypto_footer **footer) +{ + unsigned char *ptr; + + if (size < sizeof(struct crypto_header) + 4) + return false; + + *header = (struct crypto_header *)data; + ptr = data + sizeof(struct crypto_header); + *length = ddsrt_fromBE4u(*(uint32_t *)ptr); + + size -= sizeof(struct crypto_header) + 4; + + /* remain should contain the ecrypted data + the footer (common_mac (16) + length (4)) */ + if (size < (*length) + 20) + return false; + + ptr += 4; + *contents = ptr; + ptr += *length; + + /* The length is the length of the encrypted data and the common_mac of the footer + * For the serialized payload the footer consists of the common_mac and the length + * of the receiver_specific_mac which is set to 0 + */ + *footer = (struct crypto_footer *)ptr; + + return true; +} + +static void decode_serialized_payload_check(uint32_t key_size, bool encrypted) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq extra_inline_qos; + DDS_Security_OctetSeq plain_buffer; + session_key_material *session_keys; + size_t length; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_serialized_payload != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_serialized_payload != NULL); + + memset(&extra_inline_qos, 0, sizeof(extra_inline_qos)); + + length = strlen(sample_test_data) + 1; + plain_buffer._length = plain_buffer._maximum = (uint32_t) length; + plain_buffer._buffer = DDS_Security_OctetSeq_allocbuf((uint32_t)length); + memcpy((char *)plain_buffer._buffer, sample_test_data, length); + + local_writer_crypto = register_local_datawriter(encrypted); + CU_ASSERT_FATAL(local_writer_crypto != 0); + CU_ASSERT(check_writer_protection_kind(local_writer_crypto, encrypted ? DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT : DDS_SECURITY_BASICPROTECTION_KIND_SIGN)); + + session_keys = get_datawriter_session(local_writer_crypto); + session_keys->master_key_material->transformation_kind = get_transformation_kind(key_size, encrypted); + session_keys->key_size = key_size; + + local_reader_crypto = register_local_datareader(encrypted); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + result = set_remote_datawriter_tokens(local_writer_crypto, remote_reader_crypto, local_reader_crypto, remote_writer_crypto); + CU_ASSERT_FATAL(result); + + /* Encrypt the data. */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + &plain_buffer, + local_writer_crypto, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Decrypt the data */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + unregister_datareader(remote_reader_crypto); + unregister_datawriter(remote_writer_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + DDS_Security_OctetSeq_deinit(&plain_buffer); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_decode_serialized_payload, decrypt_128, .init = suite_decode_serialized_payload_init, .fini = suite_decode_serialized_payload_fini) +{ + decode_serialized_payload_check(128, true); +} + +CU_Test(ddssec_builtin_decode_serialized_payload, decrypt_256, .init = suite_decode_serialized_payload_init, .fini = suite_decode_serialized_payload_fini) +{ + decode_serialized_payload_check(256, true); +} + +CU_Test(ddssec_builtin_decode_serialized_payload, signcheck_128, .init = suite_decode_serialized_payload_init, .fini = suite_decode_serialized_payload_fini) +{ + decode_serialized_payload_check(128, false); +} + +CU_Test(ddssec_builtin_decode_serialized_payload, signcheck_256, .init = suite_decode_serialized_payload_init, .fini = suite_decode_serialized_payload_fini) +{ + decode_serialized_payload_check(256, false); +} + +CU_Test(ddssec_builtin_decode_serialized_payload, invalid_args, .init = suite_decode_serialized_payload_init, .fini = suite_decode_serialized_payload_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq extra_inline_qos; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq empty_buffer; + session_key_material *session_keys; + size_t length; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_serialized_payload != NULL); + + memset(&extra_inline_qos, 0, sizeof(extra_inline_qos)); + memset(&empty_buffer, 0, sizeof(empty_buffer)); + + length = strlen(sample_test_data) + 1; + plain_buffer._length = plain_buffer._maximum = (uint32_t)length; + plain_buffer._buffer = DDS_Security_OctetSeq_allocbuf((uint32_t)length); + memcpy((char *)plain_buffer._buffer, sample_test_data, length); + + local_writer_crypto = register_local_datawriter(true); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + session_keys = get_datawriter_session(local_writer_crypto); + session_keys->master_key_material->transformation_kind = CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + session_keys->key_size = 256; + + local_reader_crypto = register_local_datareader(true); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + result = set_remote_datawriter_tokens(local_writer_crypto, remote_reader_crypto, local_reader_crypto, remote_writer_crypto); + CU_ASSERT_FATAL(result); + + /* encrypt the data */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + &plain_buffer, + local_writer_crypto, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* no decoded data buffer specified */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + NULL, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* no encrypted data buffer specified */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + NULL, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* empty encrypted data buffer specified */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &empty_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* unknown local reader crypto handle specified */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + 0, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local reader crypto handle specified */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + remote_writer_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* unknown remote writer crypto handle specified */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + 0, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid remote writer crypto handle specified */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + local_reader_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + unregister_datareader(remote_reader_crypto); + unregister_datawriter(remote_writer_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&plain_buffer); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_decode_serialized_payload, invalid_data, .init = suite_decode_serialized_payload_init, .fini = suite_decode_serialized_payload_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq extra_inline_qos; + DDS_Security_OctetSeq plain_buffer; + session_key_material *session_keys; + size_t length; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + unsigned char *contents = NULL; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_serialized_payload != NULL); + + memset(&extra_inline_qos, 0, sizeof(extra_inline_qos)); + + length = strlen(sample_test_data) + 1; + plain_buffer._length = plain_buffer._maximum = (uint32_t) length; + plain_buffer._buffer = DDS_Security_OctetSeq_allocbuf((uint32_t) length); + memcpy((char *)plain_buffer._buffer, sample_test_data, length); + + local_writer_crypto = register_local_datawriter(true); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + session_keys = get_datawriter_session(local_writer_crypto); + session_keys->master_key_material->transformation_kind = CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + session_keys->key_size = 256; + + local_reader_crypto = register_local_datareader(true); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + result = set_remote_datawriter_tokens(local_writer_crypto, remote_reader_crypto, local_reader_crypto, remote_writer_crypto); + CU_ASSERT_FATAL(result); + + /* Encrypt the data. */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + &plain_buffer, + local_writer_crypto, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + result = split_encoded_data(encoded_buffer._buffer, encoded_buffer._length, &header, &contents, (uint32_t *) &length, &footer); + CU_ASSERT_FATAL(result); + + /* use incorrect transformation kind */ + { + DDS_Security_CryptoTransformKind_Enum kind = header->transform_identifier.transformation_kind[3]; + header->transform_identifier.transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + header->transform_identifier.transformation_kind[3] = (unsigned char) kind; + } + + /* use incorrect transformation key id */ + { + unsigned char key[4]; + uint32_t val = (uint32_t) rand(); + + memcpy(key, header->transform_identifier.transformation_key_id, 4); + memcpy(header->transform_identifier.transformation_key_id, &val, 4); + + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + memcpy(header->transform_identifier.transformation_key_id, key, 4); + } + + /* use incorrect session id*/ + { + unsigned char sid[4]; + uint32_t val = (uint32_t) rand(); + + memcpy(sid, header->session_id, 4); + memcpy(header->session_id, &val, 4); + + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + memcpy(header->session_id, sid, 4); + } + + /* use incorrect init vector suffix*/ + { + unsigned char iv[8]; + struct + { + uint32_t h; + uint32_t l; + } val; + + val.h = (uint32_t) rand(); + val.l = (uint32_t) rand(); + + memcpy(iv, header->init_vector_suffix, 8); + memcpy(header->init_vector_suffix, &val, 8); + + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + memcpy(header->init_vector_suffix, iv, 8); + } + + /* use incorrect data length */ + { + uint32_t saved, len; + unsigned char *ptr; + + ptr = encoded_buffer._buffer + sizeof(struct crypto_header); + + memcpy(&saved, ptr, 4); + + len = ddsrt_toBE4u(saved); + len += 4; + len = ddsrt_fromBE4u(len); + + memcpy(ptr, &len, 4); + + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + memcpy(ptr, &saved, 4); + } + + /* use incorrect data */ + { + unsigned char saved[10]; + unsigned char *ptr; + + ptr = contents + 20; + + memcpy(&saved, ptr, 10); + memset(ptr, 0xFF, 10); + + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + memcpy(ptr, &saved, 10); + } + + /* use incorrect hmac */ + { + unsigned char hmac[16]; + uint32_t i, j; + + memcpy(hmac, footer->common_mac, 16); + for (i = 0, j = 15; i < 8; ++i, --j) + { + unsigned char c = footer->common_mac[j]; + footer->common_mac[j] = footer->common_mac[i]; + footer->common_mac[i] = c; + } + + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + memcpy(footer->common_mac, &hmac, 16); + } + + /* use incorrect footer*/ + { + footer->length[0] = 1; + + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + footer->length[0] = 0; + } + + unregister_datareader(remote_reader_crypto); + unregister_datawriter(remote_writer_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&plain_buffer); +} + diff --git a/src/security/builtin_plugins/tests/encode_datareader_submessage/src/encode_datareader_submessage_utests.c b/src/security/builtin_plugins/tests/encode_datareader_submessage/src/encode_datareader_submessage_utests.c new file mode 100644 index 0000000..2513a39 --- /dev/null +++ b/src/security/builtin_plugins/tests/encode_datareader_submessage/src/encode_datareader_submessage_utests.c @@ -0,0 +1,1275 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_objects.h" +#include "crypto_utils.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_participant_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_handle = DDS_SECURITY_HANDLE_NIL; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +struct submsg_header +{ + unsigned char id; + unsigned char flags; + uint16_t length; +}; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[4]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + uint32_t length; +}; + +struct receiver_specific_mac +{ + DDS_Security_CryptoTransformKeyId receiver_mac_key_id; + unsigned char receiver_mac[CRYPTO_HMAC_SIZE]; +}; + +struct encrypted_data +{ + uint32_t length; + unsigned char data[1]; +}; + +struct seq_number +{ + int high; + unsigned low; +}; + +struct heartbeat +{ + struct submsg_header smhdr; + uint32_t readerId; + uint32_t writerId; + struct seq_number firstSN; + struct seq_number lastSN; + int count; +}; + +static struct heartbeat heartbeat; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void initialize_heartbeat(void) +{ + heartbeat.smhdr.id = 0x07; + heartbeat.smhdr.flags = 1; + heartbeat.smhdr.length = sizeof(heartbeat) - sizeof(struct submsg_header); + heartbeat.readerId = 0xA1B2C3D4; + heartbeat.writerId = 0xE5F6A7B0; + heartbeat.firstSN.high = 0; + heartbeat.firstSN.low = 1; + heartbeat.lastSN.high = 20; + heartbeat.lastSN.low = 500; + heartbeat.count = 1021; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + memset(&participant_security_attributes, 0, sizeof(participant_security_attributes)); + + local_participant_handle = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_participant_handle ? 0 : -1; +} + +static void unregister_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (local_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_participant_handle, &exception); + reset_exception(&exception); + } +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_participant_handle = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_handle, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_participant_handle ? 0 : -1; +} + +static void unregister_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (remote_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_participant_handle, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatareaderCryptoHandle register_local_datareader(DDS_Security_EndpointSecurityAttributes *datareader_security_attributes, DDS_Security_PropertySeq *datareader_properties) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + datareader_properties, + datareader_security_attributes, + &exception); + + if (reader_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static void unregister_datareader(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, reader_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatawriterCryptoHandle register_remote_datawriter(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + reader_crypto, + remote_participant_handle, + shared_secret_handle, + &exception); + + if (writer_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static void unregister_datawriter(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, writer_crypto, &exception); + reset_exception(&exception); + } +} + +static bool read_prefix(unsigned char **ptr, uint32_t *remain) +{ + struct submsg_header *prefix; + uint32_t hlen; + int swap; + + if (*remain < sizeof(struct submsg_header)) + { + printf("check_encoded_data: prefix missing\n"); + return false; + } + + prefix = (struct submsg_header *)(*ptr); + + if (prefix->id != SMID_SEC_PREFIX_KIND) + { + printf("check_encoded_data: prefix incorrect smid 0x%x02\n", prefix->id); + return false; + } + + if (prefix->flags & 0x01) + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + + hlen = swap ? ddsrt_bswap2u(prefix->length) : prefix->length; + + if (hlen != sizeof(struct crypto_header)) + { + printf("check_encoded_data: crypto_header missing\n"); + return false; + } + + *ptr += sizeof(struct submsg_header); + *remain -= (uint32_t)sizeof(struct submsg_header); + + return true; +} + +static bool read_header(struct crypto_header **header, unsigned char **ptr, uint32_t *remain) +{ + if (*remain < sizeof(struct crypto_header)) + { + printf("check_encoded_data: crypto_header too short\n"); + return false; + } + + *header = ddsrt_malloc(sizeof(struct crypto_header)); + memcpy(*header, *ptr, sizeof(struct crypto_header)); + + *ptr += sizeof(struct crypto_header); + *remain -= (uint32_t)sizeof(struct crypto_header); + + return true; +} + +static bool read_body(DDS_Security_OctetSeq *contents, bool encrypted, unsigned char **ptr, uint32_t *remain) +{ + struct submsg_header *body; + uint32_t hlen, clen; + int swap; + + if (*remain < sizeof(struct submsg_header)) + { + return false; + } + + body = (struct submsg_header *)(*ptr); + + if (body->flags & 0x01) + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + + hlen = swap ? ddsrt_bswap2u(body->length) : body->length; + + if (encrypted) + { + struct encrypted_data *enc; + + if (body->id != SMID_SEC_BODY_KIND) + { + printf("check_encoded_data: submessage SEC_BODY missing\n"); + return false; + } + enc = (struct encrypted_data *)(body + 1); + clen = ddsrt_fromBE4u(enc->length); + + contents->_length = contents->_maximum = clen; + contents->_buffer = &enc->data[0]; + } + else + { + if (body->id == SMID_SEC_BODY_KIND) + { + printf("check_encoded_data: submessage SEC_BODY not expected\n"); + return false; + } + clen = swap ? ddsrt_bswap2u(body->length) : body->length; + clen += (uint32_t)sizeof(struct submsg_header); + + contents->_length = contents->_maximum = clen; + contents->_buffer = *ptr; + } + *ptr += sizeof(struct submsg_header) + hlen; + *remain -= (uint32_t)sizeof(struct submsg_header) + hlen; + + return true; +} + +static bool read_postfix(unsigned char **ptr, uint32_t *remain) +{ + struct submsg_header *postfix; + + if (*remain < sizeof(struct submsg_header)) + { + printf("check_encoded_data: postfix missing\n"); + return false; + } + + postfix = (struct submsg_header *)(*ptr); + + if (postfix->id != SMID_SEC_POSTFIX_KIND) + { + printf("check_encoded_data: postfix invalid smid\n"); + return false; + } + + *ptr += sizeof(struct submsg_header); + *remain -= (uint32_t)sizeof(struct submsg_header); + + return true; +} + +static bool read_footer(struct crypto_footer **footer, unsigned char **ptr, uint32_t *remain) +{ + if (*remain < CRYPTO_HMAC_SIZE + sizeof(uint32_t)) + { + printf("check_encoded_data: crypto_footer incorrect size\n"); + return false; + } + + *footer = ddsrt_malloc(*remain); + memcpy(*footer, *ptr, *remain); + + /* length of reader specific macs is in BIG-ENDIAN format */ + (*footer)->length = ddsrt_fromBE4u((*footer)->length); + + return true; +} + +static bool check_encoded_data(DDS_Security_OctetSeq *data, bool encrypted, struct crypto_header **header, struct crypto_footer **footer, DDS_Security_OctetSeq *contents) +{ + bool result = true; + unsigned char *ptr = data->_buffer; + uint32_t remain = data->_length; + + result = read_prefix(&ptr, &remain); + if (result) + result = read_header(header, &ptr, &remain); + if (result) + result = read_body(contents, encrypted, &ptr, &remain); + if (result) + result = read_postfix(&ptr, &remain); + if (result) + result = read_footer(footer, &ptr, &remain); + + return result; +} + +static bool cipher_sign_data(const unsigned char *session_key, uint32_t key_size, const unsigned char *iv, const unsigned char *data, uint32_t data_len, unsigned char *tag) +{ + EVP_CIPHER_CTX *ctx; + unsigned char temp[32]; + int len; + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + { + ERR_print_errors_fp(stderr); + goto fail_ctx_new; + } + + /* initialize the cipher and set to AES GCM */ + if (key_size == 128) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + } + else if (key_size == 256) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + } + + /* Initialise key and IV */ + if (!EVP_EncryptInit_ex(ctx, NULL, NULL, session_key, iv)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + if (!EVP_EncryptUpdate(ctx, NULL, &len, data, (int) data_len)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + if (!EVP_EncryptFinal_ex(ctx, temp, &len)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + /* get the tag */ + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, CRYPTO_HMAC_SIZE, tag)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + /* clean up */ + EVP_CIPHER_CTX_free(ctx); + + return true; + +fail_encrypt: + EVP_CIPHER_CTX_free(ctx); +fail_ctx_new: + return false; +} + +static bool crypto_decrypt_data(uint32_t session_id, unsigned char *iv, DDS_Security_CryptoTransformKind transformation_kind, master_key_material *key_material, DDS_Security_OctetSeq *encrypted, DDS_Security_OctetSeq *decoded, unsigned char *tag) +{ + bool result = true; + EVP_CIPHER_CTX *ctx; + crypto_session_key_t session_key; + uint32_t key_size = crypto_get_key_size(CRYPTO_TRANSFORM_KIND(transformation_kind)); + int len = 0; + + if (!crypto_calculate_session_key_test(&session_key, session_id, key_material->master_salt, key_material->master_sender_key, key_material->transformation_kind)) + return false; + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (ctx) + { + if (key_size == 128) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else if (key_size == 256) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (result) + { + if (!EVP_DecryptInit_ex(ctx, NULL, NULL, session_key.data, iv)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptUpdate(ctx, decoded->_buffer, &len, encrypted->_buffer, (int) encrypted->_length)) + { + decoded->_length = (uint32_t) len; + } + else + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + if (!EVP_DecryptUpdate(ctx, NULL, &len, encrypted->_buffer, (int) encrypted->_length)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (result) + { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, CRYPTO_HMAC_SIZE, tag)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptFinal_ex(ctx, decoded->_buffer + len, &len)) + { + decoded->_length += (uint32_t) len; + } + else + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + unsigned char temp[32]; + if (!EVP_DecryptFinal_ex(ctx, temp, &len)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (ctx) + EVP_CIPHER_CTX_free(ctx); + + return result; +} + +static void prepare_endpoint_security_attributes_and_properties(DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_PropertySeq *properties, + uint32_t transformation_kind, + bool is_origin_authenticated) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + memset(properties, 0, sizeof(DDS_Security_PropertySeq)); + + attributes->is_discovery_protected = true; + + properties->_maximum = properties->_length = 1; + properties->_buffer = ddsrt_malloc(sizeof(DDS_Security_Property_t)); + + properties->_buffer[0].name = ddsrt_strdup("dds.sec.crypto.keysize"); + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC) + { + properties->_buffer[0].value = ddsrt_strdup("128"); + } + else + { + properties->_buffer[0].value = ddsrt_strdup("256"); + } + + switch (transformation_kind) + { + case CRYPTO_TRANSFORMATION_KIND_AES128_GCM: + case CRYPTO_TRANSFORMATION_KIND_AES256_GCM: + attributes->is_submessage_protected = true; + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + case CRYPTO_TRANSFORMATION_KIND_AES256_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES128_GMAC: + attributes->is_submessage_protected = true; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + default: + assert(0); + break; + } +} + +static session_key_material * get_datareader_session(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + local_datareader_crypto *reader_crypto_impl = (local_datareader_crypto *)reader_crypto; + return reader_crypto_impl->reader_session; +} + +static master_key_material * get_datawriter_key_material(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + remote_datawriter_crypto *writer_crypto_impl = (remote_datawriter_crypto *)writer_crypto; + return writer_crypto_impl->reader2writer_key_material; +} + +static void initialize_data_submessage(DDS_Security_OctetSeq *submsg) +{ + uint32_t length = sizeof(struct heartbeat); + unsigned char *buffer; + + buffer = ddsrt_malloc(length); + + memcpy(buffer, &heartbeat, length); + + submsg->_length = submsg->_maximum = length; + submsg->_buffer = buffer; +} + +static bool check_writer_sign(DDS_Security_DatareaderCryptoHandle writer_crypto, uint32_t session_id, uint32_t key_id, uint32_t key_size, unsigned char *init_vector, unsigned char *common_mac, unsigned char *hmac) +{ + master_key_material *keymat; + crypto_session_key_t key; + unsigned char md[CRYPTO_HMAC_SIZE]; + + keymat = get_datawriter_key_material(writer_crypto); + if (key_id != keymat->receiver_specific_key_id) + { + printf("check_writer_sign: key_id does not match\n"); + return false; + } + else if (!calculate_receiver_specific_key_test(&key, session_id, keymat->master_salt, keymat->master_receiver_specific_key, keymat->transformation_kind)) + { + printf("check_writer_sign: calculate key failed\n"); + return false; + } + else if (!cipher_sign_data(key.data, key_size, init_vector, common_mac, CRYPTO_HMAC_SIZE, md)) + { + return false; + } + else if (memcmp(hmac, md, CRYPTO_HMAC_SIZE) != 0) + { + printf("check_writer_sign: hmac incorrect\n"); + return false; + } + + return true; +} + +static bool check_writer_signing(DDS_Security_DatareaderCryptoHandleSeq *list, struct crypto_footer *footer, uint32_t session_id, unsigned char *init_vector, uint32_t key_size) +{ + struct receiver_specific_mac *rmac; + uint32_t key_id; + uint32_t i; + + if (footer->length != list->_length) + { + return false; + } + + rmac = (struct receiver_specific_mac *)(footer + 1); + + for (i = 0; i < list->_length; i++) + { + key_id = ddsrt_bswap4u(*(uint32_t *)rmac[i].receiver_mac_key_id); + if (!check_writer_sign(list->_buffer[i], session_id, key_id, key_size, init_vector, footer->common_mac, rmac[i].receiver_mac)) + { + return false; + } + } + + return true; +} + +static void suite_encode_datareader_submessage_init(void) +{ + allocate_shared_secret(); + initialize_heartbeat(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); +} + +static void suite_encode_datareader_submessage_fini(void) +{ + unregister_remote_participant(); + unregister_local_participant(); + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void encode_datareader_submessage_not_signed(uint32_t transformation_kind) +{ + DDS_Security_boolean result; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatawriterCryptoHandleSeq writer_list; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + DDS_Security_OctetSeq data; + session_key_material *session_keys; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + uint32_t session_id; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + bool is_encrypted; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + + is_encrypted = (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES256_GCM); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, transformation_kind, false); + + initialize_data_submessage(&plain_buffer); + + reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(reader_crypto != 0); + + session_keys = get_datareader_session(reader_crypto); + + writer_crypto = register_remote_datawriter(reader_crypto); + CU_ASSERT_FATAL(writer_crypto != 0); + + writer_list._length = writer_list._maximum = 1; + writer_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + writer_list._buffer[0] = writer_crypto; + + /* Now call the function. */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + reader_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + result = check_encoded_data(&encoded_buffer, is_encrypted, &header, &footer, &data); + CU_ASSERT_FATAL(result); + + CU_ASSERT(header->transform_identifier.transformation_kind[3] == transformation_kind); + + session_id = ddsrt_bswap4u(*(uint32_t *)header->session_id); + + if (is_encrypted) + { + decoded_buffer._buffer = ddsrt_malloc(plain_buffer._length); + decoded_buffer._length = 0; + decoded_buffer._maximum = plain_buffer._length; + + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, &decoded_buffer, footer->common_mac); + + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + CU_ASSERT(memcmp(plain_buffer._buffer, decoded_buffer._buffer, plain_buffer._length) == 0); + + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + } + else + { + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, NULL, footer->common_mac); + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + CU_ASSERT(memcmp(plain_buffer._buffer, data._buffer, plain_buffer._length) == 0); + } + + unregister_datawriter(writer_list._buffer[0]); + writer_list._buffer[0] = 0; + + unregister_datareader(reader_crypto); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatawriterCryptoHandleSeq_deinit(&writer_list); + + ddsrt_free(footer); + ddsrt_free(header); + + DDS_Security_PropertySeq_deinit(&datareader_properties); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, encode_256, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, encode_128, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, no_encode_256, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, no_encode_128, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +static void encode_datareader_submessage_sign(uint32_t transformation_kind) +{ + const uint32_t WRITERS_CNT = 4u; + DDS_Security_boolean result; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatawriterCryptoHandleSeq writer_list; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + DDS_Security_OctetSeq data; + DDS_Security_OctetSeq *buffer; + session_key_material *session_keys; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + uint32_t session_id; + uint32_t i; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + bool is_encrypted; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES256_GCM) + { + is_encrypted = true; + } + else + { + is_encrypted = false; + } + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, transformation_kind, true); + + initialize_data_submessage(&plain_buffer); + + reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(reader_crypto != 0); + + session_keys = get_datareader_session(reader_crypto); + + writer_list._length = writer_list._maximum = WRITERS_CNT; + writer_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(4); + for (i = 0; i < WRITERS_CNT; i++) + { + writer_crypto = register_remote_datawriter(reader_crypto); + CU_ASSERT_FATAL(writer_crypto != 0); + writer_list._buffer[i] = writer_crypto; + } + + /* Now call the function. */ + + buffer = &plain_buffer; + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + buffer, + reader_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("writer_crypto: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + buffer = NULL; + + result = check_encoded_data(&encoded_buffer, is_encrypted, &header, &footer, &data); + CU_ASSERT_FATAL(result); + + CU_ASSERT(header->transform_identifier.transformation_kind[3] == transformation_kind); + + session_id = ddsrt_bswap4u(*(uint32_t *)header->session_id); + + if (is_encrypted) + { + decoded_buffer._buffer = ddsrt_malloc(plain_buffer._length); + decoded_buffer._length = 0; + decoded_buffer._maximum = plain_buffer._length; + + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, &decoded_buffer, footer->common_mac); + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + CU_ASSERT(memcmp(plain_buffer._buffer, decoded_buffer._buffer, plain_buffer._length) == 0); + + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + } + else + { + result = crypto_decrypt_data(session_id, header->session_id, header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, NULL, footer->common_mac); + + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(memcmp(plain_buffer._buffer, data._buffer, plain_buffer._length) == 0); + } + + printf("num hmacs = %u\n", footer->length); + + CU_ASSERT(check_writer_signing(&writer_list, footer, session_id, header->session_id, session_keys->key_size)); + + for (i = 0; i < WRITERS_CNT; i++) + { + unregister_datawriter(writer_list._buffer[i]); + writer_list._buffer[i] = 0; + } + + unregister_datareader(reader_crypto); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&writer_list); + + ddsrt_free(footer); + ddsrt_free(header); + + DDS_Security_PropertySeq_deinit(&datareader_properties); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, encode_sign_256, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, encode_sign_128, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, no_encode_sign_256, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, no_encode_sign_128, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, invalid_args, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_DatawriterCryptoHandle reader_crypto; + DDS_Security_DatareaderCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandleSeq writer_list; + DDS_Security_DatareaderCryptoHandleSeq empty_writer_list; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + + initialize_data_submessage(&plain_buffer); + + memset(&empty_writer_list, 0, sizeof(empty_writer_list)); + + reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(reader_crypto != 0); + + writer_crypto = register_remote_datawriter(reader_crypto); + CU_ASSERT_FATAL(writer_crypto != 0); + + writer_list._length = writer_list._maximum = 1; + writer_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + writer_list._buffer[0] = writer_crypto; + + /* encoded_buffer NULL */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + NULL, + &plain_buffer, + reader_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* plain_buffer NULL */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + NULL, + writer_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto 0 */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + 0, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto unknown */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + 1, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* reader crypto list NULL*/ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + NULL, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* empty reader crypto list */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &empty_writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto list with invalid writer crypto */ + writer_list._buffer[0] = 0; + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto list with unknown writer crypto*/ + writer_list._buffer[0] = 1; + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + unregister_datawriter(writer_list._buffer[0]); + writer_list._buffer[0] = 0; + + unregister_datareader(reader_crypto); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_DatawriterCryptoHandleSeq_deinit(&writer_list); + DDS_Security_PropertySeq_deinit(&datareader_properties); +} + diff --git a/src/security/builtin_plugins/tests/encode_datawriter_submessage/src/encode_datawriter_submessage_utests.c b/src/security/builtin_plugins/tests/encode_datawriter_submessage/src/encode_datawriter_submessage_utests.c new file mode 100644 index 0000000..e4c7428 --- /dev/null +++ b/src/security/builtin_plugins/tests/encode_datawriter_submessage/src/encode_datawriter_submessage_utests.c @@ -0,0 +1,1348 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_objects.h" +#include "crypto_utils.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_particpant_crypto = 0; +static DDS_Security_ParticipantCryptoHandle remote_particpant_crypto = 0; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static const char *sample_test_data = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy"; + +struct submsg_header +{ + unsigned char id; + unsigned char flags; + uint16_t length; +}; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[4]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + uint32_t length; +}; + +struct receiver_specific_mac +{ + DDS_Security_CryptoTransformKeyId receiver_mac_key_id; + unsigned char receiver_mac[CRYPTO_HMAC_SIZE]; +}; + +struct encrypted_data +{ + uint32_t length; + unsigned char data[1]; +}; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + memset(&participant_security_attributes, 0, sizeof(participant_security_attributes)); + + local_particpant_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_particpant_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_particpant_crypto ? 0 : -1; +} + +static void unregister_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (local_particpant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_particpant_crypto, &exception); + reset_exception(&exception); + } +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_particpant_crypto = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_particpant_crypto, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_particpant_crypto == 0) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_particpant_crypto ? 0 : -1; +} + +static void prepare_endpoint_security_attributes_and_properties(DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_PropertySeq *properties, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + bool is_origin_authenticated) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + memset(properties, 0, sizeof(DDS_Security_PropertySeq)); + + attributes->is_discovery_protected = true; + + properties->_maximum = properties->_length = 1; + properties->_buffer = ddsrt_malloc(sizeof(DDS_Security_Property_t)); + + properties->_buffer[0].name = ddsrt_strdup("dds.sec.crypto.keysize"); + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC) + { + properties->_buffer[0].value = ddsrt_strdup("128"); + } + else + { + properties->_buffer[0].value = ddsrt_strdup("256"); + } + + switch (transformation_kind) + { + case CRYPTO_TRANSFORMATION_KIND_AES128_GCM: + case CRYPTO_TRANSFORMATION_KIND_AES256_GCM: + attributes->is_submessage_protected = true; + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + case CRYPTO_TRANSFORMATION_KIND_AES256_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES128_GMAC: + attributes->is_submessage_protected = true; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + default: + assert(0); + break; + } +} + +static void unregister_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (remote_particpant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_particpant_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatawriterCryptoHandle register_local_datawriter(DDS_Security_EndpointSecurityAttributes *datawriter_security_attributes, DDS_Security_PropertySeq *datawriter_properties) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_particpant_crypto, + datawriter_properties, + datawriter_security_attributes, + &exception); + + if (writer_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static void unregister_datawriter(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, writer_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatareaderCryptoHandle register_remote_datareader(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + writer_crypto, + remote_particpant_crypto, + shared_secret_handle, + true, + &exception); + + if (reader_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static void unregister_datareader(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, reader_crypto, &exception); + reset_exception(&exception); + } +} + +static bool read_prefix(unsigned char **ptr, uint32_t *remain) +{ + struct submsg_header *prefix; + uint32_t hlen; + int swap; + + if (*remain < sizeof(struct submsg_header)) + { + printf("check_encoded_data: prefix missing\n"); + return false; + } + + prefix = (struct submsg_header *)(*ptr); + + if (prefix->id != SMID_SEC_PREFIX_KIND) + { + printf("check_encoded_data: prefix incorrect smid 0x%x02\n", prefix->id); + return false; + } + + if (prefix->flags & 0x01) + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + + hlen = swap ? ddsrt_bswap2u(prefix->length) : prefix->length; + + if (hlen != sizeof(struct crypto_header)) + { + printf("check_encoded_data: crypto_header missing\n"); + return false; + } + + *ptr += sizeof(struct submsg_header); + *remain -= (uint32_t)sizeof(struct submsg_header); + + return true; +} + +static bool read_header(struct crypto_header **header, unsigned char **ptr, uint32_t *remain) +{ + if (*remain < sizeof(struct crypto_header)) + { + printf("check_encoded_data: crypto_header too short\n"); + return false; + } + + *header = ddsrt_malloc(sizeof(struct crypto_header)); + memcpy(*header, *ptr, sizeof(struct crypto_header)); + + *ptr += sizeof(struct crypto_header); + *remain -= (uint32_t)sizeof(struct crypto_header); + + return true; +} + +static bool read_body(DDS_Security_OctetSeq *contents, bool encrypted, unsigned char **ptr, uint32_t *remain) +{ + struct submsg_header *body; + uint32_t hlen, clen; + int swap; + + if (*remain < sizeof(struct submsg_header)) + { + return false; + } + + body = (struct submsg_header *)(*ptr); + + if (body->flags & 0x01) + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + + hlen = swap ? ddsrt_bswap2u(body->length) : body->length; + + if (encrypted) + { + struct encrypted_data *enc; + + if (body->id != SMID_SEC_BODY_KIND) + { + printf("check_encoded_data: submessage SEC_BODY missing\n"); + return false; + } + enc = (struct encrypted_data *)(body + 1); + clen = ddsrt_fromBE4u(enc->length); + + contents->_length = contents->_maximum = clen; + contents->_buffer = &enc->data[0]; + } + else + { + if (body->id == SMID_SEC_BODY_KIND) + { + printf("check_encoded_data: submessage SEC_BODY not expected\n"); + return false; + } + clen = swap ? ddsrt_bswap2u(body->length) : body->length; + clen += (uint32_t)sizeof(struct submsg_header); + + contents->_length = contents->_maximum = clen; + contents->_buffer = *ptr; + } + *ptr += sizeof(struct submsg_header) + hlen; + *remain -= (uint32_t)sizeof(struct submsg_header) + hlen; + + return true; +} + +static bool read_postfix(unsigned char **ptr,uint32_t *remain) +{ + struct submsg_header *postfix; + + if (*remain < sizeof(struct submsg_header)) + { + printf("check_encoded_data: postfix missing\n"); + return false; + } + + postfix = (struct submsg_header *)(*ptr); + + if (postfix->id != SMID_SEC_POSTFIX_KIND) + { + printf("check_encoded_data: postfix invalid smid\n"); + return false; + } + + *ptr += sizeof(struct submsg_header); + *remain -= (uint32_t)sizeof(struct submsg_header); + + return true; +} + +static bool read_footer(struct crypto_footer **footer, unsigned char **ptr, uint32_t *remain) +{ + if (*remain < CRYPTO_HMAC_SIZE + sizeof(uint32_t)) + { + printf("check_encoded_data: crypto_footer incorrect size\n"); + return false; + } + + *footer = ddsrt_malloc(*remain); + memcpy(*footer, *ptr, *remain); + + /* length of reader specific macs is in BIG-ENDIAN format */ + (*footer)->length = ddsrt_fromBE4u((*footer)->length); + + return true; +} + +static bool check_encoded_data(DDS_Security_OctetSeq *data, bool encrypted, struct crypto_header **header, struct crypto_footer **footer, DDS_Security_OctetSeq *contents) +{ + bool result = true; + unsigned char *ptr = data->_buffer; + uint32_t remain = data->_length; + + result = read_prefix(&ptr, &remain); + if (result) + result = read_header(header, &ptr, &remain); + if (result) + result = read_body(contents, encrypted, &ptr, &remain); + if (result) + result = read_postfix(&ptr, &remain); + if (result) + result = read_footer(footer, &ptr, &remain); + + return result; +} + +static bool cipher_sign_data(const unsigned char *session_key, uint32_t key_size, const unsigned char *iv, const unsigned char *data, uint32_t data_len, unsigned char *tag) +{ + EVP_CIPHER_CTX *ctx; + unsigned char temp[32]; + int len; + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + { + ERR_print_errors_fp(stderr); + goto fail_ctx_new; + } + + /* initialize the cipher and set to AES GCM */ + if (key_size == 128) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + } + else if (key_size == 256) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + } + + /* Initialise key and IV */ + if (!EVP_EncryptInit_ex(ctx, NULL, NULL, session_key, iv)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + if (!EVP_EncryptUpdate(ctx, NULL, &len, data, (int)data_len)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + if (!EVP_EncryptFinal_ex(ctx, temp, &len)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + /* get the tag */ + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, CRYPTO_HMAC_SIZE, tag)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + /* clean up */ + EVP_CIPHER_CTX_free(ctx); + + return true; + +fail_encrypt: + EVP_CIPHER_CTX_free(ctx); +fail_ctx_new: + return false; +} + +static bool crypto_decrypt_data(uint32_t session_id, unsigned char *iv, DDS_Security_CryptoTransformKind transformation_kind, master_key_material *key_material, DDS_Security_OctetSeq *encrypted, DDS_Security_OctetSeq *decoded, unsigned char *tag) +{ + bool result = true; + EVP_CIPHER_CTX *ctx; + crypto_session_key_t session_key; + uint32_t key_size = crypto_get_key_size(CRYPTO_TRANSFORM_KIND(transformation_kind)); + int len = 0; + + if (!crypto_calculate_session_key_test(&session_key, session_id, key_material->master_salt, key_material->master_sender_key, key_material->transformation_kind)) + return false; + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (ctx) + { + if (key_size == 128) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else if (key_size == 256) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (result) + { + if (!EVP_DecryptInit_ex(ctx, NULL, NULL, session_key.data, iv)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptUpdate(ctx, decoded->_buffer, &len, encrypted->_buffer, (int)encrypted->_length)) + { + decoded->_length = (uint32_t) len; + } + else + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + if (!EVP_DecryptUpdate(ctx, NULL, &len, encrypted->_buffer, (int) encrypted->_length)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (result) + { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, CRYPTO_HMAC_SIZE, tag)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptFinal_ex(ctx, decoded->_buffer + len, &len)) + { + decoded->_length += (uint32_t) len; + } + else + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + unsigned char temp[32]; + if (!EVP_DecryptFinal_ex(ctx, temp, &len)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (ctx) + EVP_CIPHER_CTX_free(ctx); + + return result; +} + +static session_key_material * get_datawriter_session(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + local_datawriter_crypto *writer_crypto_impl = (local_datawriter_crypto *)writer_crypto; + return writer_crypto_impl->writer_session_message; +} + +static master_key_material * get_datareader_key_material(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + remote_datareader_crypto *reader_crypto_impl = (remote_datareader_crypto *)reader_crypto; + return reader_crypto_impl->writer2reader_key_material_message; +} + +static void initialize_data_submessage(DDS_Security_OctetSeq *submsg, bool be) +{ + size_t length = strlen(sample_test_data) + 1; + struct submsg_header *header; + int swap; + unsigned char *buffer, *ptr; + + if (be) + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + + buffer = ddsrt_malloc(length + sizeof(struct submsg_header)); + header = (struct submsg_header *)buffer; + header->id = 0x15; + header->flags = be ? 0x00 : 0x01; + header->length = swap ? ddsrt_bswap2u((uint16_t)length) : (uint16_t)length; + ptr = (unsigned char *)(header + 1); + + memcpy((char *)ptr, sample_test_data, length); + + submsg->_length = submsg->_maximum = (uint32_t)(length + sizeof(struct submsg_header)); + submsg->_buffer = buffer; +} + +static bool check_reader_sign( + DDS_Security_DatareaderCryptoHandle reader_crypto, + uint32_t session_id, + uint32_t key_id, + uint32_t key_size, + unsigned char *init_vector, + unsigned char *common_mac, + unsigned char *hmac) +{ + master_key_material *keymat; + crypto_session_key_t key; + unsigned char md[CRYPTO_HMAC_SIZE]; + + keymat = get_datareader_key_material(reader_crypto); + + if (key_id != keymat->receiver_specific_key_id) + { + printf("check_reader_sign: key_id does not match\n"); + return false; + } + else if (!calculate_receiver_specific_key_test(&key, session_id, keymat->master_salt, keymat->master_receiver_specific_key, keymat->transformation_kind)) + { + printf("check_reader_sign: calculate key failed\n"); + return false; + } + else if (!cipher_sign_data(key.data, key_size, init_vector, common_mac, CRYPTO_HMAC_SIZE, md)) + { + return false; + } + else if (memcmp(hmac, md, CRYPTO_HMAC_SIZE) != 0) + { + printf("check_reader_sign: hmac incorrect\n"); + return false; + } + + return true; +} + +static bool check_reader_signing(DDS_Security_DatareaderCryptoHandleSeq *list, struct crypto_footer *footer, uint32_t session_id, unsigned char *init_vector, uint32_t key_size) +{ + struct receiver_specific_mac *rmac; + uint32_t key_id; + uint32_t i; + + if (footer->length != list->_length) + { + return false; + } + + rmac = (struct receiver_specific_mac *)(footer + 1); + + for (i = 0; i < list->_length; i++) + { + key_id = ddsrt_bswap4u(*(uint32_t *)rmac[i].receiver_mac_key_id); + if (!check_reader_sign(list->_buffer[i], session_id, key_id, key_size, init_vector, footer->common_mac, rmac[i].receiver_mac)) + { + return false; + } + } + + return true; +} + +static void suite_encode_datawriter_submessage_init(void) +{ + allocate_shared_secret(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); +} + +static void suite_encode_datawriter_submessage_fini(void) +{ + unregister_remote_participant(); + unregister_local_participant(); + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void encode_datawriter_submessage_not_signed(DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + DDS_Security_boolean result; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + int32_t index; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + DDS_Security_OctetSeq data; + + session_key_material *session_keys; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + uint32_t session_id; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + bool is_encrypted; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES256_GCM) + { + is_encrypted = true; + } + else + { + is_encrypted = false; + } + + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, transformation_kind, false); + + initialize_data_submessage(&plain_buffer, false); + + writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(writer_crypto != 0); + + session_keys = get_datawriter_session(writer_crypto); + + reader_crypto = register_remote_datareader(writer_crypto); + CU_ASSERT_FATAL(reader_crypto != 0); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = reader_crypto; + index = 0; + + /* Now call the function. */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + result = check_encoded_data(&encoded_buffer, is_encrypted, &header, &footer, &data); + CU_ASSERT_FATAL(result); + + CU_ASSERT(header->transform_identifier.transformation_kind[3] == transformation_kind); + + session_id = ddsrt_bswap4u(*(uint32_t *)header->session_id); + + if (is_encrypted) + { + decoded_buffer._buffer = ddsrt_malloc(plain_buffer._length); + decoded_buffer._length = 0; + decoded_buffer._maximum = plain_buffer._length; + + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, &decoded_buffer, footer->common_mac); + + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + CU_ASSERT(memcmp(plain_buffer._buffer, decoded_buffer._buffer, plain_buffer._length) == 0); + + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + } + else + { + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, NULL, footer->common_mac); + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + CU_ASSERT(memcmp(plain_buffer._buffer, data._buffer, plain_buffer._length) == 0); + } + + unregister_datareader(reader_list._buffer[0]); + reader_list._buffer[0] = 0; + + unregister_datawriter(writer_crypto); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + + ddsrt_free(datawriter_properties._buffer[0].name); + ddsrt_free(datawriter_properties._buffer[0].value); + ddsrt_free(datawriter_properties._buffer); + ddsrt_free(footer); + ddsrt_free(header); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, encode_256, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, encode_128, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, no_encode_256, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, no_encode_128, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +static void encode_datawriter_submessage_sign(DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + const uint32_t READERS_CNT = 4u; + DDS_Security_boolean result; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + int32_t index; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + DDS_Security_OctetSeq data; + DDS_Security_OctetSeq *buffer; + session_key_material *session_keys; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + uint32_t session_id; + uint32_t i; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + bool is_encrypted; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES256_GCM) + { + is_encrypted = true; + } + else + { + is_encrypted = false; + } + + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, transformation_kind, true); + + initialize_data_submessage(&plain_buffer, false); + + writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(writer_crypto != 0); + + session_keys = get_datawriter_session(writer_crypto); + + reader_list._length = reader_list._maximum = READERS_CNT; + reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(4); + for (i = 0; i < READERS_CNT; i++) + { + reader_crypto = register_remote_datareader(writer_crypto); + CU_ASSERT_FATAL(reader_crypto != 0); + reader_list._buffer[i] = reader_crypto; + } + index = 0; + + /* Now call the function. */ + + buffer = &plain_buffer; + while (index != (int32_t)READERS_CNT) + { + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + buffer, + writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + buffer = NULL; + } + + result = check_encoded_data(&encoded_buffer, is_encrypted, &header, &footer, &data); + CU_ASSERT_FATAL(result); + + CU_ASSERT(header->transform_identifier.transformation_kind[3] == transformation_kind); + + session_id = ddsrt_bswap4u(*(uint32_t *)header->session_id); + + if (is_encrypted) + { + decoded_buffer._buffer = ddsrt_malloc(plain_buffer._length); + decoded_buffer._length = 0; + decoded_buffer._maximum = plain_buffer._length; + + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, &decoded_buffer, footer->common_mac); + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + CU_ASSERT(memcmp(plain_buffer._buffer, decoded_buffer._buffer, plain_buffer._length) == 0); + + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + } + else + { + result = crypto_decrypt_data(session_id, header->session_id, header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, NULL, footer->common_mac); + + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(memcmp(plain_buffer._buffer, data._buffer, plain_buffer._length) == 0); + } + + printf("num hmacs = %u\n", footer->length); + + CU_ASSERT(check_reader_signing(&reader_list, footer, session_id, header->session_id, session_keys->key_size)); + + for (i = 0; i < READERS_CNT; i++) + { + unregister_datareader(reader_list._buffer[i]); + reader_list._buffer[i] = 0; + } + + unregister_datawriter(writer_crypto); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + + ddsrt_free(datawriter_properties._buffer[0].name); + ddsrt_free(datawriter_properties._buffer[0].value); + ddsrt_free(datawriter_properties._buffer); + ddsrt_free(footer); + ddsrt_free(header); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, encode_sign_256, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, encode_sign_128, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, no_encode_sign_256, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, no_encode_sign_128, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, invalid_args, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + DDS_Security_DatareaderCryptoHandleSeq empty_reader_list; + int32_t index; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + + initialize_data_submessage(&plain_buffer, false); + memset(&empty_reader_list, 0, sizeof(empty_reader_list)); + + writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(writer_crypto != 0); + + //set_protection_kind(writer_crypto, DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION); + + reader_crypto = register_remote_datareader(writer_crypto); + CU_ASSERT_FATAL(reader_crypto != 0); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = reader_crypto; + index = 0; + + /* encoded_buffer NULL */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + NULL, + &plain_buffer, + writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* plain_buffer NULL */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + NULL, + writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto 0 */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + 0, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto unknown */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + 1, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* reader crypto list NULL*/ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + NULL, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* empty reader crypto list */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &empty_reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* reader crypto list with invalid reader crypto */ + reader_list._buffer[0] = 0; + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* reader crypto list with unknown reader crypto*/ + reader_list._buffer[0] = 1; + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + reader_list._buffer[0] = reader_crypto; + + /* index NULL*/ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &reader_list, + NULL, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid index */ + index = 2; + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + unregister_datareader(reader_list._buffer[0]); + reader_list._buffer[0] = 0; + + unregister_datawriter(writer_crypto); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + ddsrt_free(datawriter_properties._buffer[0].name); + ddsrt_free(datawriter_properties._buffer[0].value); + ddsrt_free(datawriter_properties._buffer); + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); +} + diff --git a/src/security/builtin_plugins/tests/encode_rtps_message/src/encode_rtps_message_utests.c b/src/security/builtin_plugins/tests/encode_rtps_message/src/encode_rtps_message_utests.c new file mode 100644 index 0000000..d65a0c7 --- /dev/null +++ b/src/security/builtin_plugins/tests/encode_rtps_message/src/encode_rtps_message_utests.c @@ -0,0 +1,1322 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_objects.h" +#include "crypto_utils.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identities[] = {2, 3, 4, 5}; + +static DDS_Security_ParticipantCryptoHandle local_particpant_crypto = 0; +static DDS_Security_ParticipantCryptoHandle remote_particpant_cryptos[4]; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static const char *sample_test_data = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy"; + +static const char *RTPS_HEADER = "RTPS abcdefghijklmno"; + +struct submsg_header +{ + unsigned char id; + unsigned char flags; + uint16_t length; +}; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[4]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + uint32_t length; +}; + +struct receiver_specific_mac +{ + DDS_Security_CryptoTransformKeyId receiver_mac_key_id; + unsigned char receiver_mac[CRYPTO_HMAC_SIZE]; +}; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void print_octets(const char *msg, const unsigned char *data, uint32_t sz) +{ + uint32_t i; + printf("%s: ", msg); + for (i = 0; i < sz; i++) + { + printf("%02x", data[i]); + } + printf("\n"); +} + +static int register_local_participant(DDS_Security_ParticipantSecurityAttributes *participant_security_attributes, DDS_Security_PropertySeq *participant_properties) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 2; /* dummy but valid */ + + local_particpant_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + participant_properties, + participant_security_attributes, + &exception); + + if (local_particpant_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_particpant_crypto ? 0 : -1; +} + +static void unregister_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (local_particpant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_particpant_crypto, &exception); + reset_exception(&exception); + } +} + +static int register_remote_participants(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + unsigned i; + int result = 0; + + for (i = 0; i < 4; ++i) + { + remote_particpant_cryptos[i] = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_particpant_crypto, + remote_participant_identities[i], + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_particpant_cryptos[i] == 0) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + result = 1; + break; + } + } + + return result; +} + +static void +unregister_remote_participants(void) +{ + unsigned i; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + for (i = 0; i < 4; ++i) + { + if (remote_particpant_cryptos[i]) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_particpant_cryptos[i], &exception); + reset_exception(&exception); + } + } +} + +static bool check_encoded_data(DDS_Security_OctetSeq *data, bool encrypted, struct crypto_header **header, struct crypto_footer **footer, DDS_Security_OctetSeq *contents) +{ + struct submsg_header *prefix; + struct submsg_header *postfix; + struct submsg_header *body; + unsigned char *ptr = data->_buffer; + uint32_t remain = data->_length; + uint32_t hlen, clen, dlen; + int swap; + + if (remain < 20) + { + printf("check_encoded_data: RTPS header missing\n"); + goto fail_prefix; + } + + /* rtps header first */ + if (memcmp(ptr, RTPS_HEADER, strlen(RTPS_HEADER)) != 0) + { + printf("check_encoded_data: RTPS header invalid\n"); + goto fail_prefix; + } + + if (remain < sizeof(struct submsg_header)) + { + printf("check_encoded_data: prefix missing\n"); + goto fail_prefix; + } + + remain -= 20; /* rtps header */ + ptr += 20; + + prefix = (struct submsg_header *)ptr; + + if (prefix->id != SMID_SRTPS_PREFIX_KIND) + { + printf("check_encoded_data: prefix incorrect smid 0x%x02\n", prefix->id); + goto fail_prefix; + } + + if (prefix->flags & 0x01) + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + + hlen = swap ? ddsrt_bswap2u(prefix->length) : prefix->length; + + if (hlen != sizeof(struct crypto_header)) + { + printf("check_encoded_data: crypto_header missing\n"); + goto fail_prefix; + } + + ptr += sizeof(struct submsg_header); + remain -= (uint32_t)sizeof(struct submsg_header); + + if (remain < sizeof(struct crypto_header)) + { + printf("check_encoded_data: crypto_header too short\n"); + goto fail_prefix; + } + + *header = ddsrt_malloc(sizeof(struct crypto_header)); + memcpy(*header, ptr, sizeof(struct crypto_header)); + + ptr += sizeof(struct crypto_header); + remain -= (uint32_t)sizeof(struct crypto_header); + + if (remain < sizeof(struct submsg_header)) + { + goto fail_body; + } + + if (encrypted) + { + body = (struct submsg_header *)ptr; + if (body->id != SMID_SEC_BODY_KIND) + { + printf("check_encoded_data: submessage SEC_BODY missing\n"); + goto fail_body; + } + ptr += sizeof(struct submsg_header); + remain -= (uint32_t)sizeof(struct submsg_header); + + dlen = ddsrt_fromBE4u(*(uint32_t *)ptr); + + clen = swap ? ddsrt_bswap2u(body->length) : body->length; + if (dlen > clen) + { + printf("check_encoded_data: encrypted body length incorrect\n"); + goto fail_body; + } + + ptr += sizeof(uint32_t); + remain -= (uint32_t)sizeof(uint32_t); + + contents->_length = contents->_maximum = dlen; + contents->_buffer = ptr; + + ptr += clen - sizeof(uint32_t); + } + else + { + body = (struct submsg_header *)(ptr + 24); /* header after info_src */ + if (body->id == SMID_SEC_BODY_KIND) + { + printf("check_encoded_data: submessage SEC_BODY not expected\n"); + goto fail_body; + } + clen = swap ? ddsrt_bswap2u(body->length) : body->length; + clen += (uint32_t)sizeof(struct submsg_header) + 24; + + contents->_length = contents->_maximum = clen; + contents->_buffer = ptr; + + ptr += clen; + } + + if (clen > remain) + { + printf("check_encoded_data: payload invalid size\n"); + goto fail_body; + } + + remain -= contents->_length; + + if (remain < sizeof(struct submsg_header)) + { + printf("check_encoded_data: postfix missing\n"); + goto fail_postfix; + } + + postfix = (struct submsg_header *)ptr; + + if (postfix->id != SMID_SRTPS_POSTFIX_KIND) + { + printf("check_encoded_data: postfix invalid smid\n"); + goto fail_postfix; + } + + ptr += sizeof(struct submsg_header); + remain -= (uint32_t)sizeof(struct submsg_header); + + if (remain < CRYPTO_HMAC_SIZE + sizeof(uint32_t)) + { + printf("check_encoded_data: crypto_footer incorrect size\n"); + goto fail_postfix; + } + + *footer = ddsrt_malloc(remain); + memcpy(*footer, ptr, remain); + + /* length of reader specific macs is in BIG-ENDIAN format */ + (*footer)->length = ddsrt_fromBE4u((*footer)->length); + + return true; + +fail_postfix: +fail_body: + ddsrt_free(*header); +fail_prefix: + return false; +} + +static bool +cipher_sign_data( + const unsigned char *session_key, + uint32_t key_size, + const unsigned char *iv, + const unsigned char *data, + uint32_t data_len, + unsigned char *tag) +{ + EVP_CIPHER_CTX *ctx; + unsigned char temp[32]; + int len; + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + { + ERR_print_errors_fp(stderr); + goto fail_ctx_new; + } + + /* initialize the cipher and set to AES GCM */ + if (key_size == 128) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + } + else if (key_size == 256) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + } + + /* Initialise key and IV */ + if (!EVP_EncryptInit_ex(ctx, NULL, NULL, session_key, iv)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + if (!EVP_EncryptUpdate(ctx, NULL, &len, data, (int) data_len)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + if (!EVP_EncryptFinal_ex(ctx, temp, &len)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + /* get the tag */ + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, CRYPTO_HMAC_SIZE, tag)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + /* clean up */ + EVP_CIPHER_CTX_free(ctx); + + return true; + +fail_encrypt: + EVP_CIPHER_CTX_free(ctx); +fail_ctx_new: + return false; +} + +static bool +crypto_decrypt_data( + uint32_t session_id, + unsigned char *iv, + DDS_Security_CryptoTransformKind transformation_kind, + master_key_material *key_material, + DDS_Security_OctetSeq *encrypted, + DDS_Security_OctetSeq *decoded, + unsigned char *tag) +{ + bool result = true; + EVP_CIPHER_CTX *ctx; + crypto_session_key_t session_key; + uint32_t key_size = crypto_get_key_size(CRYPTO_TRANSFORM_KIND(transformation_kind)); + int len = 0; + + if (!crypto_calculate_session_key_test(&session_key, session_id, key_material->master_salt, key_material->master_sender_key, key_material->transformation_kind)) + return false; + + printf("SessionId: %08x\n", session_id); + print_octets("SessionKey", (const unsigned char *)session_key.data, key_size >> 3); + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (ctx) + { + if (key_size == 128) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else if (key_size == 256) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (result) + { + if (!EVP_DecryptInit_ex(ctx, NULL, NULL, session_key.data, iv)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptUpdate(ctx, decoded->_buffer, &len, encrypted->_buffer, (int) encrypted->_length)) + { + decoded->_length = (uint32_t) len; + } + else + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + if (!EVP_DecryptUpdate(ctx, NULL, &len, encrypted->_buffer, (int) encrypted->_length)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (result) + { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, CRYPTO_HMAC_SIZE, tag)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptFinal_ex(ctx, decoded->_buffer + len, &len)) + { + decoded->_length += (uint32_t) len; + } + else + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + unsigned char temp[32]; + if (!EVP_DecryptFinal_ex(ctx, temp, &len)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (ctx) + EVP_CIPHER_CTX_free(ctx); + + return result; +} + +static session_key_material * get_local_participant_session(DDS_Security_ParticipantCryptoHandle participant_crypto) +{ + local_participant_crypto *participant_crypto_impl = (local_participant_crypto *)participant_crypto; + return participant_crypto_impl->session; +} + +static participant_key_material * keymaterial_table_find(struct CryptoObjectTable *table, uint64_t handle) +{ + CryptoObject *object; + assert(table); + + ddsrt_mutex_lock(&table->lock); + object = table->findfnc(table, &handle); + ddsrt_mutex_unlock(&table->lock); + + return (participant_key_material *)object; +} + +static master_key_material * get_remote_participant_key_material(DDS_Security_ParticipantCryptoHandle participant_crypto) +{ + participant_key_material *key_material; + remote_participant_crypto *participant_crypto_impl = (remote_participant_crypto *)participant_crypto; + + key_material = (participant_key_material *)keymaterial_table_find(participant_crypto_impl->key_material, (uint64_t) local_particpant_crypto); + if (!key_material) + { + return NULL; + } + else + { + return key_material->local_P2P_key_material; + } +} + +static void set_protection_kind(DDS_Security_ParticipantCryptoHandle participant_crypto, DDS_Security_ProtectionKind protection_kind) +{ + local_participant_crypto *paricipant_crypto_impl = (local_participant_crypto *)participant_crypto; + paricipant_crypto_impl->rtps_protection_kind = protection_kind; +} + +static void set_remote_participant_protection_kind(DDS_Security_ParticipantCryptoHandle participant_crypto, DDS_Security_ProtectionKind protection_kind) +{ + remote_participant_crypto *paricipant_crypto_impl = (remote_participant_crypto *)participant_crypto; + paricipant_crypto_impl->rtps_protection_kind = protection_kind; +} + +static void initialize_rtps_message(DDS_Security_OctetSeq *submsg, bool be) +{ + size_t length = strlen(sample_test_data) + 1; + struct submsg_header *header; + int swap; + unsigned char *buffer, *ptr; + + if (be) + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + + buffer = ddsrt_malloc(length + 20 + sizeof(struct submsg_header)); + memcpy(buffer, RTPS_HEADER, 20); + + header = (struct submsg_header *)(buffer + 20); + header->id = 0x15; + header->flags = be ? 0x00 : 0x01; + header->length = swap ? ddsrt_bswap2u((uint16_t) length) : (uint16_t) length; + + ptr = (unsigned char *)(header + 1); + memcpy((char *)ptr, sample_test_data, length); + + submsg->_length = submsg->_maximum = (uint32_t) (20 + length + sizeof(struct submsg_header)); + submsg->_buffer = buffer; +} + +static bool check_sign(DDS_Security_ParticipantCryptoHandle participant_crypto, uint32_t session_id, uint32_t key_id, uint32_t key_size, unsigned char *init_vector, unsigned char *common_mac, unsigned char *hmac) +{ + master_key_material *keymat; + crypto_session_key_t key; + unsigned char md[CRYPTO_HMAC_SIZE]; + + memset(md, 0, CRYPTO_HMAC_SIZE); + + keymat = get_remote_participant_key_material(participant_crypto); + if (key_id != keymat->receiver_specific_key_id) + { + printf("check_sign: key_id(%d) does not match key_mat(%d)\n", (int)key_id, (int)keymat->receiver_specific_key_id); + return false; + } + else if (!calculate_receiver_specific_key_test(&key, session_id, keymat->master_salt, keymat->master_receiver_specific_key, keymat->transformation_kind)) + { + printf("check_sign: calculate key failed\n"); + return false; + } + else if (!cipher_sign_data(key.data, key_size, init_vector, common_mac, CRYPTO_HMAC_SIZE, md)) + { + return false; + } + else if (memcmp(hmac, md, CRYPTO_HMAC_SIZE) != 0) + { + printf("check_sign: hmac incorrect\n"); + + //print_octets("Reader Specific Key:", key, CRYPTO_KEY_SIZE); + //print_octets("Common:", common_mac, CRYPTO_HMAC_SIZE); + //print_octets("Hmac:", hmac, CRYPTO_HMAC_SIZE); + //print_octets("MD:", md, CRYPTO_HMAC_SIZE); + return false; + } + + return true; +} + +static bool check_signing( + DDS_Security_ParticipantCryptoHandleSeq *list, + struct crypto_footer *footer, + uint32_t session_id, + unsigned char *init_vector, + uint32_t key_size) +{ + struct receiver_specific_mac *rmac; + uint32_t key_id; + uint32_t i; + + if (footer->length != list->_length) + { + return false; + } + + rmac = (struct receiver_specific_mac *)(footer + 1); + + for (i = 0; i < list->_length; i++) + { + key_id = ddsrt_bswap4u(*(uint32_t *)rmac[i].receiver_mac_key_id); + if (!check_sign(list->_buffer[i], session_id, key_id, key_size, init_vector, footer->common_mac, rmac[i].receiver_mac)) + { + return false; + } + } + + return true; +} + +static void suite_encode_rtps_message_init(void) +{ + allocate_shared_secret(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); +} + +static void suite_encode_rtps_message_fini(void) +{ + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void prepare_participant_security_attributes_and_properties( + DDS_Security_ParticipantSecurityAttributes *attributes, + DDS_Security_PropertySeq *properties, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + bool is_origin_authenticated) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + memset(properties, 0, sizeof(DDS_Security_PropertySeq)); + + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + + properties->_maximum = properties->_length = 1; + properties->_buffer = ddsrt_malloc(sizeof(DDS_Security_Property_t)); + + properties->_buffer[0].name = ddsrt_strdup("dds.sec.crypto.keysize"); + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC) + { + properties->_buffer[0].value = ddsrt_strdup("128"); + } + else + { + properties->_buffer[0].value = ddsrt_strdup("256"); + } + + switch (transformation_kind) + { + case CRYPTO_TRANSFORMATION_KIND_AES128_GCM: + case CRYPTO_TRANSFORMATION_KIND_AES256_GCM: + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; + if (is_origin_authenticated) + { + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED; + } + break; + + case CRYPTO_TRANSFORMATION_KIND_AES256_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES128_GMAC: + attributes->is_rtps_protected = true; + if (is_origin_authenticated) + { + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED; + } + break; + + default: + assert(0); + break; + } +} + +static void encode_rtps_message_not_authenticated(DDS_Security_CryptoTransformKind_Enum transformation_kind, uint32_t key_size, bool encrypted) +{ + DDS_Security_boolean result; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + int32_t index; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + DDS_Security_OctetSeq data; + session_key_material *session_keys; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + uint32_t session_id; + DDS_Security_ParticipantSecurityAttributes attributes; + DDS_Security_PropertySeq properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_rtps_message != NULL); + + prepare_participant_security_attributes_and_properties(&attributes, &properties, transformation_kind, false); + + register_local_participant(&attributes, &properties); + + initialize_rtps_message(&plain_buffer, false); + + session_keys = get_local_participant_session(local_particpant_crypto); + + session_keys->master_key_material->transformation_kind = transformation_kind; + session_keys->key_size = key_size; + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_ParticipantCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_particpant_cryptos[0]; + index = 0; + + /* Now call the function. */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_particpant_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + result = check_encoded_data(&encoded_buffer, encrypted, &header, &footer, &data); + CU_ASSERT_FATAL(result); + + CU_ASSERT(header->transform_identifier.transformation_kind[3] == transformation_kind); + + session_id = ddsrt_bswap4u(*(uint32_t *)header->session_id); + + if (encrypted) + { + decoded_buffer._buffer = ddsrt_malloc(plain_buffer._length + 24); /* info_src is added */ + decoded_buffer._length = 0; + decoded_buffer._maximum = plain_buffer._length + 24; /* info_src is added */ + + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, &decoded_buffer, footer->common_mac); + + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + //print_octets( "PLAIN RTPS:",plain_buffer._buffer+4, plain_buffer._length-4); + //print_octets( "DECODED RTPS:",decoded_buffer._buffer+8, decoded_buffer._length-8); + + CU_ASSERT_FATAL(memcmp(plain_buffer._buffer + 4, decoded_buffer._buffer + 8, plain_buffer._length - 4) == 0); + + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + } + else + { + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, NULL, footer->common_mac); + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + CU_ASSERT_FATAL(memcmp(plain_buffer._buffer + 4, data._buffer + 8, plain_buffer._length - 4) == 0); + } + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + + ddsrt_free(footer); + ddsrt_free(header); + + DDS_Security_PropertySeq_deinit(&properties); + unregister_local_participant(); +} + +CU_Test(ddssec_builtin_encode_rtps_message, encrypt_256, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES256_GCM, 256, true); +} + +CU_Test(ddssec_builtin_encode_rtps_message, encrypt_128, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES128_GCM, 128, true); +} + +CU_Test(ddssec_builtin_encode_rtps_message, no_encrypt_256, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, 256, false); +} + +CU_Test(ddssec_builtin_encode_rtps_message, no_encrypt_128, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC, 128, false); +} + +static void encode_rtps_message_sign(DDS_Security_CryptoTransformKind_Enum transformation_kind, uint32_t key_size, DDS_Security_ProtectionKind protection_kind, bool encoded) +{ + DDS_Security_boolean result; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + int32_t index; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + DDS_Security_OctetSeq data; + DDS_Security_OctetSeq *buffer; + session_key_material *session_keys; + DDS_Security_ParticipantSecurityAttributes attributes; + DDS_Security_PropertySeq properties; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + uint32_t session_id; + int i; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_rtps_message != NULL); + + prepare_participant_security_attributes_and_properties(&attributes, &properties, transformation_kind, true); + + register_local_participant(&attributes, &properties); + + initialize_rtps_message(&plain_buffer, false); + + CU_ASSERT_FATAL(local_particpant_crypto != 0); + + session_keys = get_local_participant_session(local_particpant_crypto); + session_keys->master_key_material->transformation_kind = transformation_kind; + session_keys->key_size = key_size; + set_protection_kind(local_particpant_crypto, protection_kind); + + register_remote_participants(); + + reader_list._length = reader_list._maximum = 4; + reader_list._buffer = DDS_Security_ParticipantCryptoHandleSeq_allocbuf(4); + for (i = 0; i < 4; i++) + { + set_remote_participant_protection_kind(remote_particpant_cryptos[i], protection_kind); + reader_list._buffer[i] = remote_particpant_cryptos[i]; + } + index = 0; + + /* Now call the function. */ + + buffer = &plain_buffer; + while (index != 4) + { + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + buffer, + local_particpant_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + buffer = NULL; + } + + result = check_encoded_data(&encoded_buffer, encoded, &header, &footer, &data); + CU_ASSERT_FATAL(result); + + CU_ASSERT(header->transform_identifier.transformation_kind[3] == transformation_kind); + + session_id = ddsrt_bswap4u(*(uint32_t *)header->session_id); + + if (encoded) + { + decoded_buffer._buffer = ddsrt_malloc(plain_buffer._length + 24); /* info_src is added */ + decoded_buffer._length = 0; + decoded_buffer._maximum = plain_buffer._length + 24; /* info_src is added */ + + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, &decoded_buffer, footer->common_mac); + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + /*TODO: this should consider INFO_SRC */ + CU_ASSERT(memcmp(plain_buffer._buffer + 4, decoded_buffer._buffer + 8, plain_buffer._length - 4) == 0); + + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + } + else + { + result = crypto_decrypt_data(session_id, header->session_id, header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, NULL, footer->common_mac); + + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(memcmp(plain_buffer._buffer + 4, data._buffer + 8, plain_buffer._length - 4) == 0); + } + + printf("num hmacs = %u\n", footer->length); + + CU_ASSERT(check_signing(&reader_list, footer, session_id, header->session_id, session_keys->key_size)); + + unregister_remote_participants(); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + DDS_Security_PropertySeq_deinit(&properties); + + ddsrt_free(footer); + ddsrt_free(header); + + unregister_local_participant(); +} + +CU_Test(ddssec_builtin_encode_rtps_message, encrypt_sign_256, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_sign(CRYPTO_TRANSFORMATION_KIND_AES256_GCM, 256, DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION, true); +} + +CU_Test(ddssec_builtin_encode_rtps_message, encrypt_sign_128, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_sign(CRYPTO_TRANSFORMATION_KIND_AES128_GCM, 128, DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION, true); +} + +CU_Test(ddssec_builtin_encode_rtps_message, no_encrypt_sign_256, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_sign(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, 256, DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION, false); +} + +CU_Test(ddssec_builtin_encode_rtps_message, no_encrypt_sign_128, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_sign(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC, 128, DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION, false); +} + +CU_Test(ddssec_builtin_encode_rtps_message, invalid_args, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + DDS_Security_boolean result; + DDS_Security_ParticipantCryptoHandleSeq reader_list; + DDS_Security_ParticipantCryptoHandleSeq empty_reader_list; + int32_t index; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_ParticipantSecurityAttributes attributes; + DDS_Security_PropertySeq properties; + unsigned i; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_rtps_message != NULL); + + prepare_participant_security_attributes_and_properties(&attributes, &properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + + register_local_participant(&attributes, &properties); + + initialize_rtps_message(&plain_buffer, false); + memset(&empty_reader_list, 0, sizeof(empty_reader_list)); + + CU_ASSERT_FATAL(local_particpant_crypto != 0); + + register_remote_participants(); + for (i = 0; i < 4; i++) + { + set_remote_participant_protection_kind(remote_particpant_cryptos[i], DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION); + } + + CU_ASSERT_FATAL(remote_particpant_cryptos[0] != 0); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_ParticipantCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_particpant_cryptos[0]; + index = 0; + + /* encoded_buffer NULL */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + NULL, + &plain_buffer, + local_particpant_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* plain_buffer NULL */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + NULL, + local_particpant_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto 0 */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + 0, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto unknown */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + 1, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* reader crypto list NULL*/ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_particpant_crypto, + NULL, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* empty reader crypto list */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_particpant_crypto, + &empty_reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* reader crypto list with invalid reader crypto */ + reader_list._buffer[0] = 0; + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_particpant_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* reader crypto list with unknown reader crypto*/ + reader_list._buffer[0] = 1; + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_particpant_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + reader_list._buffer[0] = local_particpant_crypto; + + /* index NULL*/ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_particpant_crypto, + &reader_list, + NULL, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid index */ + index = 2; + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_particpant_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + unregister_remote_participants(); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + DDS_Security_PropertySeq_deinit(&properties); + + unregister_local_participant(); +} + diff --git a/src/security/builtin_plugins/tests/encode_serialized_payload/src/encode_serialized_payload_utests.c b/src/security/builtin_plugins/tests/encode_serialized_payload/src/encode_serialized_payload_utests.c new file mode 100644 index 0000000..f477ea3 --- /dev/null +++ b/src/security/builtin_plugins/tests/encode_serialized_payload/src/encode_serialized_payload_utests.c @@ -0,0 +1,786 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_objects.h" +#include "crypto_utils.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle g_local_participant_identity = 1; +static DDS_Security_IdentityHandle g_remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle g_local_participant_crypto = 0; +static DDS_Security_ParticipantCryptoHandle g_remote_participant_crypto = 0; + +static DDS_Security_SharedSecretHandle g_shared_secret_handle = DDS_SECURITY_HANDLE_NIL; + +static const char *SAMPLE_TEST_DATA = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy"; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[4]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + uint32_t length; +}; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + g_shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = (DDS_Security_SharedSecretHandleImpl *)g_shared_secret_handle; + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + g_local_participant_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + g_local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (g_local_participant_crypto == 0) + { + printf("[ERROR] register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return g_local_participant_crypto ? 0 : -1; +} + +static void unregister_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (g_local_participant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, g_local_participant_crypto, &exception); + reset_exception(&exception); + } +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + g_remote_participant_crypto = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + g_local_participant_crypto, + g_remote_participant_identity, + remote_participant_permissions, + g_shared_secret_handle, + &exception); + + if (g_remote_participant_crypto == 0) + { + printf("[ERROR] register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return g_remote_participant_crypto ? 0 : -1; +} + +static void unregister_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (g_remote_participant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, g_remote_participant_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatawriterCryptoHandle register_local_datawriter(bool encrypted) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + memset(&datawriter_security_attributes, 0, sizeof(datawriter_security_attributes)); + datawriter_security_attributes.is_payload_protected = true; + if (encrypted) + { + datawriter_security_attributes.plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + } + + writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + g_local_participant_crypto, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + if (writer_crypto == 0) + { + printf("[ERROR] register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static void unregister_local_datawriter(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, writer_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatareaderCryptoHandle register_remote_datareader(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + writer_crypto, + g_remote_participant_crypto, + g_shared_secret_handle, + true, + &exception); + + if (reader_crypto == 0) + { + printf("[ERROR] register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static void unregister_remote_datareader(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, reader_crypto, &exception); + reset_exception(&exception); + } +} + +static bool split_encoded_data(unsigned char *data, uint32_t size, struct crypto_header **header, DDS_Security_OctetSeq *payload, struct crypto_footer **footer, bool encrypted) +{ + /* The length is the length of the encrypted data and the common_mac of the footer + * For the serialized payload the footer consists of the common_mac and the length + * of the receiver_specific_mac which is set to 0 */ + static const uint32_t FOOTER_SIZE = 20; + unsigned char *header_ptr; + unsigned char *payload_ptr; + unsigned char *footer_ptr; + uint32_t payload_size; + + if (size < (sizeof(struct crypto_header) + FOOTER_SIZE)) + { + return false; + } + + header_ptr = data; + payload_ptr = data + sizeof(struct crypto_header); + footer_ptr = data + size - FOOTER_SIZE; + + /* Get header. */ + *header = (struct crypto_header *)header_ptr; + + /* Get payload */ + payload_size = (uint32_t)(footer_ptr - payload_ptr); + if (encrypted) + { + /* CryptoContent starts with 4 bytes length. */ + if (payload_size < 4) + { + return false; + } + payload->_length = ddsrt_fromBE4u(*(uint32_t *)payload_ptr); + payload->_buffer = payload_ptr + 4; + if ((payload_size - 4) != payload->_length) + { + return false; + } + } + else + { + /* Just the clear payload */ + payload->_length = payload_size; + payload->_buffer = payload_ptr; + } + payload->_maximum = payload->_length; + + /* Get footer. */ + *footer = (struct crypto_footer *)footer_ptr; + + return true; +} + +static bool crypto_decrypt_data(uint32_t session_id, unsigned char *iv, DDS_Security_CryptoTransformKind transformation_kind, master_key_material *key_material, DDS_Security_OctetSeq *encrypted, DDS_Security_OctetSeq *decoded, unsigned char *tag) +{ + bool result = true; + EVP_CIPHER_CTX *ctx; + crypto_session_key_t session_key; + uint32_t key_size = crypto_get_key_size(CRYPTO_TRANSFORM_KIND(transformation_kind)); + int len = 0; + + if (!crypto_calculate_session_key_test(&session_key, session_id, key_material->master_salt, key_material->master_sender_key, key_material->transformation_kind)) + { + printf("[ERROR] (%d) crypto_decrypt_data: could not calculate session key!\n", __LINE__); + return false; + } + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (ctx) + { + if (key_size == 128) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + printf("[ERROR] (%d) crypto_decrypt_data: could not get init CIPHER_CTX (128)\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + else if (key_size == 256) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + printf("[ERROR] (%d) crypto_decrypt_data: could not get init CIPHER_CTX (256)\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + printf("[ERROR] (%d) crypto_decrypt_data: could not determine keysize\n", __LINE__); + result = false; + } + } + else + { + printf("[ERROR] (%d) crypto_decrypt_data: could not get new CIPHER_CTX\n", __LINE__); + result = false; + } + + if (result) + { + if (!EVP_DecryptInit_ex(ctx, NULL, NULL, session_key.data, iv)) + { + printf("[ERROR] (%d) crypto_decrypt_data: could not init Decrypt\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptUpdate(ctx, decoded->_buffer, &len, encrypted->_buffer, (int) encrypted->_length)) + { + decoded->_length = (uint32_t) len; + } + else + { + printf("[ERROR] (%d) crypto_decrypt_data: could not update Decrypt (decoded)\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + if (!EVP_DecryptUpdate(ctx, NULL, &len, encrypted->_buffer, (int) encrypted->_length)) + { + printf("[ERROR] (%d) crypto_decrypt_data: could not update Decrypt (!decoded)\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (result) + { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, CRYPTO_HMAC_SIZE, tag)) + { + printf("[ERROR] (%d) crypto_decrypt_data: could not ctrl CIPHER_CTX\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptFinal_ex(ctx, decoded->_buffer + len, &len)) + { + decoded->_length += (uint32_t) len; + } + else + { + printf("[ERROR] (%d) crypto_decrypt_data: could not finalize Decrypt (decoded)\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + unsigned char temp[32]; + if (!EVP_DecryptFinal_ex(ctx, temp, &len)) + { + printf("[ERROR] (%d) crypto_decrypt_data: could not finalize Decrypt (!decoded)\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (ctx) + EVP_CIPHER_CTX_free(ctx); + + return result; +} + +static session_key_material * get_datawriter_session(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + local_datawriter_crypto *writer_crypto_impl = (local_datawriter_crypto *)writer_crypto; + return writer_crypto_impl->writer_session_payload; +} + +static bool check_protection_kind(DDS_Security_DatawriterCryptoHandle writer_crypto, DDS_Security_BasicProtectionKind protection_kind) +{ + local_datawriter_crypto *writer_crypto_impl = (local_datawriter_crypto *)writer_crypto; + return (writer_crypto_impl->data_protectionKind == protection_kind); +} + +static void suite_encode_serialized_payload_init(void) +{ + allocate_shared_secret(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); +} + +static void suite_encode_serialized_payload_fini(void) +{ + unregister_remote_participant(); + unregister_local_participant(); + unload_plugins(plugins); + deallocate_shared_secret(); +} + +static uint32_t get_transformation_kind(uint32_t key_size, bool encrypted) +{ + uint32_t kind = CRYPTO_TRANSFORMATION_KIND_INVALID; + if (key_size == 128) + { + kind = encrypted ? CRYPTO_TRANSFORMATION_KIND_AES128_GCM : CRYPTO_TRANSFORMATION_KIND_AES128_GMAC; + } + else if (key_size == 256) + { + kind = encrypted ? CRYPTO_TRANSFORMATION_KIND_AES256_GCM : CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; + } + CU_ASSERT_FATAL(kind != CRYPTO_TRANSFORMATION_KIND_INVALID); + return kind; +} + +static bool seq_equal(DDS_Security_OctetSeq *seq1, DDS_Security_OctetSeq *seq2) +{ + bool ok = false; + if (seq1->_length == seq2->_length) + { + if (memcmp(seq1->_buffer, seq2->_buffer, seq1->_length) == 0) + { + ok = true; + } + } + return ok; +} + +static bool check_payload_signed(DDS_Security_OctetSeq *payload, DDS_Security_OctetSeq *plain_buffer) +{ + /* When only signed, the payload should not have changed. */ + return seq_equal(payload, plain_buffer); +} + +static bool check_payload_encrypted(DDS_Security_OctetSeq *payload, DDS_Security_OctetSeq *plain_buffer) +{ + bool ok = false; + /* When encrypted, the payload should differ from the original data. */ + if (payload->_length >= plain_buffer->_length) + { + if (memcmp(payload->_buffer, plain_buffer->_buffer, plain_buffer->_length) != 0) + { + ok = true; + } + } + return ok; +} + +static bool check_payload_encoded(DDS_Security_OctetSeq *payload, DDS_Security_OctetSeq *plain_buffer, bool encrypted) +{ + bool ok; + if (encrypted) + { + ok = check_payload_encrypted(payload, plain_buffer); + } + else + { + ok = check_payload_signed(payload, plain_buffer); + } + return ok; +} + +static bool check_payload_decoded(DDS_Security_OctetSeq *payload, DDS_Security_OctetSeq *plain_buffer) +{ + /* After decoding, the payload should match the orignal. */ + return seq_equal(payload, plain_buffer); +} + +static void encode_serialized_payload_check(uint32_t key_size, bool encrypted) +{ + DDS_Security_boolean result; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq extra_inline_qos; + DDS_Security_OctetSeq encoded_payload; + DDS_Security_OctetSeq plain_buffer; + session_key_material *session_keys; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + uint32_t session_id; + size_t length; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_serialized_payload != NULL); + + memset(&extra_inline_qos, 0, sizeof(extra_inline_qos)); + + length = strlen(SAMPLE_TEST_DATA) + 1; + plain_buffer._length = plain_buffer._maximum = (uint32_t) length; + plain_buffer._buffer = DDS_Security_OctetSeq_allocbuf((uint32_t) length); + memcpy((char *)plain_buffer._buffer, SAMPLE_TEST_DATA, length); + + writer_crypto = register_local_datawriter(encrypted); + CU_ASSERT_FATAL(writer_crypto != 0); + CU_ASSERT(check_protection_kind(writer_crypto, encrypted ? DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT : DDS_SECURITY_BASICPROTECTION_KIND_SIGN)); + + session_keys = get_datawriter_session(writer_crypto); + session_keys->master_key_material->transformation_kind = get_transformation_kind(key_size, encrypted); + session_keys->key_size = key_size; + + /* Now call the function. */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + &plain_buffer, + writer_crypto, + &exception); + + if (!result) + { + printf("[ERROR] encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + reset_exception(&exception); + + result = split_encoded_data(encoded_buffer._buffer, encoded_buffer._length, &header, &encoded_payload, &footer, encrypted); + CU_ASSERT_FATAL(result == true); + CU_ASSERT(check_payload_encoded(&encoded_payload, &plain_buffer, encrypted)); + + session_id = ddsrt_fromBE4u(*(uint32_t *)header->session_id); + + if (encrypted) + { + DDS_Security_OctetSeq decoded_buffer; + decoded_buffer._buffer = ddsrt_malloc(length); + decoded_buffer._length = (uint32_t) length; + decoded_buffer._maximum = (uint32_t) length; + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, session_keys->master_key_material, &encoded_payload, &decoded_buffer, footer->common_mac); + if (!result) + { + printf("[ERROR] Decryption failed\n"); + } + CU_ASSERT_FATAL(result); + CU_ASSERT(check_payload_decoded(&decoded_buffer, &plain_buffer)); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + } + else + { + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, session_keys->master_key_material, &encoded_payload, NULL, footer->common_mac); + if (!result) + { + printf("[ERROR] Signature check failed\n"); + } + CU_ASSERT_FATAL(result); + } + + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&plain_buffer); + + unregister_local_datawriter(writer_crypto); +} + +CU_Test(ddssec_builtin_encode_serialized_payload, encrypt_128, .init = suite_encode_serialized_payload_init, .fini = suite_encode_serialized_payload_fini) +{ + encode_serialized_payload_check(128, true); +} + +CU_Test(ddssec_builtin_encode_serialized_payload, encrypt_256, .init = suite_encode_serialized_payload_init, .fini = suite_encode_serialized_payload_fini) +{ + encode_serialized_payload_check(256, true); +} + +CU_Test(ddssec_builtin_encode_serialized_payload, sign_128, .init = suite_encode_serialized_payload_init, .fini = suite_encode_serialized_payload_fini) +{ + encode_serialized_payload_check(128, false); +} + +CU_Test(ddssec_builtin_encode_serialized_payload, sign_256, .init = suite_encode_serialized_payload_init, .fini = suite_encode_serialized_payload_fini) +{ + encode_serialized_payload_check(256, false); +} + +CU_Test(ddssec_builtin_encode_serialized_payload, invalid_args, .init = suite_encode_serialized_payload_init, .fini = suite_encode_serialized_payload_fini) +{ + DDS_Security_boolean result; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq extra_inline_qos; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq empty_buffer; + size_t length; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_serialized_payload != NULL); + + writer_crypto = register_local_datawriter(true); + CU_ASSERT_FATAL(writer_crypto != 0); + + reader_crypto = register_remote_datareader(writer_crypto); + CU_ASSERT_FATAL(reader_crypto != 0); + + memset(&extra_inline_qos, 0, sizeof(extra_inline_qos)); + memset(&empty_buffer, 0, sizeof(empty_buffer)); + + length = strlen(SAMPLE_TEST_DATA) + 1; + plain_buffer._length = plain_buffer._maximum = (uint32_t) length; + plain_buffer._buffer = DDS_Security_OctetSeq_allocbuf((uint32_t) length); + memcpy((char *)plain_buffer._buffer, SAMPLE_TEST_DATA, length); + + /* no encoded data specified */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + NULL, + &extra_inline_qos, + &plain_buffer, + writer_crypto, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* no plain data specified */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + NULL, + writer_crypto, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + unregister_local_datawriter(writer_crypto); + + /* empty plain data specified */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + &empty_buffer, + writer_crypto, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* unknown writer crypto handle specified */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + &plain_buffer, + 0, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* incorrect writer crypto handle specified */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + &plain_buffer, + reader_crypto, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + unregister_remote_datareader(reader_crypto); + unregister_local_datawriter(writer_crypto); + + DDS_Security_OctetSeq_deinit(&plain_buffer); +} + diff --git a/src/security/builtin_plugins/tests/get_authenticated_peer_credential_token/src/get_authenticated_peer_credential_token_utests.c b/src/security/builtin_plugins/tests/get_authenticated_peer_credential_token/src/get_authenticated_peer_credential_token_utests.c index 12216c5..160ae83 100644 --- a/src/security/builtin_plugins/tests/get_authenticated_peer_credential_token/src/get_authenticated_peer_credential_token_utests.c +++ b/src/security/builtin_plugins/tests/get_authenticated_peer_credential_token/src/get_authenticated_peer_credential_token_utests.c @@ -31,27 +31,14 @@ #include #include "dds/ddsrt/environ.h" +#include "dds/ddsrt/bswap.h" #include "dds/ddsrt/misc.h" -#include "dds/ddsrt/endian.h" #include "dds/security/core/dds_security_serialize.h" #include "dds/security/dds_security_api.h" #include "dds/security/core/dds_security_utils.h" #define HANDSHAKE_SIGNATURE_SIZE 6 -#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN -static unsigned bswap4u (unsigned x) -{ - return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24); -} -#define toBE4u(x) bswap4u (x) -#define fromBE4u(x) bswap4u (x) -#else -#define toBE4u(x) (x) -#define fromBE4u(x) (x) -#endif - - static const char * AUTH_PROTOCOL_CLASS_ID = "DDS:Auth:PKI-DH:1.0"; static const char * PERM_ACCESS_CLASS_ID = "DDS:Access:Permissions:1.0"; @@ -483,9 +470,9 @@ validate_local_identity(void) g_local_participant_data = DDS_Security_ParticipantBuiltinTopicData_alloc(); memcpy(&g_local_participant_data->key[0], &local_participant_guid, 12); /* convert from big-endian format to native format */ - g_local_participant_data->key[0] = fromBE4u(g_local_participant_data->key[0]); - g_local_participant_data->key[1] = fromBE4u(g_local_participant_data->key[1]); - g_local_participant_data->key[2] = fromBE4u(g_local_participant_data->key[2]); + g_local_participant_data->key[0] = ddsrt_fromBE4u(g_local_participant_data->key[0]); + g_local_participant_data->key[1] = ddsrt_fromBE4u(g_local_participant_data->key[1]); + g_local_participant_data->key[2] = ddsrt_fromBE4u(g_local_participant_data->key[2]); initialize_identity_token(&g_local_participant_data->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); initialize_permissions_token(&g_local_participant_data->permissions_token, RSA_2048_ALGORITHM_NAME); @@ -843,9 +830,9 @@ validate_remote_identities (const char *remote_id_certificate) g_remote_participant_data1 = DDS_Security_ParticipantBuiltinTopicData_alloc(); memcpy(&g_remote_participant_data1->key[0], &g_remote_participant_guid1, 12); - g_remote_participant_data1->key[0] = fromBE4u(g_remote_participant_data1->key[0]); - g_remote_participant_data1->key[1] = fromBE4u(g_remote_participant_data1->key[1]); - g_remote_participant_data1->key[2] = fromBE4u(g_remote_participant_data1->key[2]); + g_remote_participant_data1->key[0] = ddsrt_fromBE4u(g_remote_participant_data1->key[0]); + g_remote_participant_data1->key[1] = ddsrt_fromBE4u(g_remote_participant_data1->key[1]); + g_remote_participant_data1->key[2] = ddsrt_fromBE4u(g_remote_participant_data1->key[2]); initialize_identity_token(&g_remote_participant_data1->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); initialize_permissions_token(&g_remote_participant_data1->permissions_token, RSA_2048_ALGORITHM_NAME); @@ -855,9 +842,9 @@ validate_remote_identities (const char *remote_id_certificate) g_remote_participant_data2 = DDS_Security_ParticipantBuiltinTopicData_alloc(); memcpy(&g_remote_participant_data2->key[0], &g_remote_participant_guid2, 12); - g_remote_participant_data2->key[0] = fromBE4u(g_remote_participant_data2->key[0]); - g_remote_participant_data2->key[1] = fromBE4u(g_remote_participant_data2->key[1]); - g_remote_participant_data2->key[2] = fromBE4u(g_remote_participant_data2->key[2]); + g_remote_participant_data2->key[0] = ddsrt_fromBE4u(g_remote_participant_data2->key[0]); + g_remote_participant_data2->key[1] = ddsrt_fromBE4u(g_remote_participant_data2->key[1]); + g_remote_participant_data2->key[2] = ddsrt_fromBE4u(g_remote_participant_data2->key[2]); initialize_identity_token(&g_remote_participant_data2->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); initialize_permissions_token(&g_remote_participant_data2->permissions_token, RSA_2048_ALGORITHM_NAME); @@ -952,7 +939,7 @@ serializer_participant_data( DDS_Security_Serializer serializer; serializer = DDS_Security_Serializer_new(1024, 1024); - DDD_Security_Serialize_ParticipantBuiltinTopicData(serializer, pdata); + DDS_Security_Serialize_ParticipantBuiltinTopicData(serializer, pdata); DDS_Security_Serializer_buffer(serializer, buffer, size); DDS_Security_Serializer_free(serializer); } diff --git a/src/security/builtin_plugins/tests/preprocess_secure_submsg/src/preprocess_secure_submsg_utests.c b/src/security/builtin_plugins/tests/preprocess_secure_submsg/src/preprocess_secure_submsg_utests.c new file mode 100644 index 0000000..f469a09 --- /dev/null +++ b/src/security/builtin_plugins/tests/preprocess_secure_submsg/src/preprocess_secure_submsg_utests.c @@ -0,0 +1,930 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +#define VALID_SMID_SEC_PREFIX 0x31 +#define INVALID_SMID_SEC_PREFIX 0x15 + + +typedef struct SubMessageHeader { + unsigned char kind; + unsigned char flags; + uint16_t octetsToNextSubMsg; +} SubMessageHeader; + +typedef struct CryptoHeader { + DDS_Security_CryptoTransformKind transform_id; + DDS_Security_CryptoTransformKeyId key_id; + unsigned char session_id[4]; + unsigned char initVectorSuffix[8]; +} CryptoHeader; + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_participant_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_handle = DDS_SECURITY_HANDLE_NIL; + +static DDS_Security_DatawriterCryptoHandle local_writer_crypto = 0; +static DDS_Security_DatawriterCryptoHandle remote_writer_crypto = 0; +static DDS_Security_DatareaderCryptoHandle local_reader_crypto = 0; +static DDS_Security_DatareaderCryptoHandle remote_reader_crypto = 0; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static DDS_Security_KeyMaterial_AES_GCM_GMAC writer_key_message; +static DDS_Security_KeyMaterial_AES_GCM_GMAC writer_key_payload; +static DDS_Security_KeyMaterial_AES_GCM_GMAC reader_key_message; + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc (sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc (TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle) shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + memset(&participant_security_attributes, 0, sizeof(participant_security_attributes)); + + local_participant_handle = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_participant_handle == DDS_SECURITY_HANDLE_NIL) { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_participant_handle ? 0 : -1; +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_participant_handle = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_handle, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_participant_handle == DDS_SECURITY_HANDLE_NIL) { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_participant_handle ? 0 : -1; +} + +static void prepare_endpoint_security_attributes( DDS_Security_EndpointSecurityAttributes *attributes){ + memset( attributes, 0 , sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + +} + +static int register_local_datareader(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + memset(&datareader_properties, 0, sizeof(datareader_properties)); + prepare_endpoint_security_attributes( &datareader_security_attributes ); + + local_reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + + + if (local_reader_crypto == 0) + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + + return local_reader_crypto ? 0 : -1; +} + +static int register_remote_datareader(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + + memset (&datawriter_properties, 0, sizeof(datawriter_properties)); + remote_reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_crypto, + remote_participant_handle, + shared_secret_handle, + true, + &exception); + + if (remote_reader_crypto == 0) + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + + return remote_reader_crypto ? 0 : -1; +} + +static int register_local_datawriter(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + prepare_endpoint_security_attributes( &datawriter_security_attributes ); + + local_writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + + if (local_writer_crypto == 0) + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + + return local_writer_crypto ? 0 : -1; +} + +static int register_remote_datawriter(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + remote_writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_crypto, + remote_participant_handle, + shared_secret_handle, + &exception); + + if (remote_writer_crypto == 0) + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + + return remote_writer_crypto ? 0 : -1; +} + +static DDS_Security_boolean retrieve_datawriter_keys(DDS_Security_DatawriterCryptoTokenSeq *tokens) +{ + DDS_Security_boolean result = true; + DDS_Security_Deserializer deserializer; + DDS_Security_KeyMaterial_AES_GCM_GMAC *key_mat = &writer_key_message; + uint32_t i; + + for (i = 0; result && (i < tokens->_length); i++) { + const DDS_Security_OctetSeq *tdata = &tokens->_buffer[i].binary_properties._buffer[0].value; + + deserializer = DDS_Security_Deserializer_new(tdata->_buffer, tdata->_length); + + if (!deserializer) + result = false; + else if (!DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC(deserializer, key_mat)) + result = false; + + DDS_Security_Deserializer_free(deserializer); + key_mat = &writer_key_payload; + } + + return result; +} + +static DDS_Security_boolean retrieve_datareader_keys(DDS_Security_DatareaderCryptoTokenSeq *tokens) +{ + DDS_Security_boolean result = true; + const DDS_Security_OctetSeq *tdata = &tokens->_buffer[0].binary_properties._buffer[0].value; + DDS_Security_Deserializer deserializer; + DDS_Security_KeyMaterial_AES_GCM_GMAC *key_mat = &reader_key_message; + + deserializer = DDS_Security_Deserializer_new(tdata->_buffer, tdata->_length); + + if (!deserializer) + result = false; + else if (!DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC(deserializer, key_mat)) + result = false; + DDS_Security_Deserializer_free(deserializer); + + return result; +} + +static int set_remote_datawriter_tokens(void) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (result) + result = retrieve_datawriter_keys(&tokens); + + if (result) { + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + } + + DDS_Security_DataHolderSeq_deinit((DDS_Security_DataHolderSeq*)&tokens); + + return result ? 0 : -1; +} + +static int set_remote_datareader_tokens(void) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoTokenSeq tokens; + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (result) + result = retrieve_datareader_keys(&tokens); + if (result) { + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + } + + DDS_Security_DataHolderSeq_deinit((DDS_Security_DataHolderSeq*)&tokens); + + return result ? 0 : -1; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + + +static void suite_preprocess_secure_submsg_init (void) +{ + allocate_shared_secret(); + memset(&writer_key_message, 0, sizeof(DDS_Security_KeyMaterial_AES_GCM_GMAC)); + memset(&writer_key_payload, 0, sizeof(DDS_Security_KeyMaterial_AES_GCM_GMAC)); + memset(&reader_key_message, 0, sizeof(DDS_Security_KeyMaterial_AES_GCM_GMAC)); + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptography */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_local_datawriter(), 0); + CU_ASSERT_EQUAL_FATAL (register_local_datareader(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_datareader(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_datawriter(), 0); + CU_ASSERT_EQUAL_FATAL (set_remote_datawriter_tokens(), 0); + CU_ASSERT_EQUAL_FATAL (set_remote_datareader_tokens(), 0); +} + +static void suite_preprocess_secure_submsg_fini (void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + if (remote_writer_crypto) { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, remote_writer_crypto, &exception); + reset_exception(&exception); + } + if (remote_reader_crypto) { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, remote_reader_crypto, &exception); + reset_exception(&exception); + } + if (local_reader_crypto) { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_reader_crypto, &exception); + reset_exception(&exception); + } + if (local_writer_crypto) { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, local_writer_crypto, &exception); + reset_exception(&exception); + } + if (remote_participant_handle) { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_participant_handle, &exception); + reset_exception(&exception); + } + if (local_participant_handle) { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_participant_handle, &exception); + reset_exception(&exception); + } + + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&reader_key_message); + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&writer_key_message); + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void create_encoded_submsg(DDS_Security_OctetSeq *msg, DDS_Security_CryptoTransformKeyId key_id, DDS_Security_CryptoTransformKind transform_kind, unsigned char msg_id, bool be) +{ + unsigned char *buffer; + uint32_t length = sizeof(SubMessageHeader) + sizeof(CryptoHeader) + 200; + SubMessageHeader *submsg; + CryptoHeader *crpthdr; + int swap = be ? (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN) : (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + + buffer = ddsrt_malloc(length); + submsg = (SubMessageHeader *) buffer; + crpthdr = (CryptoHeader *) (submsg + 1); + + submsg->kind = msg_id; + submsg->flags = be ? 0 : 1; + submsg->octetsToNextSubMsg = swap ? ddsrt_bswap2u((uint16_t)(length - 24)) : (uint16_t)(length - 24); + + memcpy(crpthdr->key_id, key_id, 4); + memcpy(crpthdr->transform_id, transform_kind, 4); + + msg->_buffer = buffer; + msg->_length = msg->_maximum = length; +} + +static void clear_encoded_submsg(DDS_Security_OctetSeq *msg) +{ + if (msg) { + ddsrt_free(msg->_buffer); + memset(msg, 0, sizeof(*msg)); + } +} + + +CU_Test(ddssec_builtin_preprocess_secure_submsg, writer_happy_day, .init = suite_preprocess_secure_submsg_init, .fini = suite_preprocess_secure_submsg_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecureSubmessageCategory_t category; + DDS_Security_OctetSeq message; + + CU_ASSERT_FATAL (crypto != NULL); + CU_ASSERT_FATAL (crypto->crypto_transform != NULL); + CU_ASSERT_FATAL (crypto->crypto_transform->preprocess_secure_submsg != NULL); + + create_encoded_submsg(&message, writer_key_message.sender_key_id, writer_key_message.transformation_kind, VALID_SMID_SEC_PREFIX, false); + + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT(writer_crypto == remote_writer_crypto); + CU_ASSERT(reader_crypto == local_reader_crypto); + CU_ASSERT(category == DDS_SECURITY_DATAWRITER_SUBMESSAGE); + + reset_exception(&exception); + + clear_encoded_submsg(&message); + + create_encoded_submsg(&message, writer_key_message.sender_key_id, writer_key_message.transformation_kind, VALID_SMID_SEC_PREFIX, true); + + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT(writer_crypto == remote_writer_crypto); + CU_ASSERT(reader_crypto == local_reader_crypto); + CU_ASSERT(category == DDS_SECURITY_DATAWRITER_SUBMESSAGE); + + reset_exception(&exception); + + clear_encoded_submsg(&message); +} + +CU_Test(ddssec_builtin_preprocess_secure_submsg, reader_happy_day, .init = suite_preprocess_secure_submsg_init, .fini = suite_preprocess_secure_submsg_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecureSubmessageCategory_t category; + DDS_Security_OctetSeq message; + + CU_ASSERT_FATAL (crypto != NULL); + CU_ASSERT_FATAL (crypto ->crypto_transform!= NULL); + CU_ASSERT_FATAL (crypto ->crypto_transform->preprocess_secure_submsg != NULL); + + create_encoded_submsg(&message, reader_key_message.sender_key_id, reader_key_message.transformation_kind, VALID_SMID_SEC_PREFIX, false); + + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT(writer_crypto == local_writer_crypto); + CU_ASSERT(reader_crypto == remote_reader_crypto); + CU_ASSERT(category == DDS_SECURITY_DATAREADER_SUBMESSAGE); + + reset_exception(&exception); + clear_encoded_submsg(&message); + create_encoded_submsg(&message, reader_key_message.sender_key_id, reader_key_message.transformation_kind, VALID_SMID_SEC_PREFIX, true); + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT(writer_crypto == local_writer_crypto); + CU_ASSERT(reader_crypto == remote_reader_crypto); + CU_ASSERT(category == DDS_SECURITY_DATAREADER_SUBMESSAGE); + + reset_exception(&exception); + clear_encoded_submsg(&message); +} + + +CU_Test(ddssec_builtin_preprocess_secure_submsg, invalid_args, .init = suite_preprocess_secure_submsg_init, .fini = suite_preprocess_secure_submsg_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecureSubmessageCategory_t category; + DDS_Security_OctetSeq message; + + CU_ASSERT_FATAL (crypto != NULL); + CU_ASSERT_FATAL (crypto ->crypto_transform!= NULL); + CU_ASSERT_FATAL (crypto ->crypto_transform->preprocess_secure_submsg != NULL); + + create_encoded_submsg(&message, writer_key_message.sender_key_id, reader_key_message.transformation_kind, VALID_SMID_SEC_PREFIX, false); + + /* writer handle = NULL. */ + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + NULL, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* reader handle = NULL. */ + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + NULL, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* category = NULL */ + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + NULL, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* message = NULL */ + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + NULL, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* unknown local_participant_handle */ + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + 1, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* remote_participant_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + 0, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* unknown remote_participant_handle */ + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + 1, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + clear_encoded_submsg(&message); +} + + +CU_Test(ddssec_builtin_preprocess_secure_submsg, invalid_message, .init = suite_preprocess_secure_submsg_init, .fini = suite_preprocess_secure_submsg_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecureSubmessageCategory_t category; + DDS_Security_OctetSeq message; + + CU_ASSERT_FATAL (crypto != NULL); + CU_ASSERT_FATAL (crypto ->crypto_transform!= NULL); + CU_ASSERT_FATAL (crypto ->crypto_transform->preprocess_secure_submsg != NULL); + + /* unknown key id */ + create_encoded_submsg(&message, writer_key_payload.sender_key_id, writer_key_payload.transformation_kind, VALID_SMID_SEC_PREFIX, false); + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + clear_encoded_submsg(&message); + + /* invalid transformation kind */ + { + DDS_Security_CryptoTransformKind kind = {5, 1, 3, 6}; + + create_encoded_submsg(&message, writer_key_message.sender_key_id, kind, VALID_SMID_SEC_PREFIX, false); + + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + clear_encoded_submsg(&message); + } + + /* not expected submessage id */ + { + DDS_Security_CryptoTransformKind kind = {5, 1, 3, 6}; + create_encoded_submsg(&message, writer_key_message.sender_key_id, kind, INVALID_SMID_SEC_PREFIX, false); + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + clear_encoded_submsg(&message); + } +} + + +CU_Test(ddssec_builtin_preprocess_secure_submsg, volatile_secure, .init = suite_preprocess_secure_submsg_init, .fini = suite_preprocess_secure_submsg_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandle local_reader_crypto_vol; + DDS_Security_DatawriterCryptoHandle local_writer_crypto_vol; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto_vol; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto_vol; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecureSubmessageCategory_t category; + DDS_Security_CryptoTransformKeyId key_id = {0, 0, 0, 0}; + DDS_Security_OctetSeq message; + + CU_ASSERT_FATAL (crypto != NULL); + CU_ASSERT_FATAL (crypto->crypto_transform != NULL); + CU_ASSERT_FATAL (crypto->crypto_transform->preprocess_secure_submsg != NULL); + + datareader_properties._length = datareader_properties._maximum = 1; + datareader_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datareader_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datareader_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureReader"); + datareader_properties._buffer[0].propagate = false; + + prepare_endpoint_security_attributes( &datareader_security_attributes ); + prepare_endpoint_security_attributes( &datawriter_security_attributes ); + + datawriter_properties._length = datawriter_properties._maximum = 1; + datawriter_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datawriter_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datawriter_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureWriter"); + datawriter_properties._buffer[0].propagate = false; + + local_writer_crypto_vol = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + CU_ASSERT_FATAL(local_writer_crypto_vol != 0); + + local_reader_crypto_vol = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + CU_ASSERT_FATAL(local_reader_crypto_vol != 0); + + remote_writer_crypto_vol = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_crypto_vol, + remote_participant_handle, + shared_secret_handle, + &exception); + CU_ASSERT_FATAL(remote_writer_crypto_vol != 0); + + remote_reader_crypto_vol = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_crypto_vol, + remote_participant_handle, + shared_secret_handle, + true, + &exception); + CU_ASSERT_FATAL(remote_reader_crypto_vol != 0); + + create_encoded_submsg(&message, key_id, reader_key_message.transformation_kind, VALID_SMID_SEC_PREFIX, false); + + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT(((remote_datawriter_crypto *)writer_crypto)->is_builtin_participant_volatile_message_secure_writer); + CU_ASSERT(((local_datareader_crypto *)reader_crypto)->is_builtin_participant_volatile_message_secure_reader); + CU_ASSERT(category == DDS_SECURITY_DATAWRITER_SUBMESSAGE); + + reset_exception(&exception); + + if (remote_writer_crypto_vol) { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, remote_writer_crypto_vol, &exception); + reset_exception(&exception); + } + if (remote_reader_crypto_vol) { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, remote_reader_crypto_vol, &exception); + reset_exception(&exception); + } + if (local_reader_crypto_vol) { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_reader_crypto_vol, &exception); + reset_exception(&exception); + } + if (local_writer_crypto_vol) { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, local_writer_crypto_vol, &exception); + reset_exception(&exception); + } + + clear_encoded_submsg(&message); + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} diff --git a/src/security/builtin_plugins/tests/process_handshake/src/process_handshake_utests.c b/src/security/builtin_plugins/tests/process_handshake/src/process_handshake_utests.c index e717e54..9eaf2d1 100644 --- a/src/security/builtin_plugins/tests/process_handshake/src/process_handshake_utests.c +++ b/src/security/builtin_plugins/tests/process_handshake/src/process_handshake_utests.c @@ -11,9 +11,9 @@ #include "dds/security/core/dds_security_serialize.h" #include "dds/security/core/dds_security_utils.h" #include "dds/security/dds_security_api.h" +#include "dds/ddsrt/bswap.h" #include "dds/ddsrt/heap.h" #include "dds/ddsrt/string.h" -#include "dds/ddsrt/endian.h" #include #include #include "dds/ddsrt/environ.h" @@ -34,19 +34,6 @@ #define HANDSHAKE_SIGNATURE_SIZE 6 -#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN -static unsigned bswap4u (unsigned x) -{ - return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24); -} -#define toBE4u(x) bswap4u (x) -#define fromBE4u(x) bswap4u (x) -#else -#define toBE4u(x) (x) -#define fromBE4u(x) (x) -#endif - - static const char * AUTH_PROTOCOL_CLASS_ID = "DDS:Auth:PKI-DH:1.0"; static const char * PERM_ACCESS_CLASS_ID = "DDS:Access:Permissions:1.0"; @@ -574,9 +561,9 @@ validate_local_identity(const char* trusted_ca_dir) local_participant_data = DDS_Security_ParticipantBuiltinTopicData_alloc(); memcpy(&local_participant_data->key[0], &local_participant_guid, 12); /* convert from big-endian format to native format */ - local_participant_data->key[0] = fromBE4u(local_participant_data->key[0]); - local_participant_data->key[1] = fromBE4u(local_participant_data->key[1]); - local_participant_data->key[2] = fromBE4u(local_participant_data->key[2]); + local_participant_data->key[0] = ddsrt_fromBE4u(local_participant_data->key[0]); + local_participant_data->key[1] = ddsrt_fromBE4u(local_participant_data->key[1]); + local_participant_data->key[2] = ddsrt_fromBE4u(local_participant_data->key[2]); initialize_identity_token(&local_participant_data->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); initialize_permissions_token(&local_participant_data->permissions_token, RSA_2048_ALGORITHM_NAME); @@ -947,9 +934,9 @@ validate_remote_identities (const char *remote_id_certificate) remote_participant_data1 = DDS_Security_ParticipantBuiltinTopicData_alloc(); memcpy(&remote_participant_data1->key[0], &remote_participant_guid1, 12); - remote_participant_data1->key[0] = fromBE4u(remote_participant_data1->key[0]); - remote_participant_data1->key[1] = fromBE4u(remote_participant_data1->key[1]); - remote_participant_data1->key[2] = fromBE4u(remote_participant_data1->key[2]); + remote_participant_data1->key[0] = ddsrt_fromBE4u(remote_participant_data1->key[0]); + remote_participant_data1->key[1] = ddsrt_fromBE4u(remote_participant_data1->key[1]); + remote_participant_data1->key[2] = ddsrt_fromBE4u(remote_participant_data1->key[2]); initialize_identity_token(&remote_participant_data1->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); initialize_permissions_token(&remote_participant_data1->permissions_token, RSA_2048_ALGORITHM_NAME); @@ -959,9 +946,9 @@ validate_remote_identities (const char *remote_id_certificate) remote_participant_data2 = DDS_Security_ParticipantBuiltinTopicData_alloc(); memcpy(&remote_participant_data2->key[0], &remote_participant_guid2, 12); - remote_participant_data2->key[0] = fromBE4u(remote_participant_data2->key[0]); - remote_participant_data2->key[1] = fromBE4u(remote_participant_data2->key[1]); - remote_participant_data2->key[2] = fromBE4u(remote_participant_data2->key[2]); + remote_participant_data2->key[0] = ddsrt_fromBE4u(remote_participant_data2->key[0]); + remote_participant_data2->key[1] = ddsrt_fromBE4u(remote_participant_data2->key[1]); + remote_participant_data2->key[2] = ddsrt_fromBE4u(remote_participant_data2->key[2]); initialize_identity_token(&remote_participant_data2->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); initialize_permissions_token(&remote_participant_data2->permissions_token, RSA_2048_ALGORITHM_NAME); @@ -1095,7 +1082,7 @@ serializer_participant_data( DDS_Security_Serializer serializer; serializer = DDS_Security_Serializer_new(1024, 1024); - DDD_Security_Serialize_ParticipantBuiltinTopicData(serializer, pdata); + DDS_Security_Serialize_ParticipantBuiltinTopicData(serializer, pdata); DDS_Security_Serializer_buffer(serializer, buffer, size); DDS_Security_Serializer_free(serializer); } diff --git a/src/security/builtin_plugins/tests/register_local_datareader/src/register_local_datareader_utests.c b/src/security/builtin_plugins/tests/register_local_datareader/src/register_local_datareader_utests.c new file mode 100644 index 0000000..327ddb7 --- /dev/null +++ b/src/security/builtin_plugins/tests/register_local_datareader/src/register_local_datareader_utests.c @@ -0,0 +1,311 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_objects.h" + +#if OPENSLL_VERSION_NUMBER >= 0x10002000L +#define AUTH_INCLUDE_EC +#endif + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle = DDS_SECURITY_HANDLE_NIL; +static dds_security_cryptography *crypto = NULL; +static DDS_Security_ParticipantCryptoHandle local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static void suite_register_local_datareader_init(void) +{ + DDS_Security_IdentityHandle participant_identity = 5; //valid dummy value + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq participant_properties; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; //valid dummy value + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + /* Only need the crypto plugin. */ + CU_ASSERT_FATAL((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + + /* prepare test shared secret handle */ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(DDS_Security_octet)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL && crypto->crypto_key_factory != NULL && crypto->crypto_key_factory->register_local_participant != NULL); + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + CU_ASSERT_FATAL((local_participant_crypto_handle = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception)) != DDS_SECURITY_HANDLE_NIL) + + /* Now call the function. */ + remote_participant_crypto_handle = crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_crypto_handle, + participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); +} + +static void suite_register_local_datareader_fini(void) +{ + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = (DDS_Security_SharedSecretHandleImpl *)shared_secret_handle; + unload_plugins(plugins); + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); + shared_secret_handle = DDS_SECURITY_HANDLE_NIL; + crypto = NULL; + local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; + remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void prepare_endpoint_security_attributes(DDS_Security_EndpointSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; +} + +CU_Test(ddssec_builtin_register_local_datareader, happy_day, .init = suite_register_local_datareader_init, .fini = suite_register_local_datareader_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + local_datareader_crypto *reader_crypto; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datareader != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datareader_properties, 0, sizeof(datareader_properties)); + + prepare_endpoint_security_attributes(&datareader_security_attributes); + + /* Now call the function. */ + + result = crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT(result != 0); + + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + reader_crypto = (local_datareader_crypto *)result; + + CU_ASSERT_FATAL(reader_crypto->reader_key_material != NULL); + CU_ASSERT(master_salt_not_empty(reader_crypto->reader_key_material)); + CU_ASSERT(master_key_not_empty(reader_crypto->reader_key_material)); + CU_ASSERT(reader_crypto->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_register_local_datareader, builtin_endpoint, .init = suite_register_local_datareader_init, .fini = suite_register_local_datareader_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + local_datareader_crypto *reader_crypto; + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datareader_properties, 0, sizeof(datareader_properties)); + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datareader != NULL); + + datareader_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datareader_properties._length = datareader_properties._maximum = 1; + + datareader_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datareader_properties._buffer[0].value = ddsrt_strdup("BuiltinSecureEndpointName"); + + prepare_endpoint_security_attributes(&datareader_security_attributes); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + + if (exception.code != 0) + printf("register_local_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT(result != 0); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + reader_crypto = (local_datareader_crypto *)result; + CU_ASSERT_FATAL(reader_crypto->reader_key_material != NULL); + CU_ASSERT(master_salt_not_empty(reader_crypto->reader_key_material)); + CU_ASSERT(master_key_not_empty(reader_crypto->reader_key_material)); + CU_ASSERT(reader_crypto->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT); + CU_ASSERT(reader_crypto->is_builtin_participant_volatile_message_secure_reader == false); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_register_local_datareader, special_endpoint_name, .init = suite_register_local_datareader_init, .fini = suite_register_local_datareader_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datareader_properties, 0, sizeof(datareader_properties)); + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datareader != NULL); + + /*set special endpoint name*/ + datareader_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datareader_properties._length = datareader_properties._maximum = 1; + datareader_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datareader_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureReader"); + + prepare_endpoint_security_attributes(&datareader_security_attributes); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + + if (exception.code != 0) + printf("register_local_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT(result != 0); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + CU_ASSERT_FATAL(((local_datareader_crypto *)result)->is_builtin_participant_volatile_message_secure_reader); + reset_exception(&exception); + DDS_Security_PropertySeq_deinit(&datareader_properties); +} + +CU_Test(ddssec_builtin_register_local_datareader, invalid_participant, .init = suite_register_local_datareader_init, .fini = suite_register_local_datareader_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datareader != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datareader_properties, 0, sizeof(datareader_properties)); + + prepare_endpoint_security_attributes(&datareader_security_attributes); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + 8, /*non existing handle*/ + &datareader_properties, + &datareader_security_attributes, + &exception); + + /* Invalid handle should be returned */ + CU_ASSERT(result == 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE); + CU_ASSERT_NSTRING_EQUAL_FATAL(exception.message, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE, sizeof(DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE)); + reset_exception(&exception); +} + diff --git a/src/security/builtin_plugins/tests/register_local_datawriter/src/register_local_datawriter_utests.c b/src/security/builtin_plugins/tests/register_local_datawriter/src/register_local_datawriter_utests.c new file mode 100644 index 0000000..c6d1adc --- /dev/null +++ b/src/security/builtin_plugins/tests/register_local_datawriter/src/register_local_datawriter_utests.c @@ -0,0 +1,333 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_objects.h" + +#if OPENSLL_VERSION_NUMBER >= 0x10002000L +#define AUTH_INCLUDE_EC +#endif + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle = DDS_SECURITY_HANDLE_NIL; +static dds_security_cryptography *crypto = NULL; +static DDS_Security_ParticipantCryptoHandle local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static void suite_register_local_datawriter_init(void) +{ + DDS_Security_IdentityHandle participant_identity = 5; //valid dummy value + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq participant_properties; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; //valid dummy value + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + + /* prepare test shared secret handle */ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(DDS_Security_octet)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (crypto != NULL && crypto->crypto_key_factory != NULL && crypto->crypto_key_factory->register_local_participant != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + local_participant_crypto_handle = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + CU_ASSERT_FATAL (local_participant_crypto_handle != DDS_SECURITY_HANDLE_NIL); + + /* Now call the function. */ + remote_participant_crypto_handle = crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_crypto_handle, + participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + CU_ASSERT_FATAL (remote_participant_crypto_handle != DDS_SECURITY_HANDLE_NIL); + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void suite_register_local_datawriter_fini(void) +{ + unload_plugins(plugins); + shared_secret_handle = DDS_SECURITY_HANDLE_NIL; + crypto = NULL; + local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; + remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void prepare_endpoint_security_attributes(DDS_Security_EndpointSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; +} + +CU_Test(ddssec_builtin_register_local_datawriter, happy_day, .init = suite_register_local_datawriter_init, .fini = suite_register_local_datawriter_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + local_datawriter_crypto *writer_crypto; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datawriter != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + prepare_endpoint_security_attributes(&datawriter_security_attributes); + + datawriter_security_attributes.is_payload_protected = true; + datawriter_security_attributes.plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + if (exception.code != 0) + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT(result != 0); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + writer_crypto = (local_datawriter_crypto *)result; + + CU_ASSERT_FATAL(writer_crypto->writer_key_material_message != NULL); + CU_ASSERT_FATAL(writer_crypto->writer_key_material_payload != NULL); + + CU_ASSERT(master_salt_not_empty(writer_crypto->writer_key_material_message)); + CU_ASSERT(master_key_not_empty(writer_crypto->writer_key_material_message)); + + CU_ASSERT(master_salt_not_empty(writer_crypto->writer_key_material_payload)); + CU_ASSERT(master_key_not_empty(writer_crypto->writer_key_material_payload)); + + CU_ASSERT(writer_crypto->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT); + CU_ASSERT(writer_crypto->data_protectionKind == DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_register_local_datawriter, builtin_endpoint, .init = suite_register_local_datawriter_init, .fini = suite_register_local_datawriter_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + local_datawriter_crypto *writer_crypto; + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + prepare_endpoint_security_attributes(&datawriter_security_attributes); + datawriter_security_attributes.is_payload_protected = true; + datawriter_security_attributes.plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datawriter != NULL); + + datawriter_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datawriter_properties._length = datawriter_properties._maximum = 1; + datawriter_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datawriter_properties._buffer[0].value = ddsrt_strdup("BuiltinSecureEndpointName"); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + if (exception.code != 0) + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT(result != 0); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + writer_crypto = (local_datawriter_crypto *)result; + + CU_ASSERT_FATAL(writer_crypto->writer_key_material_message != NULL); + CU_ASSERT_FATAL(writer_crypto->writer_key_material_payload != NULL); + + CU_ASSERT(master_salt_not_empty(writer_crypto->writer_key_material_message)); + CU_ASSERT(master_key_not_empty(writer_crypto->writer_key_material_message)); + + CU_ASSERT(master_salt_not_empty(writer_crypto->writer_key_material_payload)); + CU_ASSERT(master_key_not_empty(writer_crypto->writer_key_material_payload)); + + CU_ASSERT_FATAL(writer_crypto->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT); + CU_ASSERT_FATAL(writer_crypto->data_protectionKind == DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT); + CU_ASSERT_FATAL(writer_crypto->is_builtin_participant_volatile_message_secure_writer == false); + + reset_exception(&exception); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_register_local_datawriter, special_endpoint_name, .init = suite_register_local_datawriter_init, .fini = suite_register_local_datawriter_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + memset(&datawriter_security_attributes, 0, sizeof(datawriter_security_attributes)); + prepare_endpoint_security_attributes(&datawriter_security_attributes); + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datawriter != NULL); + + /*set special endpoint name*/ + datawriter_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datawriter_properties._length = datawriter_properties._maximum = 1; + datawriter_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datawriter_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureWriter"); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + if (exception.code != 0) + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT(result != 0); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + CU_ASSERT_FATAL(((local_datawriter_crypto *)result)->is_builtin_participant_volatile_message_secure_writer); + + reset_exception(&exception); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_register_local_datawriter, invalid_participant, .init = suite_register_local_datawriter_init, .fini = suite_register_local_datawriter_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datawriter != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + prepare_endpoint_security_attributes(&datawriter_security_attributes); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + 8, /*non existing handle*/ + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + /* Invalid handle should be returned */ + CU_ASSERT(result == 0); + + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE); + CU_ASSERT_NSTRING_EQUAL_FATAL(exception.message, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE, sizeof(DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE)); + + reset_exception(&exception); +} diff --git a/src/security/builtin_plugins/tests/register_local_participant/src/register_local_participant_utests.c b/src/security/builtin_plugins/tests/register_local_participant/src/register_local_participant_utests.c new file mode 100644 index 0000000..967cf67 --- /dev/null +++ b/src/security/builtin_plugins/tests/register_local_participant/src/register_local_participant_utests.c @@ -0,0 +1,154 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#if OPENSLL_VERSION_NUMBER >= 0x10002000L +#define AUTH_INCLUDE_EC +#endif + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static void suite_register_local_participant_init(void) +{ + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); +} + +static void suite_register_local_participant_fini(void) +{ + unload_plugins(plugins); +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +CU_Test(ddssec_builtin_register_local_participant, happy_day, .init = suite_register_local_participant_init, .fini = suite_register_local_participant_fini) +{ + DDS_Security_ParticipantCryptoHandle hdl; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_IdentityHandle participant_identity = 5; //valid dummy value + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 2; /*dummy but valid */ + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_participant != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + + prepare_participant_security_attributes(&participant_security_attributes); + + /* Now call the function. */ + hdl = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (exception.code != 0) + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT(hdl != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + + reset_exception(&exception); + + (void)crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + hdl, + &exception); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_register_local_participant, empty_identity, .init = suite_register_local_participant_init, .fini = suite_register_local_participant_fini) +{ + DDS_Security_ParticipantCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_IdentityHandle participant_identity = 0; //empty identity + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + DDS_Security_PermissionsHandle participant_permissions = 2; /*dummy but valid */ + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_participant != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + if (exception.code != 0) + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(exception.code == DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE); + CU_ASSERT(!strcmp(exception.message, DDS_SECURITY_ERR_IDENTITY_EMPTY_MESSAGE)); + CU_ASSERT(result == 0); + + reset_exception(&exception); +} + diff --git a/src/security/builtin_plugins/tests/register_matched_remote_datareader/src/register_matched_remote_datareader_utests.c b/src/security/builtin_plugins/tests/register_matched_remote_datareader/src/register_matched_remote_datareader_utests.c new file mode 100644 index 0000000..6c6d6ff --- /dev/null +++ b/src/security/builtin_plugins/tests/register_matched_remote_datareader/src/register_matched_remote_datareader_utests.c @@ -0,0 +1,392 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_objects.h" + +#if OPENSLL_VERSION_NUMBER >= 0x10002000L +#define AUTH_INCLUDE_EC +#endif + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle = DDS_SECURITY_HANDLE_NIL; +static dds_security_cryptography *crypto = NULL; +static DDS_Security_ParticipantCryptoHandle local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_DatawriterCryptoHandle local_writer_handle = DDS_SECURITY_HANDLE_NIL; + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static void prepare_endpoint_security_attributes(DDS_Security_EndpointSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; +} + +static void register_local_regular() +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + prepare_endpoint_security_attributes(&datawriter_security_attributes); + datawriter_security_attributes.is_payload_protected = true; + datawriter_security_attributes.plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + + /* Now call the function. */ + + local_writer_handle = crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); +} + +static void suite_register_matched_remote_datareader_init(void) +{ + DDS_Security_IdentityHandle participant_identity = 5; //valid dummy value + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq participant_properties; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; //valid dummy value + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + /* prepare test shared secret handle */ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(DDS_Security_octet)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (crypto != NULL && crypto->crypto_key_factory != NULL && crypto->crypto_key_factory->register_local_participant != NULL); + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + local_participant_crypto_handle = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + CU_ASSERT_FATAL (local_participant_crypto_handle != DDS_SECURITY_HANDLE_NIL); + + /* Now call the function. */ + remote_participant_crypto_handle = crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_crypto_handle, + participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + CU_ASSERT_FATAL (remote_participant_crypto_handle != DDS_SECURITY_HANDLE_NIL); + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void suite_register_matched_remote_datareader_fini(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + (void)crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + remote_participant_crypto_handle, + &exception); + (void)crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &exception); + unload_plugins(plugins); + shared_secret_handle = DDS_SECURITY_HANDLE_NIL; + crypto = NULL; + local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; + remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +CU_Test(ddssec_builtin_register_remote_datareader, happy_day, .init = suite_register_matched_remote_datareader_init, .fini = suite_register_matched_remote_datareader_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + bool unregister_result = false; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + remote_datareader_crypto *reader_crypto; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datareader != NULL); + + register_local_regular(); + + /* Now call the function. */ + + result = crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_handle, + remote_participant_crypto_handle, + shared_secret_handle, + true, + &exception); + + if (exception.code != 0) + printf("register_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT(result != 0); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + reader_crypto = (remote_datareader_crypto *)result; + CU_ASSERT_FATAL(reader_crypto->writer2reader_key_material_message != NULL); + CU_ASSERT_FATAL(reader_crypto->writer2reader_key_material_payload != NULL); + CU_ASSERT(master_salt_not_empty(reader_crypto->writer2reader_key_material_message)); + CU_ASSERT(master_key_not_empty(reader_crypto->writer2reader_key_material_message)); + CU_ASSERT(master_salt_not_empty(reader_crypto->writer2reader_key_material_payload)); + CU_ASSERT(master_key_not_empty(reader_crypto->writer2reader_key_material_payload)); + CU_ASSERT_FATAL(reader_crypto->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT); + reset_exception(&exception); + + unregister_result = crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, result, &exception); + CU_ASSERT_FATAL(unregister_result); +} + +/* test if function returns volatile secure reader crypto if the writer is volatile secure*/ +CU_Test(ddssec_builtin_register_remote_datareader, volatile_secure, .init = suite_register_matched_remote_datareader_init, .fini = suite_register_matched_remote_datareader_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + DDS_Security_DatawriterCryptoHandle local_volatile_secure_writer; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + prepare_endpoint_security_attributes(&datawriter_security_attributes); + + datawriter_security_attributes.is_discovery_protected = true; + datawriter_security_attributes.is_submessage_protected = true; + + datawriter_properties._length = datawriter_properties._maximum = 1; + datawriter_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datawriter_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datawriter_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureWriter"); + datawriter_properties._buffer[0].propagate = false; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datawriter != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datareader != NULL); + + local_volatile_secure_writer = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_volatile_secure_writer, + remote_participant_crypto_handle, + shared_secret_handle, + true, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result != 0); + CU_ASSERT_FATAL(((remote_datareader_crypto *)result)->is_builtin_participant_volatile_message_secure_reader); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_OK_CODE); + reset_exception(&exception); + + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, result, &exception); + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, local_volatile_secure_writer, &exception); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_register_remote_datareader, with_origin_authentication, .init = suite_register_matched_remote_datareader_init, .fini = suite_register_matched_remote_datareader_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + bool unregister_result = false; + local_datawriter_crypto *writer_crypto; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + remote_datareader_crypto *reader_crypto; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datareader != NULL); + register_local_regular(); + + /*set writer protection kind */ + writer_crypto = (local_datawriter_crypto *)local_writer_handle; + writer_crypto->metadata_protectionKind = DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION; + writer_crypto = (local_datawriter_crypto *)local_writer_handle; + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_handle, + remote_participant_crypto_handle, + shared_secret_handle, + true, + &exception); + + if (exception.code != 0) + printf("register_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT(result != 0); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + reader_crypto = (remote_datareader_crypto *)result; + CU_ASSERT_FATAL(reader_crypto->writer2reader_key_material_message != NULL); + CU_ASSERT_FATAL(reader_crypto->writer2reader_key_material_payload != NULL); + CU_ASSERT(master_salt_not_empty(reader_crypto->writer2reader_key_material_message)); + CU_ASSERT(master_key_not_empty(reader_crypto->writer2reader_key_material_message)); + CU_ASSERT(master_salt_not_empty(reader_crypto->writer2reader_key_material_payload)); + CU_ASSERT(master_key_not_empty(reader_crypto->writer2reader_key_material_payload)); + CU_ASSERT_FATAL(reader_crypto->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION); + reset_exception(&exception); + + /* test to unregister with local writer*/ + unregister_result = crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, local_writer_handle, &exception); + CU_ASSERT_FATAL(unregister_result); + + unregister_result = crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, result, &exception); + CU_ASSERT_FATAL(!unregister_result); + + reset_exception(&exception); +} + +/* test invalid parameter*/ +CU_Test(ddssec_builtin_register_remote_datareader, invalid_participant, .init = suite_register_matched_remote_datareader_init, .fini = suite_register_matched_remote_datareader_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datareader != NULL); + + register_local_regular(); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_handle, + 0, + shared_secret_handle, + true, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result == 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE); + reset_exception(&exception); +} + +/* test invalid parameter*/ +CU_Test(ddssec_builtin_register_remote_datareader, invalid_writer_properties, .init = suite_register_matched_remote_datareader_init, .fini = suite_register_matched_remote_datareader_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datareader != NULL); + register_local_regular(); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + 0, + remote_participant_crypto_handle, + shared_secret_handle, + true, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result == 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE); + reset_exception(&exception); +} diff --git a/src/security/builtin_plugins/tests/register_matched_remote_datawriter/src/register_matched_remote_datawriter_utests.c b/src/security/builtin_plugins/tests/register_matched_remote_datawriter/src/register_matched_remote_datawriter_utests.c new file mode 100644 index 0000000..635c018 --- /dev/null +++ b/src/security/builtin_plugins/tests/register_matched_remote_datawriter/src/register_matched_remote_datawriter_utests.c @@ -0,0 +1,376 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_objects.h" + +#if OPENSLL_VERSION_NUMBER >= 0x10002000L +#define AUTH_INCLUDE_EC +#endif + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle = DDS_SECURITY_HANDLE_NIL; +static dds_security_cryptography *crypto = NULL; +static DDS_Security_ParticipantCryptoHandle local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_DatareaderCryptoHandle local_reader_handle = DDS_SECURITY_HANDLE_NIL; + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static void prepare_endpoint_security_attributes(DDS_Security_EndpointSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; +} + +static void register_local_regular() +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + memset(&datareader_properties, 0, sizeof(datareader_properties)); + + prepare_endpoint_security_attributes(&datareader_security_attributes); + + /* Now call the function. */ + + local_reader_handle = crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); +} + +static void suite_register_matched_remote_datawriter_init(void) +{ + DDS_Security_IdentityHandle participant_identity = 5; //valid dummy value + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq participant_properties; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; //valid dummy value + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + + /* prepare test shared secret handle */ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(DDS_Security_octet)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (crypto != NULL && crypto->crypto_key_factory != NULL && crypto->crypto_key_factory->register_local_participant != NULL) + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + + prepare_participant_security_attributes(&participant_security_attributes); + local_participant_crypto_handle = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + CU_ASSERT_FATAL (local_participant_crypto_handle != DDS_SECURITY_HANDLE_NIL); + + /* Now call the function. */ + remote_participant_crypto_handle = crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_crypto_handle, + participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + CU_ASSERT_FATAL (remote_participant_crypto_handle != DDS_SECURITY_HANDLE_NIL); +} + +static void suite_register_matched_remote_datawriter_fini(void) +{ + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = (DDS_Security_SharedSecretHandleImpl *)shared_secret_handle; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + CU_ASSERT_EQUAL_FATAL (crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + remote_participant_crypto_handle, + &exception), true); + + CU_ASSERT_EQUAL_FATAL (crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &exception), true); + + unload_plugins(plugins); + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); + shared_secret_handle = DDS_SECURITY_HANDLE_NIL; + crypto = NULL; + local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; + remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + + +CU_Test(ddssec_builtin_register_remote_datawriter, happy_day, .init = suite_register_matched_remote_datawriter_init, .fini = suite_register_matched_remote_datawriter_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + bool unregister_result = false; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + remote_datawriter_crypto *writer_crypto; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datawriter != NULL); + register_local_regular(); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_handle, + remote_participant_crypto_handle, + shared_secret_handle, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result != 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_OK_CODE); + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + writer_crypto = (remote_datawriter_crypto *)result; + CU_ASSERT_FATAL(writer_crypto->reader2writer_key_material != NULL); + CU_ASSERT(master_salt_not_empty(writer_crypto->reader2writer_key_material)); + CU_ASSERT(master_key_not_empty(writer_crypto->reader2writer_key_material)); + CU_ASSERT_FATAL(writer_crypto->reader2writer_key_material->receiver_specific_key_id == 0); + reset_exception(&exception); + + unregister_result = crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, result, &exception); + CU_ASSERT_FATAL(unregister_result); +} + +/* test if function returns volatile secure writer crypto if the reader is volatile secure*/ +CU_Test(ddssec_builtin_register_remote_datawriter, volatile_secure, .init = suite_register_matched_remote_datawriter_init, .fini = suite_register_matched_remote_datawriter_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + DDS_Security_DatareaderCryptoHandle local_volatile_secure_reader; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datawriter != NULL); + + datareader_properties._length = datareader_properties._maximum = 1; + datareader_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datareader_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datareader_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureReader"); + datareader_properties._buffer[0].propagate = false; + memset(&datareader_security_attributes, 0, sizeof(datareader_security_attributes)); + + datareader_security_attributes.is_discovery_protected = true; + datareader_security_attributes.is_submessage_protected = true; + + local_volatile_secure_reader = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_volatile_secure_reader, + remote_participant_crypto_handle, + shared_secret_handle, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result != 0); + CU_ASSERT_FATAL(((remote_datawriter_crypto *)result)->is_builtin_participant_volatile_message_secure_writer); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_OK_CODE); + reset_exception(&exception); + + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, result, &exception); + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_volatile_secure_reader, &exception); + DDS_Security_PropertySeq_deinit(&datareader_properties); +} + +CU_Test(ddssec_builtin_register_remote_datawriter, with_origin_authentication, .init = suite_register_matched_remote_datawriter_init, .fini = suite_register_matched_remote_datawriter_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + bool unregister_result = false; + local_datareader_crypto *reader_crypto; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + remote_datawriter_crypto *writer_crypto; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datawriter != NULL); + register_local_regular(); + + /*set reader protection kind */ + reader_crypto = (local_datareader_crypto *)local_reader_handle; + reader_crypto->metadata_protectionKind = DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION; + reader_crypto = (local_datareader_crypto *)local_reader_handle; + /* Now call the function. */ + + result = crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_handle, + remote_participant_crypto_handle, + shared_secret_handle, + &exception); + + if (exception.code != 0) + printf("register_remote_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT(result != 0); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + writer_crypto = (remote_datawriter_crypto *)result; + CU_ASSERT_FATAL(writer_crypto->reader2writer_key_material != NULL); + CU_ASSERT(master_salt_not_empty(writer_crypto->reader2writer_key_material)); + CU_ASSERT(master_key_not_empty(writer_crypto->reader2writer_key_material)); + CU_ASSERT_FATAL(writer_crypto->reader2writer_key_material->receiver_specific_key_id != 0); + CU_ASSERT(master_receiver_specific_key_not_empty(writer_crypto->reader2writer_key_material)); + reset_exception(&exception); + + /*test unregister the local pair*/ + unregister_result = crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_reader_handle, &exception); + CU_ASSERT_FATAL(unregister_result); + + /* unregister remote should give error*/ + unregister_result = crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, result, &exception); + CU_ASSERT_FATAL(!unregister_result); + reset_exception(&exception); +} + +/* test invalid parameter*/ +CU_Test(ddssec_builtin_register_remote_datawriter, invalid_participant, .init = suite_register_matched_remote_datawriter_init, .fini = suite_register_matched_remote_datawriter_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datawriter != NULL); + register_local_regular(); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_handle, + 0, + shared_secret_handle, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result == 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE); + reset_exception(&exception); +} + +/* test invalid parameter */ +CU_Test(ddssec_builtin_register_remote_datawriter, invalid_writer_properties, .init = suite_register_matched_remote_datawriter_init, .fini = suite_register_matched_remote_datawriter_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datawriter != NULL); + register_local_regular(); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + 0, + remote_participant_crypto_handle, + shared_secret_handle, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result == 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE); + reset_exception(&exception); +} + diff --git a/src/security/builtin_plugins/tests/register_matched_remote_participant/src/register_matched_remote_participant_utests.c b/src/security/builtin_plugins/tests/register_matched_remote_participant/src/register_matched_remote_participant_utests.c new file mode 100644 index 0000000..2402697 --- /dev/null +++ b/src/security/builtin_plugins/tests/register_matched_remote_participant/src/register_matched_remote_participant_utests.c @@ -0,0 +1,229 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#if OPENSLL_VERSION_NUMBER >= 0x10002000L +#define AUTH_INCLUDE_EC +#endif + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static void suite_register_matched_remote_participant_init(void) +{ + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); +} + +static void suite_register_matched_remote_participant_fini(void) +{ + unload_plugins(plugins); +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +CU_Test(ddssec_builtin_register_remote_participant, happy_day, .init = suite_register_matched_remote_participant_init, .fini = suite_register_matched_remote_participant_fini) +{ + DDS_Security_ParticipantCryptoHandle local_crypto_handle; + DDS_Security_ParticipantCryptoHandle remote_crypto_handle; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_IdentityHandle participant_identity = 5; //valid dummy value + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq participant_properties; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; /*valid dummy value */ + DDS_Security_SharedSecretHandle shared_secret_handle; + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + DDS_Security_PermissionsHandle participant_permissions = 2; /*valid but dummy value */ + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + /* prepare test shared secret handle */ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(DDS_Security_octet)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_participant != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + + prepare_participant_security_attributes(&participant_security_attributes); + local_crypto_handle = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + CU_ASSERT_FATAL(local_crypto_handle != DDS_SECURITY_HANDLE_NIL); + + /* Now call the function. */ + remote_crypto_handle = crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_crypto_handle, + participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (exception.code != 0) + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT(remote_crypto_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + reset_exception(&exception); + + (void)crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + remote_crypto_handle, + &exception); + reset_exception(&exception); + + (void)crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + local_crypto_handle, + &exception); + reset_exception(&exception); + + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +CU_Test(ddssec_builtin_register_remote_participant, empty_identity, .init = suite_register_matched_remote_participant_init, .fini = suite_register_matched_remote_participant_fini) +{ + DDS_Security_ParticipantCryptoHandle local_crypto_handle; + DDS_Security_ParticipantCryptoHandle remote_crypto_handle; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_IdentityHandle participant_identity = 5; //empty identity + DDS_Security_IdentityHandle remote_participant_identity_empty = 0; //empty identity + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + DDS_Security_PermissionsHandle participant_permissions = 2; /*valid but dummy value */ + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + DDS_Security_SharedSecretHandle shared_secret_handle; + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; //valid dummy value + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(DDS_Security_octet)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_participant != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + + prepare_participant_security_attributes(&participant_security_attributes); + + /* Now call the function. */ + local_crypto_handle = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + remote_crypto_handle = crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_crypto_handle, + remote_participant_identity_empty, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (exception.code != 0) + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(remote_crypto_handle == DDS_SECURITY_HANDLE_NIL); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE); + CU_ASSERT(!strcmp(exception.message, DDS_SECURITY_ERR_IDENTITY_EMPTY_MESSAGE)); + reset_exception(&exception); + + (void)crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + local_crypto_handle, + &exception); + reset_exception(&exception); + + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + diff --git a/src/security/builtin_plugins/tests/set_remote_datareader_crypto_tokens/src/set_remote_datareader_crypto_tokens_utests.c b/src/security/builtin_plugins/tests/set_remote_datareader_crypto_tokens/src/set_remote_datareader_crypto_tokens_utests.c new file mode 100644 index 0000000..c8297bb --- /dev/null +++ b/src/security/builtin_plugins/tests/set_remote_datareader_crypto_tokens/src/set_remote_datareader_crypto_tokens_utests.c @@ -0,0 +1,980 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 +#define CRYPTO_TRANSFORM_KIND(k) (*(uint32_t *)&((k)[0])) +#define CRYPTO_TRANSFORM_ID(k) (*(uint32_t *)&((k)[0])) + +static const char *CRYPTO_TOKEN_CLASS_ID = "DDS:Crypto:AES_GCM_GMAC"; +static const char *CRYPTO_TOKEN_PROPERTY_NAME = "dds.cryp.keymat"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_particpant_crypto = 0; +static DDS_Security_ParticipantCryptoHandle remote_particpant_crypto = 0; +static DDS_Security_DatawriterCryptoHandle remote_reader_crypto = 0; +static DDS_Security_DatareaderCryptoHandle local_writer_crypto = 0; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static void allocate_shared_secret(void) +{ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void +deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int +register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + local_particpant_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_particpant_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_particpant_crypto ? 0 : -1; +} + +static int +register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_particpant_crypto = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_particpant_crypto, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_particpant_crypto == 0) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_particpant_crypto ? 0 : -1; +} + +static int +register_local_datawriter(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + memset(&datawriter_security_attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + + datawriter_security_attributes.is_discovery_protected = true; + + local_writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_particpant_crypto, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + if (local_writer_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_writer_crypto ? 0 : -1; +} + +static int +register_remote_datareader(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + remote_reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_crypto, + remote_particpant_crypto, + shared_secret_handle, + true, + &exception); + + if (remote_reader_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_reader_crypto ? 0 : -1; +} + +static void +reset_exception( + DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void suite_set_remote_datareader_crypto_tokens_init(void) +{ + allocate_shared_secret(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_local_datawriter(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_datareader(), 0); +} + +static void suite_set_remote_datareader_crypto_tokens_fini(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + if (remote_reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, remote_reader_crypto, &exception); + reset_exception(&exception); + } + if (local_writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, local_writer_crypto, &exception); + reset_exception(&exception); + } + if (remote_particpant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_particpant_crypto, &exception); + reset_exception(&exception); + } + if (local_particpant_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_particpant_crypto, &exception); + reset_exception(&exception); + } + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void create_key_material(DDS_Security_OctetSeq *seq, bool include_specific_key) +{ + DDS_Security_KeyMaterial_AES_GCM_GMAC keymat; + DDS_Security_Serializer serializer; + unsigned char *buffer; + size_t length; + + memset(&keymat, 0, sizeof(keymat)); + + keymat.transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + RAND_bytes(keymat.sender_key_id, 4); + + keymat.master_salt._length = keymat.master_salt._maximum = DDS_SECURITY_MASTER_SALT_SIZE_256; + keymat.master_salt._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SALT_SIZE_256); + RAND_bytes(keymat.master_salt._buffer, DDS_SECURITY_MASTER_SALT_SIZE_256); + + keymat.master_sender_key._length = keymat.master_sender_key._maximum = DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256; + keymat.master_sender_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + RAND_bytes(keymat.master_sender_key._buffer, DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + + if (include_specific_key) + { + RAND_bytes(keymat.receiver_specific_key_id, 4); + keymat.master_receiver_specific_key._length = keymat.master_receiver_specific_key._maximum = DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256; + keymat.master_receiver_specific_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + RAND_bytes(keymat.master_receiver_specific_key._buffer, DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + } + + serializer = DDS_Security_Serializer_new(256, 256); + DDS_Security_Serialize_KeyMaterial_AES_GCM_GMAC(serializer, &keymat); + DDS_Security_Serializer_buffer(serializer, &buffer, &length); + DDS_Security_Serializer_free(serializer); + + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&keymat); + + seq->_length = seq->_maximum = (uint32_t)length; + seq->_buffer = buffer; +} + +static void init_key_material(DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat, bool include_specific_key) +{ + memset(keymat, 0, sizeof(*keymat)); + + keymat->transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + RAND_bytes(keymat->sender_key_id, 4); + + keymat->master_salt._length = keymat->master_salt._maximum = DDS_SECURITY_MASTER_SALT_SIZE_256; + keymat->master_salt._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SALT_SIZE_256); + RAND_bytes(keymat->master_salt._buffer, DDS_SECURITY_MASTER_SALT_SIZE_256); + + keymat->master_sender_key._length = keymat->master_sender_key._maximum = DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256; + keymat->master_sender_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + RAND_bytes(keymat->master_sender_key._buffer, DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + + if (include_specific_key) + { + RAND_bytes(keymat->receiver_specific_key_id, 4); + keymat->master_receiver_specific_key._length = keymat->master_receiver_specific_key._maximum = DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256; + keymat->master_receiver_specific_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + RAND_bytes(keymat->master_receiver_specific_key._buffer, DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + } +} + +static void deinit_key_material(DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat) +{ + ddsrt_free(keymat->master_salt._buffer); + ddsrt_free(keymat->master_sender_key._buffer); + ddsrt_free(keymat->master_receiver_specific_key._buffer); +} + +static void create_reader_tokens(DDS_Security_DatawriterCryptoTokenSeq *tokens) +{ + tokens->_length = tokens->_maximum = 1; + tokens->_buffer = DDS_Security_DataHolderSeq_allocbuf(1); + tokens->_buffer[0].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + tokens->_buffer[0].binary_properties._length = 1; + tokens->_buffer[0].binary_properties._maximum = 1; + tokens->_buffer[0].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + tokens->_buffer[0].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + create_key_material(&tokens->_buffer[0].binary_properties._buffer[0].value, false); +} + +static void create_reader_tokens_no_key_material(DDS_Security_DatawriterCryptoTokenSeq *tokens) +{ + tokens->_length = tokens->_maximum = 1; + tokens->_buffer = DDS_Security_DataHolderSeq_allocbuf(1); + tokens->_buffer[0].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + tokens->_buffer[0].binary_properties._length = 1; + tokens->_buffer[0].binary_properties._maximum = 1; + tokens->_buffer[0].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + tokens->_buffer[0].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); +} + +static void serialize_key_material(DDS_Security_OctetSeq *seq, DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat) +{ + DDS_Security_Serializer serializer; + unsigned char *buffer; + size_t length; + + serializer = DDS_Security_Serializer_new(256, 256); + DDS_Security_Serialize_KeyMaterial_AES_GCM_GMAC(serializer, keymat); + DDS_Security_Serializer_buffer(serializer, &buffer, &length); + DDS_Security_Serializer_free(serializer); + + seq->_length = seq->_maximum = (uint32_t) length; + seq->_buffer = buffer; +} + +CU_Test(ddssec_builtin_set_remote_datareader_crypto_tokens, happy_day, .init = suite_set_remote_datareader_crypto_tokens_init, .fini = suite_set_remote_datareader_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + create_reader_tokens(&tokens); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + DDS_Security_DataHolderSeq_deinit(&tokens); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_set_remote_datareader_crypto_tokens, single_token, .init = suite_set_remote_datareader_crypto_tokens_init, .fini = suite_set_remote_datareader_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens != NULL); + memset(&tokens, 0, sizeof(tokens)); + create_reader_tokens(&tokens); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + DDS_Security_DataHolderSeq_deinit(&tokens); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_set_remote_datareader_crypto_tokens, invalid_args, .init = suite_set_remote_datareader_crypto_tokens_init, .fini = suite_set_remote_datareader_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + create_reader_tokens(&tokens); + + /* invalid token seq = NULL */ + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + NULL, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + 0, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid remote_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + 0, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid local_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + 1, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid remote_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + 1, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + DDS_Security_DataHolderSeq_deinit(&tokens); +} + +CU_Test(ddssec_builtin_set_remote_datareader_crypto_tokens, invalid_tokens, .init = suite_set_remote_datareader_crypto_tokens_init, .fini = suite_set_remote_datareader_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + DDS_Security_DatawriterCryptoTokenSeq empty_tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + memset(&empty_tokens, 0, sizeof(empty_tokens)); + create_reader_tokens(&tokens); + + /* empty token sequence */ + { + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &empty_tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + } + + /* DDS_Security_DatawriterCryptoTokenSeq with empty token */ + { + empty_tokens._length = 1; + empty_tokens._buffer = DDS_Security_DataHolderSeq_allocbuf(1); + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &empty_tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_DataHolderSeq_deinit(&empty_tokens); + } + + /* invalid token class id */ + { + ddsrt_free(tokens._buffer[0].class_id); + tokens._buffer[0].class_id = ddsrt_strdup("invalid class"); + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + ddsrt_free(tokens._buffer[0].class_id); + tokens._buffer[0].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + } + + /* no key material, binary_property missing */ + { + tokens._buffer[0].binary_properties._length = 0; + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + tokens._buffer[0].binary_properties._length = 1; + } + + /* no key material, property is empty */ + { + DDS_Security_BinaryProperty_t *saved_buffer = tokens._buffer[0].binary_properties._buffer; + tokens._buffer[0].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + ddsrt_free(tokens._buffer[0].binary_properties._buffer); + tokens._buffer[0].binary_properties._buffer = saved_buffer; + } + + /* invalid property name */ + { + ddsrt_free(tokens._buffer[0].binary_properties._buffer[0].name); + tokens._buffer[0].binary_properties._buffer[0].name = ddsrt_strdup("invalid_key_mat_name"); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + ddsrt_free(tokens._buffer[0].binary_properties._buffer[0].name); + tokens._buffer[0].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); +} + +CU_Test(ddssec_builtin_set_remote_datareader_crypto_tokens, invalid_key_material, .init = suite_set_remote_datareader_crypto_tokens_init, .fini = suite_set_remote_datareader_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + DDS_Security_KeyMaterial_AES_GCM_GMAC keymat; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + create_reader_tokens_no_key_material(&tokens); + + /* empty key material */ + { + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + } + + /* invalid transform kind */ + { + init_key_material(&keymat, false); + keymat.transformation_kind[2] = 1; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* no master salt */ + { + init_key_material(&keymat, false); + + DDS_Security_OctetSeq_deinit(&keymat.master_salt); + keymat.master_salt._buffer = NULL; + keymat.master_salt._length = keymat.master_salt._maximum = 0; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* empty master salt */ + { + init_key_material(&keymat, false); + + memset(keymat.master_salt._buffer, 0, keymat.master_salt._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* incorrect master salt */ + { + init_key_material(&keymat, false); + + keymat.master_salt._length = 16; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* no master sender key */ + { + init_key_material(&keymat, false); + + DDS_Security_OctetSeq_deinit(&keymat.master_sender_key); + + keymat.master_sender_key._buffer = NULL; + keymat.master_sender_key._length = keymat.master_sender_key._maximum = 0; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* empty master sender key */ + { + init_key_material(&keymat, false); + + memset(keymat.master_sender_key._buffer, 0, keymat.master_sender_key._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* incorrect master sender key */ + { + init_key_material(&keymat, false); + + memset(keymat.master_sender_key._buffer, 0, keymat.master_sender_key._length); + keymat.master_sender_key._length = 16; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* no master receiver specific key */ + { + init_key_material(&keymat, true); + + DDS_Security_OctetSeq_deinit(&keymat.master_receiver_specific_key); + + keymat.master_receiver_specific_key._buffer = NULL; + keymat.master_receiver_specific_key._length = keymat.master_receiver_specific_key._maximum = 0; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* nempty master receiver specific key */ + { + init_key_material(&keymat, true); + + memset(keymat.master_receiver_specific_key._buffer, 0, keymat.master_receiver_specific_key._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* incorrect master receiver specific key */ + { + init_key_material(&keymat, true); + + memset(keymat.master_receiver_specific_key._buffer, 0, keymat.master_receiver_specific_key._length); + keymat.master_receiver_specific_key._length = 16; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* invalid key material */ + { + init_key_material(&keymat, true); + + memset(keymat.master_receiver_specific_key._buffer, 0, keymat.master_receiver_specific_key._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + RAND_bytes(tokens._buffer[0].binary_properties._buffer[0].value._buffer, (int) tokens._buffer[0].binary_properties._buffer[0].value._length); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); +} diff --git a/src/security/builtin_plugins/tests/set_remote_datawriter_crypto_tokens/src/set_remote_datawriter_crypto_tokens_utests.c b/src/security/builtin_plugins/tests/set_remote_datawriter_crypto_tokens/src/set_remote_datawriter_crypto_tokens_utests.c new file mode 100644 index 0000000..90c8112 --- /dev/null +++ b/src/security/builtin_plugins/tests/set_remote_datawriter_crypto_tokens/src/set_remote_datawriter_crypto_tokens_utests.c @@ -0,0 +1,1029 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 +#define CRYPTO_TRANSFORM_KIND(k) (*(uint32_t *)&((k)[0])) +#define CRYPTO_TRANSFORM_ID(k) (*(uint32_t *)&((k)[0])) + +static const char *CRYPTO_TOKEN_CLASS_ID = "DDS:Crypto:AES_GCM_GMAC"; +static const char *CRYPTO_TOKEN_PROPERTY_NAME = "dds.cryp.keymat"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_particpant_crypto = 0; +static DDS_Security_ParticipantCryptoHandle remote_particpant_crypto = 0; +static DDS_Security_DatawriterCryptoHandle remote_writer_crypto = 0; +static DDS_Security_DatareaderCryptoHandle local_reader_crypto = 0; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static void allocate_shared_secret(void) +{ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + local_particpant_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_particpant_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_particpant_crypto ? 0 : -1; +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_particpant_crypto = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_particpant_crypto, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_particpant_crypto == 0) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_particpant_crypto ? 0 : -1; +} + +static int register_local_datareader(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + memset(&datareader_properties, 0, sizeof(datareader_properties)); + memset(&datareader_security_attributes, 0, sizeof(datareader_security_attributes)); + datareader_security_attributes.is_discovery_protected = true; + + local_reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_particpant_crypto, + &datareader_properties, + &datareader_security_attributes, + &exception); + + if (local_reader_crypto == 0) + { + printf("register_local_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_reader_crypto ? 0 : -1; +} + +static int register_remote_datawriter(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + remote_writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_crypto, + remote_particpant_crypto, + shared_secret_handle, + &exception); + + if (remote_writer_crypto == 0) + { + printf("register_matched_remote_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_writer_crypto ? 0 : -1; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void suite_set_remote_datawriter_crypto_tokens_init(void) +{ + allocate_shared_secret(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_local_datareader(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_datawriter(), 0); +} + +static void suite_set_remote_datawriter_crypto_tokens_fini(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + if (remote_writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, remote_writer_crypto, &exception); + reset_exception(&exception); + } + if (local_reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_reader_crypto, &exception); + reset_exception(&exception); + } + if (remote_particpant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_particpant_crypto, &exception); + reset_exception(&exception); + } + if (local_particpant_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_particpant_crypto, &exception); + reset_exception(&exception); + } + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void create_key_material(DDS_Security_OctetSeq *seq, bool include_specific_key) +{ + DDS_Security_KeyMaterial_AES_GCM_GMAC keymat; + DDS_Security_Serializer serializer; + unsigned char *buffer; + size_t length; + + memset(&keymat, 0, sizeof(keymat)); + + keymat.transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + RAND_bytes(keymat.sender_key_id, 4); + + keymat.master_salt._length = keymat.master_salt._maximum = DDS_SECURITY_MASTER_SALT_SIZE_256; + keymat.master_salt._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SALT_SIZE_256); + RAND_bytes(keymat.master_salt._buffer, DDS_SECURITY_MASTER_SALT_SIZE_256); + + keymat.master_sender_key._length = keymat.master_sender_key._maximum = DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256; + keymat.master_sender_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + RAND_bytes(keymat.master_sender_key._buffer, DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + + if (include_specific_key) + { + RAND_bytes(keymat.receiver_specific_key_id, 4); + keymat.master_receiver_specific_key._length = keymat.master_receiver_specific_key._maximum = DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256; + keymat.master_receiver_specific_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + RAND_bytes(keymat.master_receiver_specific_key._buffer, DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + } + + serializer = DDS_Security_Serializer_new(256, 256); + DDS_Security_Serialize_KeyMaterial_AES_GCM_GMAC(serializer, &keymat); + DDS_Security_Serializer_buffer(serializer, &buffer, &length); + DDS_Security_Serializer_free(serializer); + + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&keymat); + + seq->_length = seq->_maximum = (uint32_t) length; + seq->_buffer = buffer; +} + +static void init_key_material(DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat, bool include_specific_key) +{ + memset(keymat, 0, sizeof(*keymat)); + + keymat->transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + RAND_bytes(keymat->sender_key_id, 4); + + keymat->master_salt._length = keymat->master_salt._maximum = DDS_SECURITY_MASTER_SALT_SIZE_256; + keymat->master_salt._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SALT_SIZE_256); + RAND_bytes(keymat->master_salt._buffer, DDS_SECURITY_MASTER_SALT_SIZE_256); + + keymat->master_sender_key._length = keymat->master_sender_key._maximum = DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256; + keymat->master_sender_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + RAND_bytes(keymat->master_sender_key._buffer, DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + + if (include_specific_key) + { + RAND_bytes(keymat->receiver_specific_key_id, 4); + keymat->master_receiver_specific_key._length = keymat->master_receiver_specific_key._maximum = DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256; + keymat->master_receiver_specific_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + RAND_bytes(keymat->master_receiver_specific_key._buffer, DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + } +} + +static void deinit_key_material(DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat) +{ + ddsrt_free(keymat->master_salt._buffer); + ddsrt_free(keymat->master_sender_key._buffer); + ddsrt_free(keymat->master_receiver_specific_key._buffer); +} + +static void create_writer_tokens(DDS_Security_DatawriterCryptoTokenSeq *tokens, uint32_t num) +{ + tokens->_length = tokens->_maximum = num; + tokens->_buffer = DDS_Security_DataHolderSeq_allocbuf(num); + for (uint32_t i = 0; i < num; i++) + { + tokens->_buffer[i].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + tokens->_buffer[i].binary_properties._length = 1; + tokens->_buffer[i].binary_properties._maximum = 1; + tokens->_buffer[i].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + tokens->_buffer[i].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + create_key_material(&tokens->_buffer[i].binary_properties._buffer[0].value, false); + } +} + +static void create_writer_tokens_no_key_material(DDS_Security_DatawriterCryptoTokenSeq *tokens, uint32_t num) +{ + tokens->_length = tokens->_maximum = num; + tokens->_buffer = DDS_Security_DataHolderSeq_allocbuf(num); + for (uint32_t i = 0; i < num; i++) + { + tokens->_buffer[i].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + tokens->_buffer[i].binary_properties._length = 1; + tokens->_buffer[i].binary_properties._maximum = 1; + tokens->_buffer[i].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + tokens->_buffer[i].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + } +} + +static void serialize_key_material(DDS_Security_OctetSeq *seq, DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat) +{ + DDS_Security_Serializer serializer; + unsigned char *buffer; + size_t length; + + serializer = DDS_Security_Serializer_new(256, 256); + DDS_Security_Serialize_KeyMaterial_AES_GCM_GMAC(serializer, keymat); + DDS_Security_Serializer_buffer(serializer, &buffer, &length); + DDS_Security_Serializer_free(serializer); + + seq->_length = seq->_maximum = (uint32_t) length; + seq->_buffer = buffer; +} + +CU_Test(ddssec_builtin_set_remote_datawriter_crypto_tokens, happy_day, .init = suite_set_remote_datawriter_crypto_tokens_init, .fini = suite_set_remote_datawriter_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + create_writer_tokens(&tokens, 2); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + DDS_Security_DataHolderSeq_deinit(&tokens); + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_set_remote_datawriter_crypto_tokens, single_token, .init = suite_set_remote_datawriter_crypto_tokens_init, .fini = suite_set_remote_datawriter_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens != NULL); + memset(&tokens, 0, sizeof(tokens)); + create_writer_tokens(&tokens, 1); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + DDS_Security_DataHolderSeq_deinit(&tokens); + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_set_remote_datawriter_crypto_tokens, invalid_args, .init = suite_set_remote_datawriter_crypto_tokens_init, .fini = suite_set_remote_datawriter_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens != NULL); + memset(&tokens, 0, sizeof(tokens)); + create_writer_tokens(&tokens, 2); + + /* invalid token seq = NULL */ + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + NULL, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid local_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + 0, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid remote_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + 0, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid local_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + 1, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid remote_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + 1, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_DataHolderSeq_deinit(&tokens); +} + +CU_Test(ddssec_builtin_set_remote_datawriter_crypto_tokens, invalid_tokens, .init = suite_set_remote_datawriter_crypto_tokens_init, .fini = suite_set_remote_datawriter_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + DDS_Security_DatawriterCryptoTokenSeq empty_tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + memset(&empty_tokens, 0, sizeof(empty_tokens)); + create_writer_tokens(&tokens, 2); + + /* empty token sequence */ + { + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &empty_tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + } + + /* DDS_Security_DatawriterCryptoTokenSeq with empty token */ + { + empty_tokens._length = 1; + empty_tokens._buffer = DDS_Security_DataHolderSeq_allocbuf(1); + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &empty_tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_DataHolderSeq_deinit(&empty_tokens); + } + + /* invalid token class id */ + { + ddsrt_free(tokens._buffer[0].class_id); + tokens._buffer[0].class_id = ddsrt_strdup("invalid class"); + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + } + + /* invalid token class id */ + { + ddsrt_free(tokens._buffer[0].class_id); + tokens._buffer[0].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + ddsrt_free(tokens._buffer[1].class_id); + tokens._buffer[1].class_id = ddsrt_strdup("invalid class"); + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + ddsrt_free(tokens._buffer[1].class_id); + tokens._buffer[1].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + } + + /* no key material, binary_property missing */ + { + tokens._buffer[0].binary_properties._length = 0; + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + tokens._buffer[0].binary_properties._length = 1; + } + + /* no key material, binary_property missing */ + { + tokens._buffer[1].binary_properties._length = 0; + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + tokens._buffer[1].binary_properties._length = 1; + } + + /* no key material, property is empty */ + { + DDS_Security_BinaryProperty_t *saved_buffer = tokens._buffer[0].binary_properties._buffer; + tokens._buffer[0].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + ddsrt_free(tokens._buffer[0].binary_properties._buffer); + tokens._buffer[0].binary_properties._buffer = saved_buffer; + } + + /* invalid property name */ + { + ddsrt_free(tokens._buffer[0].binary_properties._buffer[0].name); + tokens._buffer[0].binary_properties._buffer[0].name = ddsrt_strdup("invalid_key_mat_name"); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + ddsrt_free(tokens._buffer[0].binary_properties._buffer[0].name); + tokens._buffer[0].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + } + + /* invalid property name */ + { + ddsrt_free(tokens._buffer[1].binary_properties._buffer[0].name); + tokens._buffer[1].binary_properties._buffer[0].name = ddsrt_strdup("invalid_key_mat_name"); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + ddsrt_free(tokens._buffer[1].binary_properties._buffer[0].name); + tokens._buffer[1].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); +} + +CU_Test(ddssec_builtin_set_remote_datawriter_crypto_tokens, invalid_key_material, .init = suite_set_remote_datawriter_crypto_tokens_init, .fini = suite_set_remote_datawriter_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + DDS_Security_KeyMaterial_AES_GCM_GMAC keymat; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens != NULL); + memset(&tokens, 0, sizeof(tokens)); + create_writer_tokens_no_key_material(&tokens, 1); + + /* empty key material */ + { + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + } + + /* invalid transform kind */ + { + init_key_material(&keymat, false); + keymat.transformation_kind[2] = 1; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* no master salt */ + { + init_key_material(&keymat, false); + + DDS_Security_OctetSeq_deinit(&keymat.master_salt); + keymat.master_salt._buffer = NULL; + keymat.master_salt._length = keymat.master_salt._maximum = 0; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* empty master salt */ + { + init_key_material(&keymat, false); + + memset(keymat.master_salt._buffer, 0, keymat.master_salt._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* incorrect master salt */ + { + init_key_material(&keymat, false); + + keymat.master_salt._length = 16; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* no master sender key */ + { + init_key_material(&keymat, false); + + DDS_Security_OctetSeq_deinit(&keymat.master_sender_key); + + keymat.master_sender_key._buffer = NULL; + keymat.master_sender_key._length = keymat.master_sender_key._maximum = 0; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* empty master sender key */ + { + init_key_material(&keymat, false); + + memset(keymat.master_sender_key._buffer, 0, keymat.master_sender_key._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* incorrect master sender key */ + { + init_key_material(&keymat, false); + + memset(keymat.master_sender_key._buffer, 0, keymat.master_sender_key._length); + keymat.master_sender_key._length = 16; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* no master receiver specific key */ + { + init_key_material(&keymat, true); + + DDS_Security_OctetSeq_deinit(&keymat.master_receiver_specific_key); + + keymat.master_receiver_specific_key._buffer = NULL; + keymat.master_receiver_specific_key._length = keymat.master_receiver_specific_key._maximum = 0; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* nempty master receiver specific key */ + { + init_key_material(&keymat, true); + + memset(keymat.master_receiver_specific_key._buffer, 0, keymat.master_receiver_specific_key._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* incorrect master receiver specific key */ + { + init_key_material(&keymat, true); + + memset(keymat.master_receiver_specific_key._buffer, 0, keymat.master_receiver_specific_key._length); + keymat.master_receiver_specific_key._length = 16; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* invalid key material */ + { + init_key_material(&keymat, true); + + memset(keymat.master_receiver_specific_key._buffer, 0, keymat.master_receiver_specific_key._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + RAND_bytes(tokens._buffer[0].binary_properties._buffer[0].value._buffer, (int) tokens._buffer[0].binary_properties._buffer[0].value._length); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); +} diff --git a/src/security/builtin_plugins/tests/set_remote_participant_crypto_tokens/src/set_remote_participant_crypto_tokens_utests.c b/src/security/builtin_plugins/tests/set_remote_participant_crypto_tokens/src/set_remote_participant_crypto_tokens_utests.c new file mode 100644 index 0000000..433b8fc --- /dev/null +++ b/src/security/builtin_plugins/tests/set_remote_participant_crypto_tokens/src/set_remote_participant_crypto_tokens_utests.c @@ -0,0 +1,545 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static const char *CRYPTO_TOKEN_CLASS_ID = "DDS:Crypto:AES_GCM_GMA"; +static const char *CRYPTO_TOKEN_PROPERTY_NAME = "dds.cryp.keymat"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_crypto_handle = DDS_SECURITY_HANDLE_NIL; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoTokenSeq tokens; + +static void allocate_shared_secret(void) +{ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + memset(&tokens, 0, sizeof(tokens)); + + prepare_participant_security_attributes(&participant_security_attributes); + + local_crypto_handle = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_crypto_handle == DDS_SECURITY_HANDLE_NIL) + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + + return local_crypto_handle ? 0 : -1; +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_crypto_handle = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_crypto_handle, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_crypto_handle == DDS_SECURITY_HANDLE_NIL) + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + + return remote_crypto_handle ? 0 : -1; +} + +static int create_crypto_tokens(void) +{ + DDS_Security_boolean status; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + status = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_crypto_handle, + remote_crypto_handle, + &exception); + if (!status) + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + + return status ? 0 : -1; +} + +static void unregister_participants(void) +{ + DDS_Security_boolean status; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + if (tokens._length != 0) + { + status = crypto->crypto_key_exchange->return_crypto_tokens(crypto->crypto_key_exchange, &tokens, &exception); + if (!status) + printf("return_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + if (local_crypto_handle) + { + status = crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_crypto_handle, &exception); + if (!status) + printf("unregister_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + if (remote_crypto_handle) + { + status = crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_crypto_handle, &exception); + if (!status) + printf("unregister_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } +} + +static void suite_set_remote_participant_crypto_tokens_init(void) +{ + allocate_shared_secret(); + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); + CU_ASSERT_EQUAL_FATAL (create_crypto_tokens(), 0); +} + +static void suite_set_remote_participant_crypto_tokens_fini(void) +{ + unregister_participants(); + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +CU_Test(ddssec_builtin_set_remote_participant_crypto_tokens, happy_day, .init = suite_set_remote_participant_crypto_tokens_init, .fini = suite_set_remote_participant_crypto_tokens_fini) +{ + DDS_Security_boolean result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_participant_crypto_tokens != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_set_remote_participant_crypto_tokens, invalid_args, .init = suite_set_remote_participant_crypto_tokens_init, .fini = suite_set_remote_participant_crypto_tokens_fini) +{ + DDS_Security_boolean result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq participant_properties; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_participant_crypto_tokens != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + + /* invalid token seq = NULL */ + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + NULL, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid local_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + 0, + remote_crypto_handle, + &tokens, + &exception); + if (!result) + printf("set_remote_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid remote_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + 0, + &tokens, + &exception); + if (!result) + printf("set_remote_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid local_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + 1, + remote_crypto_handle, + &tokens, + &exception); + if (!result) + printf("set_remote_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid remote_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + 1, + &tokens, + &exception); + if (!result) + printf("set_remote_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_set_remote_participant_crypto_tokens, invalid_tokens, .init = suite_set_remote_participant_crypto_tokens_init, .fini = suite_set_remote_participant_crypto_tokens_fini) +{ + DDS_Security_boolean result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantCryptoTokenSeq invalid_tokens; + DDS_Security_KeyMaterial_AES_GCM_GMAC keymat; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_participant_crypto_tokens != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + memset(&keymat, 0, sizeof(keymat)); + + memset(&invalid_tokens, 0, sizeof(invalid_tokens)); + + /* empty token sequence */ + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* DDS_Security_ParticipantCryptoTokenSeq with empty token */ + invalid_tokens._length = 1; + invalid_tokens._buffer = DDS_Security_DataHolderSeq_allocbuf(1); + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid token class id */ + invalid_tokens._buffer[0].class_id = ddsrt_strdup("invalid class"); + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + ddsrt_free(invalid_tokens._buffer[0].class_id); + reset_exception(&exception); + + /* no key material, binary_property missing */ + invalid_tokens._buffer[0].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* no key material, property is empty */ + invalid_tokens._buffer[0].binary_properties._length = 1; + invalid_tokens._buffer[0].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid property name */ + invalid_tokens._buffer[0].binary_properties._buffer[0].name = ddsrt_strdup("invalid_key_mat_name"); + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + ddsrt_free(invalid_tokens._buffer[0].binary_properties._buffer[0].name); + reset_exception(&exception); + + /* invalid property name */ + invalid_tokens._buffer[0].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* empty key material */ + invalid_tokens._buffer[0].binary_properties._buffer[0].value._length = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._maximum = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._buffer = (unsigned char *)&keymat; + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + keymat.transformation_kind[3] = 5; + + /* invalid CryptoTransformKind */ + invalid_tokens._buffer[0].binary_properties._buffer[0].value._length = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._maximum = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._buffer = (unsigned char *)&keymat; + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + keymat.transformation_kind[3] = 2; + keymat.master_salt._length = 16; + keymat.master_salt._buffer = DDS_Security_OctetSeq_allocbuf(32); + + /* invalid master salt */ + invalid_tokens._buffer[0].binary_properties._buffer[0].value._length = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._maximum = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._buffer = (unsigned char *)&keymat; + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + keymat.master_salt._length = 32; + + /* invalid master salt */ + invalid_tokens._buffer[0].binary_properties._buffer[0].value._length = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._maximum = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._buffer = (unsigned char *)&keymat; + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + invalid_tokens._buffer[0].binary_properties._buffer[0].value._length = 0; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._maximum = 0; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._buffer = NULL; + DDS_Security_ParticipantCryptoTokenSeq_deinit(&invalid_tokens); + DDS_Security_OctetSeq_deinit(&keymat.master_salt); +} diff --git a/src/security/builtin_plugins/tests/validate_begin_handshake_reply/src/validate_begin_handshake_reply_utests.c b/src/security/builtin_plugins/tests/validate_begin_handshake_reply/src/validate_begin_handshake_reply_utests.c index 3b2907e..b3871db 100644 --- a/src/security/builtin_plugins/tests/validate_begin_handshake_reply/src/validate_begin_handshake_reply_utests.c +++ b/src/security/builtin_plugins/tests/validate_begin_handshake_reply/src/validate_begin_handshake_reply_utests.c @@ -25,27 +25,12 @@ #include "dds/ddsrt/string.h" #include #include +#include "dds/ddsrt/bswap.h" #include "dds/ddsrt/environ.h" -#include "dds/ddsrt/endian.h" #include "CUnit/CUnit.h" #include "CUnit/Test.h" #include "assert.h" - -#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN -unsigned bswap4u (unsigned x); -unsigned bswap4u (unsigned x) -{ - return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24); -} -#define toBE4u(x) bswap4u (x) -#define fromBE4u(x) bswap4u (x) -#else -#define toBE4u(x) (x) -#define fromBE4u(x) (x) -#endif - - static const char * AUTH_PROTOCOL_CLASS_ID = "DDS:Auth:PKI-DH:1.0"; static const char * PERM_ACCESS_CLASS_ID = "DDS:Access:Permissions:1.0"; @@ -582,9 +567,9 @@ validate_local_identity(const char* trusted_ca_dir) local_participant_data = DDS_Security_ParticipantBuiltinTopicData_alloc(); memcpy(&local_participant_data->key[0], &local_participant_guid, 12); /* convert from big-endian format to native format */ - local_participant_data->key[0] = fromBE4u(local_participant_data->key[0]); - local_participant_data->key[1] = fromBE4u(local_participant_data->key[1]); - local_participant_data->key[2] = fromBE4u(local_participant_data->key[2]); + local_participant_data->key[0] = ddsrt_fromBE4u(local_participant_data->key[0]); + local_participant_data->key[1] = ddsrt_fromBE4u(local_participant_data->key[1]); + local_participant_data->key[2] = ddsrt_fromBE4u(local_participant_data->key[2]); initialize_identity_token(&local_participant_data->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); initialize_permissions_token(&local_participant_data->permissions_token, RSA_2048_ALGORITHM_NAME); @@ -853,9 +838,9 @@ validate_remote_identities (const char *remote_id_certificate) remote_participant_data1 = DDS_Security_ParticipantBuiltinTopicData_alloc(); memcpy(&remote_participant_data1->key[0], &remote_participant_guid1, 12); - remote_participant_data1->key[0] = fromBE4u(remote_participant_data1->key[0]); - remote_participant_data1->key[1] = fromBE4u(remote_participant_data1->key[1]); - remote_participant_data1->key[2] = fromBE4u(remote_participant_data1->key[2]); + remote_participant_data1->key[0] = ddsrt_fromBE4u(remote_participant_data1->key[0]); + remote_participant_data1->key[1] = ddsrt_fromBE4u(remote_participant_data1->key[1]); + remote_participant_data1->key[2] = ddsrt_fromBE4u(remote_participant_data1->key[2]); initialize_identity_token(&remote_participant_data1->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); @@ -866,9 +851,9 @@ validate_remote_identities (const char *remote_id_certificate) remote_participant_data2 = DDS_Security_ParticipantBuiltinTopicData_alloc(); memcpy(&remote_participant_data2->key[0], &remote_participant_guid2, 12); - remote_participant_data2->key[0] = fromBE4u(remote_participant_data2->key[0]); - remote_participant_data2->key[1] = fromBE4u(remote_participant_data2->key[1]); - remote_participant_data2->key[2] = fromBE4u(remote_participant_data2->key[2]); + remote_participant_data2->key[0] = ddsrt_fromBE4u(remote_participant_data2->key[0]); + remote_participant_data2->key[1] = ddsrt_fromBE4u(remote_participant_data2->key[1]); + remote_participant_data2->key[2] = ddsrt_fromBE4u(remote_participant_data2->key[2]); initialize_identity_token(&remote_participant_data2->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); initialize_permissions_token(&remote_participant_data2->permissions_token, RSA_2048_ALGORITHM_NAME); @@ -1019,7 +1004,7 @@ serializer_participant_data( DDS_Security_Serializer serializer; serializer = DDS_Security_Serializer_new(1024, 1024); - DDD_Security_Serialize_ParticipantBuiltinTopicData(serializer, pdata); + DDS_Security_Serialize_ParticipantBuiltinTopicData(serializer, pdata); DDS_Security_Serializer_buffer(serializer, buffer, size); DDS_Security_Serializer_free(serializer); } diff --git a/src/security/core/include/dds/security/core/dds_security_serialize.h b/src/security/core/include/dds/security/core/dds_security_serialize.h index 1454d9c..f6a0251 100644 --- a/src/security/core/include/dds/security/core/dds_security_serialize.h +++ b/src/security/core/include/dds/security/core/dds_security_serialize.h @@ -65,12 +65,12 @@ DDS_Security_Serialize_DataHolderSeq( const DDS_Security_DataHolderSeq *seq); DDS_EXPORT void -DDD_Security_Serialize_ParticipantBuiltinTopicData( +DDS_Security_Serialize_ParticipantBuiltinTopicData( DDS_Security_Serializer ser, DDS_Security_ParticipantBuiltinTopicData *pdata); DDS_EXPORT void -DDD_Security_Serialize_KeyMaterial_AES_GCM_GMAC( +DDS_Security_Serialize_KeyMaterial_AES_GCM_GMAC( DDS_Security_Serializer ser, const DDS_Security_KeyMaterial_AES_GCM_GMAC *data); @@ -84,18 +84,18 @@ DDS_Security_Deserializer_free( DDS_Security_Deserializer deserializer); DDS_EXPORT int -DDD_Security_Deserialize_ParticipantBuiltinTopicData( +DDS_Security_Deserialize_ParticipantBuiltinTopicData( DDS_Security_Deserializer deserializer, DDS_Security_ParticipantBuiltinTopicData *pdata, DDS_Security_SecurityException *ex); DDS_EXPORT void -DDD_Security_BuiltinTopicKeyBE( +DDS_Security_BuiltinTopicKeyBE( DDS_Security_BuiltinTopicKey_t dst, const DDS_Security_BuiltinTopicKey_t src); DDS_EXPORT int -DDD_Security_Deserialize_KeyMaterial_AES_GCM_GMAC( +DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC( DDS_Security_Deserializer dser, DDS_Security_KeyMaterial_AES_GCM_GMAC *data); diff --git a/src/security/core/include/dds/security/core/dds_security_types.h b/src/security/core/include/dds/security/core/dds_security_types.h index e9748a5..953220f 100644 --- a/src/security/core/include/dds/security/core/dds_security_types.h +++ b/src/security/core/include/dds/security/core/dds_security_types.h @@ -50,11 +50,11 @@ typedef enum typedef struct DDS_Security_KeyMaterial_AES_GCM_GMAC { DDS_Security_CryptoTransformKind transformation_kind; - DDS_Security_OctetSeq master_salt; /*size shall be 32*/ + DDS_Security_OctetSeq master_salt; /*size shall be 16 or 32*/ DDS_Security_CryptoTransformKeyId sender_key_id; - DDS_Security_OctetSeq master_sender_key; /*size shall be 32*/ + DDS_Security_OctetSeq master_sender_key; /*size shall be 16 or 32*/ DDS_Security_CryptoTransformKeyId receiver_specific_key_id; - DDS_Security_OctetSeq master_receiver_specific_key; /*size shall be 32*/ + DDS_Security_OctetSeq master_receiver_specific_key; /*size shall be 0, 16 or 32*/ } DDS_Security_KeyMaterial_AES_GCM_GMAC; struct CryptoTransformIdentifier { diff --git a/src/security/core/include/dds/security/core/dds_security_utils.h b/src/security/core/include/dds/security/core/dds_security_utils.h index e2ade89..fe975d6 100644 --- a/src/security/core/include/dds/security/core/dds_security_utils.h +++ b/src/security/core/include/dds/security/core/dds_security_utils.h @@ -341,39 +341,39 @@ ddssec_strchrs ( #define DDS_Security_ParticipantCryptoTokenSeq_alloc() \ - (DDS_Security_ParticipantCryptoTokenSeq *)DDS_Security_DataHolderSeq_alloc()) + DDS_Security_DataHolderSeq_alloc()) #define DDS_Security_ParticipantCryptoTokenSeq_freebuf(s) \ - DDS_Security_DataHolderSeq_freebuf((DDS_Security_DataHolderSeq *)(s)) + DDS_Security_DataHolderSeq_freebuf(s) #define DDS_Security_ParticipantCryptoTokenSeq_free(s) \ - DDS_Security_DataHolderSeq_free((DDS_Security_DataHolderSeq *)(s)) + DDS_Security_DataHolderSeq_free(s) #define DDS_Security_ParticipantCryptoTokenSeq_deinit(s) \ - DDS_Security_DataHolderSeq_deinit((DDS_Security_DataHolderSeq *)(s)) + DDS_Security_DataHolderSeq_deinit(s) #define DDS_Security_ParticipantCryptoTokenSeq_copy(d,s) \ - DDS_Security_DataHolderSeq_copy((DDS_Security_DataHolderSeq *)(d), (const DDS_Security_DataHolderSeq *)(s)) + DDS_Security_DataHolderSeq_copy((d), (s)) -#define DDS_Security_ParticipantCryptoHandleSeq_alloc() (DDS_Security_ParticipantCryptoHandleSeq*)DDS_Security_HandleSeq_alloc() +#define DDS_Security_ParticipantCryptoHandleSeq_alloc() DDS_Security_HandleSeq_alloc() #define DDS_Security_ParticipantCryptoHandleSeq_allocbuf(l) DDS_Security_HandleSeq_allocbuf(l) -#define DDS_Security_ParticipantCryptoHandleSeq_freebuf(s) DDS_Security_HandleSeq_freebuf((DDS_Security_HandleSeq*)s) -#define DDS_Security_ParticipantCryptoHandleSeq_free(s) DDS_Security_HandleSeq_free((DDS_Security_HandleSeq*)s) -#define DDS_Security_ParticipantCryptoHandleSeq_deinit(s) DDS_Security_HandleSeq_deinit((DDS_Security_HandleSeq*)s) +#define DDS_Security_ParticipantCryptoHandleSeq_freebuf(s) DDS_Security_HandleSeq_freebuf(s) +#define DDS_Security_ParticipantCryptoHandleSeq_free(s) DDS_Security_HandleSeq_free(s) +#define DDS_Security_ParticipantCryptoHandleSeq_deinit(s) DDS_Security_HandleSeq_deinit(s) -#define DDS_Security_DatawriterCryptoHandleSeq_alloc() (DDS_Security_DatawriterCryptoHandleSeq*)DDS_Security_HandleSeq_alloc() +#define DDS_Security_DatawriterCryptoHandleSeq_alloc() DDS_Security_HandleSeq_alloc() #define DDS_Security_DatawriterCryptoHandleSeq_allocbuf(l) DDS_Security_HandleSeq_allocbuf(l) -#define DDS_Security_DatawriterCryptoHandleSeq_freebuf(s) DDS_Security_HandleSeq_freebuf((DDS_Security_HandleSeq*)s) -#define DDS_Security_DatawriterCryptoHandleSeq_free(s) DDS_Security_HandleSeq_free((DDS_Security_HandleSeq*)s) -#define DDS_Security_DatawriterCryptoHandleSeq_deinit(s) DDS_Security_HandleSeq_deinit((DDS_Security_HandleSeq*)s) +#define DDS_Security_DatawriterCryptoHandleSeq_freebuf(s) DDS_Security_HandleSeq_freebuf(s) +#define DDS_Security_DatawriterCryptoHandleSeq_free(s) DDS_Security_HandleSeq_free(s) +#define DDS_Security_DatawriterCryptoHandleSeq_deinit(s) DDS_Security_HandleSeq_deinit(s) -#define DDS_Security_DatareaderCryptoHandleSeq_alloc() (DDS_Security_DatareaderCryptoHandleSeq*)DDS_Security_HandleSeq_alloc() +#define DDS_Security_DatareaderCryptoHandleSeq_alloc() DDS_Security_HandleSeq_alloc() #define DDS_Security_DatareaderCryptoHandleSeq_allocbuf(l) DDS_Security_HandleSeq_allocbuf(l) -#define DDS_Security_DatareaderCryptoHandleSeq_freebuf(s) DDS_Security_HandleSeq_freebuf((DDS_Security_HandleSeq*)s) -#define DDS_Security_DatareaderCryptoHandleSeq_free(s) DDS_Security_HandleSeq_free((DDS_Security_HandleSeq*)s) -#define DDS_Security_DatareaderCryptoHandleSeq_deinit(s) DDS_Security_HandleSeq_deinit((DDS_Security_HandleSeq*)s) +#define DDS_Security_DatareaderCryptoHandleSeq_freebuf(s) DDS_Security_HandleSeq_freebuf(s) +#define DDS_Security_DatareaderCryptoHandleSeq_free(s) DDS_Security_HandleSeq_free(s) +#define DDS_Security_DatareaderCryptoHandleSeq_deinit(s) DDS_Security_HandleSeq_deinit(s) -#define DDS_Security_CryptoTokenSeq_alloc() (DDS_Security_CryptoTokenSeq*)DDS_Security_DataHolderSeq_alloc() +#define DDS_Security_CryptoTokenSeq_alloc() DDS_Security_DataHolderSeq_alloc() #define DDS_Security_CryptoTokenSeq_allocbuf(l) DDS_Security_DataHolderSeq_allocbuf(l) -#define DDS_Security_CryptoTokenSeq_freebuf(s) DDS_Security_DataHolderSeq_freebuf((DDS_Security_CryptoTokenSeq*)s) -#define DDS_Security_CryptoTokenSeq_free(s) DDS_Security_DataHolderSeq_free((DDS_Security_CryptoTokenSeq*)s) +#define DDS_Security_CryptoTokenSeq_freebuf(s) DDS_Security_DataHolderSeq_freebuf(s) +#define DDS_Security_CryptoTokenSeq_free(s) DDS_Security_DataHolderSeq_free(s) /* for DEBUG purposes */ diff --git a/src/security/core/include/dds/security/core/shared_secret.h b/src/security/core/include/dds/security/core/shared_secret.h index e0262d7..e0302e9 100644 --- a/src/security/core/include/dds/security/core/shared_secret.h +++ b/src/security/core/include/dds/security/core/shared_secret.h @@ -9,32 +9,25 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ - - #ifndef SRC_SECURITY_CORE_INCLUDE_SHARED_SECRET_HANDLE_H_ #define SRC_SECURITY_CORE_INCLUDE_SHARED_SECRET_HANDLE_H_ -#include "dds/export.h" +#include #include + +#include "dds/export.h" #include "dds/security/dds_security_api.h" - typedef struct DDS_Security_SharedSecretHandleImpl { - - DDS_Security_octet* shared_secret; - DDS_Security_long shared_secret_size; - DDS_Security_octet challenge1[DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE]; - DDS_Security_octet challenge2[DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE]; - + DDS_Security_octet* shared_secret; + DDS_Security_long shared_secret_size; + DDS_Security_octet challenge1[DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE]; + DDS_Security_octet challenge2[DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE]; } DDS_Security_SharedSecretHandleImpl; -DDS_EXPORT const DDS_Security_octet* get_challenge1_from_secret_handle( DDS_Security_SharedSecretHandle handle); - -DDS_EXPORT const DDS_Security_octet* get_challenge2_from_secret_handle( DDS_Security_SharedSecretHandle handle ); - -DDS_EXPORT const DDS_Security_octet* get_secret_from_secret_handle( DDS_Security_SharedSecretHandle handle ); - -DDS_EXPORT int32_t get_secret_size_from_secret_handle( DDS_Security_SharedSecretHandle handle ); +DDS_EXPORT const DDS_Security_octet* get_challenge1_from_secret_handle (DDS_Security_SharedSecretHandle handle); +DDS_EXPORT const DDS_Security_octet* get_challenge2_from_secret_handle (DDS_Security_SharedSecretHandle handle); +DDS_EXPORT const DDS_Security_octet* get_secret_from_secret_handle (DDS_Security_SharedSecretHandle handle); +DDS_EXPORT size_t get_secret_size_from_secret_handle (DDS_Security_SharedSecretHandle handle); #endif /* SRC_SECURITY_CORE_INCLUDE_SHARED_SECRET_H_ */ - diff --git a/src/security/core/src/dds_security_serialize.c b/src/security/core/src/dds_security_serialize.c index afa9733..d5a37d4 100644 --- a/src/security/core/src/dds_security_serialize.c +++ b/src/security/core/src/dds_security_serialize.c @@ -13,6 +13,7 @@ #include #include +#include "dds/ddsrt/bswap.h" #include "dds/ddsrt/heap.h" #include "dds/ddsrt/atomics.h" #include "dds/ddsrt/string.h" @@ -92,7 +93,6 @@ #define PID_PARTICIPANT_SECURITY_INFO 0x1005u #define PID_IDENTITY_STATUS_TOKEN 0x1006u - struct DDS_Security_Serializer { unsigned char *buffer; size_t size; @@ -211,7 +211,7 @@ DDS_Security_Serialize_update_len( { unsigned short len; - len = (unsigned short)(ser->offset - ser->marker - sizeof(unsigned short)); + len = (unsigned short)(ser->offset - ser->marker - sizeof(len)); *(unsigned short *)&(ser->buffer[ser->marker]) = ddsrt_toBE2u(len); } @@ -220,11 +220,11 @@ DDS_Security_Serialize_uint16( DDS_Security_Serializer ser, unsigned short value) { - serbuffer_align(ser, sizeof(unsigned short)); - serbuffer_adjust_size(ser, sizeof(unsigned short)); + serbuffer_align(ser, sizeof(value)); + serbuffer_adjust_size(ser, sizeof(value)); *(unsigned short *)&(ser->buffer[ser->offset]) = ddsrt_toBE2u(value); - ser->offset += sizeof(unsigned short); + ser->offset += sizeof(value); } static void @@ -232,11 +232,11 @@ DDS_Security_Serialize_uint32_t( DDS_Security_Serializer ser, uint32_t value) { - serbuffer_align(ser, sizeof(uint32_t)); - serbuffer_adjust_size(ser, sizeof(uint32_t)); + serbuffer_align(ser, sizeof(value)); + serbuffer_adjust_size(ser, sizeof(value)); *(uint32_t *)&(ser->buffer[ser->offset]) = ddsrt_toBE4u(value); - ser->offset += sizeof(uint32_t); + ser->offset += sizeof(value); } static void @@ -244,12 +244,10 @@ DDS_Security_Serialize_string( DDS_Security_Serializer ser, const char *str) { - size_t len; - - len = strlen(str) + 1; + size_t len = strlen(str) + 1; DDS_Security_Serialize_uint32_t(ser, (uint32_t)len); - serbuffer_adjust_size(ser, len ); + serbuffer_adjust_size(ser, len); memcpy(&(ser->buffer[ser->offset]), str, len); ser->offset += len; @@ -416,7 +414,7 @@ DDS_Security_Serialize_ParticipantSecurityInfo( void -DDD_Security_Serialize_ParticipantBuiltinTopicData( +DDS_Security_Serialize_ParticipantBuiltinTopicData( DDS_Security_Serializer ser, DDS_Security_ParticipantBuiltinTopicData *pdata) { @@ -432,7 +430,7 @@ DDD_Security_Serialize_ParticipantBuiltinTopicData( } static void -DDD_Security_Serialize_OctetArray( +DDS_Security_Serialize_OctetArray( DDS_Security_Serializer ser, const DDS_Security_octet *data, uint32_t length) @@ -443,15 +441,15 @@ DDD_Security_Serialize_OctetArray( } void -DDD_Security_Serialize_KeyMaterial_AES_GCM_GMAC( +DDS_Security_Serialize_KeyMaterial_AES_GCM_GMAC( DDS_Security_Serializer ser, const DDS_Security_KeyMaterial_AES_GCM_GMAC *data) { - DDD_Security_Serialize_OctetArray(ser, data->transformation_kind, sizeof(data->transformation_kind)); + DDS_Security_Serialize_OctetArray(ser, data->transformation_kind, sizeof(data->transformation_kind)); DDS_Security_Serialize_OctetSeq(ser, &data->master_salt); - DDD_Security_Serialize_OctetArray(ser, data->sender_key_id, sizeof(data->sender_key_id)); + DDS_Security_Serialize_OctetArray(ser, data->sender_key_id, sizeof(data->sender_key_id)); DDS_Security_Serialize_OctetSeq(ser, &data->master_sender_key); - DDD_Security_Serialize_OctetArray(ser, data->receiver_specific_key_id, sizeof(data->receiver_specific_key_id)); + DDS_Security_Serialize_OctetArray(ser, data->receiver_specific_key_id, sizeof(data->receiver_specific_key_id)); DDS_Security_Serialize_OctetSeq(ser, &data->master_receiver_specific_key); } @@ -500,7 +498,7 @@ DDS_Security_Deserialize_uint16( DDS_Security_Deserializer dser, unsigned short *value) { - size_t l = sizeof(unsigned short); + size_t l = sizeof(*value); DDS_Security_Deserialize_align(dser, l); @@ -519,7 +517,7 @@ DDS_Security_Deserialize_uint32_t( DDS_Security_Deserializer dser, uint32_t *value) { - size_t l = sizeof(uint32_t); + size_t l = sizeof(*value); DDS_Security_Deserialize_align(dser, l); @@ -692,9 +690,7 @@ DDS_Security_Deserialize_BuiltinTopicKey( DDS_Security_Deserializer dser, DDS_Security_BuiltinTopicKey_t key) { - int r; - - r = DDS_Security_Deserialize_uint32_t(dser, (uint32_t *)&key[0]) && + int r = DDS_Security_Deserialize_uint32_t(dser, (uint32_t *)&key[0]) && DDS_Security_Deserialize_uint32_t(dser, (uint32_t *)&key[1]) && DDS_Security_Deserialize_uint32_t(dser, (uint32_t *)&key[2]); @@ -710,16 +706,12 @@ DDS_Security_Deserialize_ParticipantSecurityInfo( DDS_Security_Deserializer dser, DDS_Security_ParticipantSecurityInfo *info) { - int r; - - r = DDS_Security_Deserialize_uint32_t(dser, &info->participant_security_attributes) && + return DDS_Security_Deserialize_uint32_t(dser, &info->participant_security_attributes) && DDS_Security_Deserialize_uint32_t(dser, &info->plugin_participant_security_attributes); - - return r; } int -DDD_Security_Deserialize_ParticipantBuiltinTopicData( +DDS_Security_Deserialize_ParticipantBuiltinTopicData( DDS_Security_Deserializer dser, DDS_Security_ParticipantBuiltinTopicData *pdata, DDS_Security_SecurityException *ex) @@ -786,7 +778,7 @@ DDD_Security_Deserialize_ParticipantBuiltinTopicData( } void -DDD_Security_BuiltinTopicKeyBE( +DDS_Security_BuiltinTopicKeyBE( DDS_Security_BuiltinTopicKey_t dst, const DDS_Security_BuiltinTopicKey_t src) { @@ -796,18 +788,16 @@ DDD_Security_BuiltinTopicKeyBE( } int -DDD_Security_Deserialize_KeyMaterial_AES_GCM_GMAC( +DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC( DDS_Security_Deserializer dser, DDS_Security_KeyMaterial_AES_GCM_GMAC *data) { - int r = 0; - - r = DDS_Security_Deserialize_OctetArray(dser, data->transformation_kind, sizeof(data->transformation_kind)) && + memset(data, 0, sizeof(*data)); + return + DDS_Security_Deserialize_OctetArray(dser, data->transformation_kind, sizeof(data->transformation_kind)) && DDS_Security_Deserialize_OctetSeq(dser, &data->master_salt) && DDS_Security_Deserialize_OctetArray(dser, data->sender_key_id, sizeof(data->sender_key_id)) && DDS_Security_Deserialize_OctetSeq(dser, &data->master_sender_key) && DDS_Security_Deserialize_OctetArray(dser, data->receiver_specific_key_id, sizeof(data->receiver_specific_key_id)) && DDS_Security_Deserialize_OctetSeq(dser, &data->master_receiver_specific_key); - - return r; } diff --git a/src/security/core/src/dds_security_utils.c b/src/security/core/src/dds_security_utils.c index 8e417e6..665e587 100644 --- a/src/security/core/src/dds_security_utils.c +++ b/src/security/core/src/dds_security_utils.c @@ -46,6 +46,7 @@ DDS_Security_BinaryProperty_deinit( } ddsrt_free(p->name); + memset (p->value._buffer, 0, p->value._length); /* because key material can be stored in binary property */ ddsrt_free(p->value._buffer); } @@ -906,51 +907,45 @@ DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit( { if (key_material) { if (key_material->master_receiver_specific_key._buffer != NULL) { + memset (key_material->master_receiver_specific_key._buffer, 0, key_material->master_receiver_specific_key._length); ddsrt_free(key_material->master_receiver_specific_key._buffer); } if( key_material->master_salt._buffer != NULL){ + memset (key_material->master_salt._buffer, 0, key_material->master_salt._length); ddsrt_free(key_material->master_salt._buffer); } if( key_material->master_sender_key._buffer != NULL){ + memset (key_material->master_sender_key._buffer, 0, key_material->master_sender_key._length); ddsrt_free(key_material->master_sender_key._buffer); } } } +static uint32_t DDS_Security_getKeySize (const DDS_Security_PropertySeq *properties) +{ + const DDS_Security_Property_t *key_size_property; + if (properties != NULL) + { + key_size_property = DDS_Security_PropertySeq_find_property (properties, "dds.sec.crypto.keysize"); + if (key_size_property != NULL && !strcmp(key_size_property->value, "128")) + return 128; + } + return 256; +} DDS_Security_CryptoTransformKind_Enum DDS_Security_basicprotectionkind2transformationkind( - const DDS_Security_PropertySeq *properties, + const DDS_Security_PropertySeq *properties, DDS_Security_BasicProtectionKind protection) { - int keysize=256; - const DDS_Security_Property_t *key_size_property = NULL; - if( properties != NULL ){ - key_size_property = DDS_Security_PropertySeq_find_property( - properties, "dds.sec.crypto.keysize"); - - if (key_size_property != NULL) { - if (strcmp(key_size_property->value, "128") == 0) { - keysize = 128; - } - } - } - + uint32_t keysize = DDS_Security_getKeySize (properties); switch (protection) { case DDS_SECURITY_BASICPROTECTION_KIND_NONE: return CRYPTO_TRANSFORMATION_KIND_NONE; case DDS_SECURITY_BASICPROTECTION_KIND_SIGN: - if( keysize == 128 ){ - return CRYPTO_TRANSFORMATION_KIND_AES128_GMAC; - } else{ - return CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; - } + return (keysize == 128) ? CRYPTO_TRANSFORMATION_KIND_AES128_GMAC : CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; case DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT: - if( keysize == 128 ){ - return CRYPTO_TRANSFORMATION_KIND_AES128_GCM; - } else{ - return CRYPTO_TRANSFORMATION_KIND_AES256_GCM; - } + return (keysize == 128) ? CRYPTO_TRANSFORMATION_KIND_AES128_GCM : CRYPTO_TRANSFORMATION_KIND_AES256_GCM; default: return CRYPTO_TRANSFORMATION_KIND_INVALID; } @@ -961,41 +956,22 @@ DDS_Security_protectionkind2transformationkind( const DDS_Security_PropertySeq *properties, DDS_Security_ProtectionKind protection) { - int keysize=256; - const DDS_Security_Property_t *key_size_property = NULL; - if( properties != NULL ){ - key_size_property = DDS_Security_PropertySeq_find_property( - properties, "dds.sec.crypto.keysize"); - if (key_size_property != NULL) { - if (strcmp(key_size_property->value, "128") == 0) { - keysize = 128; - } - } - } - + uint32_t keysize = DDS_Security_getKeySize (properties); switch (protection) { case DDS_SECURITY_PROTECTION_KIND_NONE: return CRYPTO_TRANSFORMATION_KIND_NONE; case DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION: case DDS_SECURITY_PROTECTION_KIND_SIGN: - if( keysize == 128 ){ - return CRYPTO_TRANSFORMATION_KIND_AES128_GMAC; - } else{ - return CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; - } + return (keysize == 128) ? CRYPTO_TRANSFORMATION_KIND_AES128_GMAC : CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; case DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION: case DDS_SECURITY_PROTECTION_KIND_ENCRYPT: - if( keysize == 128 ){ - return CRYPTO_TRANSFORMATION_KIND_AES128_GCM; - } else { - return CRYPTO_TRANSFORMATION_KIND_AES256_GCM; - } + return (keysize == 128) ? CRYPTO_TRANSFORMATION_KIND_AES128_GCM : CRYPTO_TRANSFORMATION_KIND_AES256_GCM; default: return CRYPTO_TRANSFORMATION_KIND_INVALID; } } -/* for DEBUG purposes */ +#ifndef NDEBUG void print_binary_debug( char* name, @@ -1021,8 +997,7 @@ print_binary_properties_debug( } } - - +#endif DDS_Security_config_item_prefix_t diff --git a/src/security/core/src/shared_secret.c b/src/security/core/src/shared_secret.c index 7b1de75..2446906 100644 --- a/src/security/core/src/shared_secret.c +++ b/src/security/core/src/shared_secret.c @@ -13,31 +13,29 @@ #include "dds/security/core/shared_secret.h" const DDS_Security_octet* -get_challenge1_from_secret_handle(DDS_Security_SharedSecretHandle handle) +get_challenge1_from_secret_handle (DDS_Security_SharedSecretHandle handle) { - - DDS_Security_SharedSecretHandleImpl *secret = (DDS_Security_SharedSecretHandleImpl *)(uintptr_t)handle; - return secret->challenge1; + DDS_Security_SharedSecretHandleImpl *secret = (DDS_Security_SharedSecretHandleImpl *)(uintptr_t)handle; + return secret->challenge1; } const DDS_Security_octet* -get_challenge2_from_secret_handle(DDS_Security_SharedSecretHandle handle) +get_challenge2_from_secret_handle (DDS_Security_SharedSecretHandle handle) { - DDS_Security_SharedSecretHandleImpl *secret = (DDS_Security_SharedSecretHandleImpl *)(uintptr_t)handle; - return secret->challenge2; + DDS_Security_SharedSecretHandleImpl *secret = (DDS_Security_SharedSecretHandleImpl *)(uintptr_t)handle; + return secret->challenge2; } const DDS_Security_octet* -get_secret_from_secret_handle(DDS_Security_SharedSecretHandle handle) +get_secret_from_secret_handle (DDS_Security_SharedSecretHandle handle) { - DDS_Security_SharedSecretHandleImpl *secret = (DDS_Security_SharedSecretHandleImpl *)(uintptr_t)handle; - return secret->shared_secret; + DDS_Security_SharedSecretHandleImpl *secret = (DDS_Security_SharedSecretHandleImpl *)(uintptr_t)handle; + return secret->shared_secret; } - -int32_t -get_secret_size_from_secret_handle( DDS_Security_SharedSecretHandle handle ){ - DDS_Security_SharedSecretHandleImpl *secret = (DDS_Security_SharedSecretHandleImpl *)(uintptr_t)handle; - return secret->shared_secret_size; - +size_t +get_secret_size_from_secret_handle (DDS_Security_SharedSecretHandle handle) +{ + DDS_Security_SharedSecretHandleImpl *secret = (DDS_Security_SharedSecretHandleImpl *)(uintptr_t)handle; + return (size_t) secret->shared_secret_size; }