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; }