From fd27604a26cd2f3e1bbef0d8403eeb9340f937a3 Mon Sep 17 00:00:00 2001 From: Dennis Potman Date: Wed, 22 Apr 2020 16:59:29 +0200 Subject: [PATCH] Add crypto token exchange test Introduced a test that checks if all crypto tokens send by a node are received correctly by the remote node. To support this test, the crypto wrapper plugin is extended with a token_log mode, that stores all tokens that are exchanged after the security handshake is finished. Signed-off-by: Dennis Potman --- src/security/core/tests/authentication.c | 1 - .../core/tests/common/cryptography_wrapper.c | 258 +++++++++++++++++- .../core/tests/common/cryptography_wrapper.h | 32 +++ src/security/core/tests/common/test_utils.c | 22 ++ src/security/core/tests/common/test_utils.h | 1 + src/security/core/tests/handshake.c | 128 +++++++-- .../core/tests/secure_communication.c | 77 +----- 7 files changed, 412 insertions(+), 107 deletions(-) diff --git a/src/security/core/tests/authentication.c b/src/security/core/tests/authentication.c index fe6aa6a..dbd80be 100644 --- a/src/security/core/tests/authentication.c +++ b/src/security/core/tests/authentication.c @@ -34,7 +34,6 @@ #include "common/security_config_test_utils.h" #include "common/test_identity.h" #include "common/cert_utils.h" -#include "common/security_config_test_utils.h" #define ID1 TEST_IDENTITY1_CERTIFICATE #define ID1K TEST_IDENTITY1_PRIVATE_KEY diff --git a/src/security/core/tests/common/cryptography_wrapper.c b/src/security/core/tests/common/cryptography_wrapper.c index 034d81d..1856c09 100644 --- a/src/security/core/tests/common/cryptography_wrapper.c +++ b/src/security/core/tests/common/cryptography_wrapper.c @@ -13,6 +13,7 @@ #include #include "CUnit/Test.h" #include "dds/dds.h" +#include "dds/ddsrt/circlist.h" #include "dds/ddsrt/heap.h" #include "dds/ddsrt/sync.h" #include "dds/ddsrt/string.h" @@ -22,13 +23,17 @@ #include "dds/security/core/dds_security_utils.h" #include "cryptography_wrapper.h" -int init_crypto(const char *argument, void **context, struct ddsi_domaingv *gv); -int finalize_crypto(void *context); +#define CRYPTO_TOKEN_CLASS_ID "DDS:Crypto:AES_GCM_GMAC" +#define CRYPTO_TOKEN_PROPERTY_NAME "dds.cryp.keymat" + +int32_t init_crypto(const char *argument, void **context, struct ddsi_domaingv *gv); +int32_t finalize_crypto(void *context); enum crypto_plugin_mode { PLUGIN_MODE_ALL_OK, PLUGIN_MODE_MISSING_FUNC, - PLUGIN_MODE_WRAPPED + PLUGIN_MODE_WRAPPED, + PLUGIN_MODE_TOKEN_LOG }; struct dds_security_crypto_key_exchange_impl { @@ -67,9 +72,13 @@ struct dds_security_cryptography_impl { const char * groupdata_secret; const char * ep_secret; const char * encrypted_secret; + ddsrt_mutex_t token_data_lock; + struct ddsrt_circlist token_data_list; }; static DDS_Security_ParticipantCryptoHandle g_local_participant_handle = 0; +static ddsrt_once_t lock_inited = DDSRT_ONCE_INIT; +static ddsrt_mutex_t g_print_token_lock; void set_protection_kinds( struct dds_security_cryptography_impl * impl, @@ -109,6 +118,144 @@ void set_entity_data_secret(struct dds_security_cryptography_impl * impl, const impl->ep_secret = ep_secret; } +static bool check_crypto_tokens(const DDS_Security_DataHolderSeq *tokens) +{ + bool result = true; + + if (tokens->_length == 0 || tokens->_buffer == NULL) + return false; + + for (uint32_t i = 0; result && (i < tokens->_length); i++) + { + result = (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 result; +} + +const char *get_crypto_token_type_str (enum crypto_tokens_type type) +{ + switch (type) + { + case LOCAL_PARTICIPANT_TOKENS: return "LOCAL_PARTICIPANT_TOKENS"; + case LOCAL_WRITER_TOKENS: return "LOCAL_WRITER_TOKENS"; + case LOCAL_READER_TOKENS: return "LOCAL_READER_TOKENS"; + case REMOTE_PARTICIPANT_TOKENS: return "REMOTE_PARTICIPANT_TOKENS"; + case REMOTE_WRITER_TOKENS: return "REMOTE_WRITER_TOKENS"; + case REMOTE_READER_TOKENS: return "REMOTE_READER_TOKENS"; + default: assert (0); return ""; + } +} + +static void print_tokens (enum crypto_tokens_type type, const DDS_Security_ParticipantCryptoHandle lch, const DDS_Security_ParticipantCryptoHandle rch, + const DDS_Security_ParticipantCryptoTokenSeq *tokens) +{ + ddsrt_mutex_lock (&g_print_token_lock); + printf ("Token type %s, local %"PRIx64" / remote %"PRIx64", count: %u\n", get_crypto_token_type_str (type), lch, rch, tokens->_length); + for (uint32_t i = 0; i < tokens->_length; i++) + { + printf ("- token: "); + for (uint32_t j = 0; j < tokens->_buffer[i].binary_properties._buffer[0].value._length && j < 32; j++) + printf ("%02x", tokens->_buffer[i].binary_properties._buffer[0].value._buffer[j]); + printf ("\n"); + } + printf ("\n"); + ddsrt_mutex_unlock (&g_print_token_lock); +} + +static void add_tokens (struct ddsrt_circlist *list, enum crypto_tokens_type type, + const DDS_Security_ParticipantCryptoHandle lch, const DDS_Security_ParticipantCryptoHandle rch, + const DDS_Security_ParticipantCryptoTokenSeq *tokens) +{ + struct crypto_token_data *token_data = ddsrt_malloc (sizeof (*token_data)); + token_data->type = type; + token_data->local_handle = lch; + token_data->remote_handle = rch; + token_data->n_tokens = tokens->_length; + assert (tokens->_length <= CRYPTO_TOKEN_MAXLEN); + for (uint32_t i = 0; i < tokens->_length; i++) + { + size_t len = tokens->_buffer[i].binary_properties._buffer[0].value._length; + assert (len <= CRYPTO_TOKEN_SIZE); + memcpy (token_data->data[i], tokens->_buffer[i].binary_properties._buffer[0].value._buffer, len); + token_data->data_len[i] = len; + } + ddsrt_circlist_append(list, &token_data->e); +} + +static void store_tokens (struct dds_security_crypto_key_exchange_impl *impl, enum crypto_tokens_type type, const DDS_Security_ParticipantCryptoHandle lch, + const DDS_Security_ParticipantCryptoHandle rch, const DDS_Security_ParticipantCryptoTokenSeq *tokens) +{ + if (!check_crypto_tokens ((const DDS_Security_DataHolderSeq *) tokens)) + { + printf ("%d ERROR\n", type); + return; + } + + ddsrt_mutex_lock (&impl->parent->token_data_lock); + add_tokens (&impl->parent->token_data_list, type, lch, rch, tokens); + ddsrt_mutex_unlock (&impl->parent->token_data_lock); + + print_tokens (type, lch, rch, tokens); +} + +struct ddsrt_circlist * get_crypto_tokens (struct dds_security_cryptography_impl * impl) +{ + struct ddsrt_circlist *tokens = ddsrt_malloc (sizeof (*tokens)); + ddsrt_circlist_init (tokens); + + ddsrt_mutex_lock (&impl->token_data_lock); + struct ddsrt_circlist_elem *elem0 = ddsrt_circlist_oldest (&impl->token_data_list), *elem = elem0; + while (elem != NULL) + { + struct crypto_token_data *elem_data = DDSRT_FROM_CIRCLIST (struct crypto_token_data, e, elem); + struct crypto_token_data *token_data = ddsrt_malloc (sizeof (*token_data)); + memcpy (token_data, elem_data, sizeof (*token_data)); + ddsrt_circlist_append (tokens, &token_data->e); + elem = elem->next; + if (elem == elem0) + break; + } + ddsrt_mutex_unlock (&impl->token_data_lock); + + return tokens; +} + +struct crypto_token_data * find_crypto_token (struct dds_security_cryptography_impl * impl, enum crypto_tokens_type type, unsigned char * data, size_t data_len) +{ + assert (data_len <= CRYPTO_TOKEN_SIZE); + ddsrt_mutex_lock (&impl->token_data_lock); + struct ddsrt_circlist_elem *elem0 = ddsrt_circlist_oldest (&impl->token_data_list), *elem = elem0; + while (elem != NULL) + { + struct crypto_token_data *elem_data = DDSRT_FROM_CIRCLIST (struct crypto_token_data, e, elem); + if (elem_data->type == type) + { + for (uint32_t i = 0; i < elem_data->n_tokens; i++) + { + size_t len = elem_data->data_len[i]; + assert (len <= CRYPTO_TOKEN_SIZE); + if (!memcmp (data, elem_data->data[i], data_len < len ? data_len : len)) + { + ddsrt_mutex_unlock (&impl->token_data_lock); + return elem_data; + } + } + } + elem = elem->next; + if (elem == elem0) + break; + } + ddsrt_mutex_unlock (&impl->token_data_lock); + return NULL; +} + static unsigned char * find_buffer_match(const unsigned char *input, size_t input_len, const unsigned char *match, size_t match_len) { if (match_len <= input_len && match_len > 0 && input_len > 0) @@ -171,8 +318,14 @@ static DDS_Security_boolean create_local_participant_crypto_tokens( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: - return impl->instance->create_local_participant_crypto_tokens (impl->instance, local_participant_crypto_tokens, + case PLUGIN_MODE_TOKEN_LOG: + { + DDS_Security_boolean ret = impl->instance->create_local_participant_crypto_tokens (impl->instance, local_participant_crypto_tokens, local_participant_crypto, remote_participant_crypto, ex); + if (ret && impl->parent->mode == PLUGIN_MODE_TOKEN_LOG) + store_tokens (impl, LOCAL_PARTICIPANT_TOKENS, local_participant_crypto, remote_participant_crypto, local_participant_crypto_tokens); + return ret; + } default: return true; } @@ -189,8 +342,14 @@ static DDS_Security_boolean set_remote_participant_crypto_tokens( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: - return impl->instance->set_remote_participant_crypto_tokens (impl->instance, check_handle (local_participant_crypto), + case PLUGIN_MODE_TOKEN_LOG: + { + DDS_Security_boolean ret = impl->instance->set_remote_participant_crypto_tokens (impl->instance, check_handle (local_participant_crypto), check_handle (remote_participant_crypto), remote_participant_tokens, ex); + if (ret && impl->parent->mode == PLUGIN_MODE_TOKEN_LOG) + store_tokens (impl, REMOTE_PARTICIPANT_TOKENS, local_participant_crypto, remote_participant_crypto, remote_participant_tokens); + return ret; + } default: return true; } @@ -207,8 +366,14 @@ static DDS_Security_boolean create_local_datawriter_crypto_tokens( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: - return impl->instance->create_local_datawriter_crypto_tokens (impl->instance, local_datawriter_crypto_tokens, + case PLUGIN_MODE_TOKEN_LOG: + { + DDS_Security_boolean ret = impl->instance->create_local_datawriter_crypto_tokens (impl->instance, local_datawriter_crypto_tokens, check_handle (local_datawriter_crypto), check_handle (remote_datareader_crypto), ex); + if (ret && impl->parent->mode == PLUGIN_MODE_TOKEN_LOG) + store_tokens (impl, LOCAL_WRITER_TOKENS, local_datawriter_crypto, remote_datareader_crypto, local_datawriter_crypto_tokens); + return ret; + } default: return true; } @@ -225,8 +390,14 @@ static DDS_Security_boolean set_remote_datawriter_crypto_tokens( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: - return impl->instance->set_remote_datawriter_crypto_tokens (impl->instance, check_handle (local_datareader_crypto), + case PLUGIN_MODE_TOKEN_LOG: + { + DDS_Security_boolean ret = impl->instance->set_remote_datawriter_crypto_tokens (impl->instance, check_handle (local_datareader_crypto), check_handle (remote_datawriter_crypto), remote_datawriter_tokens, ex); + if (ret && impl->parent->mode == PLUGIN_MODE_TOKEN_LOG) + store_tokens (impl, REMOTE_WRITER_TOKENS, local_datareader_crypto, remote_datawriter_crypto, remote_datawriter_tokens); + return ret; + } default: return true; } @@ -243,8 +414,14 @@ static DDS_Security_boolean create_local_datareader_crypto_tokens( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: - return impl->instance->create_local_datareader_crypto_tokens (impl->instance, local_datareader_cryto_tokens, + case PLUGIN_MODE_TOKEN_LOG: + { + DDS_Security_boolean ret = impl->instance->create_local_datareader_crypto_tokens (impl->instance, local_datareader_cryto_tokens, check_handle (local_datareader_crypto), check_handle (remote_datawriter_crypto), ex); + if (ret && impl->parent->mode == PLUGIN_MODE_TOKEN_LOG) + store_tokens (impl, LOCAL_READER_TOKENS, local_datareader_crypto, remote_datawriter_crypto, local_datareader_cryto_tokens); + return ret; + } default: return true; } @@ -261,8 +438,14 @@ static DDS_Security_boolean set_remote_datareader_crypto_tokens( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: - return impl->instance->set_remote_datareader_crypto_tokens (impl->instance, check_handle (local_datawriter_crypto), + case PLUGIN_MODE_TOKEN_LOG: + { + DDS_Security_boolean ret = impl->instance->set_remote_datareader_crypto_tokens (impl->instance, check_handle (local_datawriter_crypto), check_handle (remote_datareader_crypto), remote_datareader_tokens, ex); + if (ret && impl->parent->mode == PLUGIN_MODE_TOKEN_LOG) + store_tokens (impl, REMOTE_READER_TOKENS, local_datawriter_crypto, remote_datareader_crypto, remote_datareader_tokens); + return ret; + } default: return true; } @@ -277,6 +460,7 @@ static DDS_Security_boolean return_crypto_tokens( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: return impl->instance->return_crypto_tokens (impl->instance, crypto_tokens, ex); default: return true; @@ -298,6 +482,7 @@ static DDS_Security_ParticipantCryptoHandle register_local_participant( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: return check_handle (impl->instance->register_local_participant (impl->instance, check_handle (participant_identity), check_handle (participant_permissions), participant_properties, participant_security_attributes, ex)); default: @@ -317,6 +502,7 @@ static DDS_Security_ParticipantCryptoHandle register_matched_remote_participant( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: return check_handle (impl->instance->register_matched_remote_participant (impl->instance, local_participant_crypto_handle, remote_participant_identity, remote_participant_permissions, shared_secret, ex)); default: @@ -335,6 +521,7 @@ static DDS_Security_DatawriterCryptoHandle register_local_datawriter( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: return check_handle (impl->instance->register_local_datawriter (impl->instance, check_handle (participant_crypto), datawriter_properties, datawriter_security_attributes, ex)); default: @@ -354,6 +541,7 @@ static DDS_Security_DatareaderCryptoHandle register_matched_remote_datareader( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: return check_handle (impl->instance->register_matched_remote_datareader (impl->instance, check_handle (local_datawriter_crypto_handle), check_handle (remote_participant_crypto), check_handle (shared_secret), relay_only, ex)); default: @@ -372,6 +560,7 @@ static DDS_Security_DatareaderCryptoHandle register_local_datareader( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: return check_handle (impl->instance->register_local_datareader (impl->instance, check_handle (participant_crypto), datareader_properties, datareader_security_attributes, ex)); default: @@ -390,6 +579,7 @@ static DDS_Security_DatawriterCryptoHandle register_matched_remote_datawriter( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: return check_handle (impl->instance->register_matched_remote_datawriter (impl->instance, check_handle (local_datareader_crypto_handle), check_handle (remote_participant_crypt), shared_secret, ex)); default: @@ -406,6 +596,7 @@ static DDS_Security_boolean unregister_participant( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: return impl->instance->unregister_participant (impl->instance, check_handle (participant_crypto_handle), ex); default: return true; @@ -421,6 +612,7 @@ static DDS_Security_boolean unregister_datawriter( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: return impl->instance->unregister_datawriter (impl->instance, check_handle (datawriter_crypto_handle), ex); default: return true; @@ -436,6 +628,7 @@ static DDS_Security_boolean unregister_datareader( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: return impl->instance->unregister_datareader (impl->instance, check_handle (datareader_crypto_handle), ex); default: return true; @@ -457,6 +650,7 @@ static DDS_Security_boolean encode_serialized_payload( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: { if (!impl->instance->encode_serialized_payload (impl->instance, encoded_buffer, extra_inline_qos, plain_buffer, check_handle (sending_datawriter_crypto), ex)) @@ -511,6 +705,7 @@ static DDS_Security_boolean encode_datawriter_submessage( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: if (!impl->instance->encode_datawriter_submessage (impl->instance, encoded_rtps_submessage, plain_rtps_submessage, check_handle (sending_datawriter_crypto), receiving_datareader_crypto_list, receiving_datareader_crypto_list_index, ex)) return false; @@ -558,6 +753,7 @@ static DDS_Security_boolean encode_datareader_submessage( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: if (!impl->instance->encode_datareader_submessage (impl->instance, encoded_rtps_submessage, plain_rtps_submessage, check_handle (sending_datareader_crypto), receiving_datawriter_crypto_list, ex)) return false; @@ -580,6 +776,7 @@ static DDS_Security_boolean encode_rtps_message( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: if (!impl->instance->encode_rtps_message (impl->instance, encoded_rtps_message, plain_rtps_message, check_handle (sending_participant_crypto), receiving_participant_crypto_list, receiving_participant_crypto_list_index, ex)) return false; @@ -611,6 +808,7 @@ static DDS_Security_boolean decode_rtps_message( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: return impl->instance->decode_rtps_message (impl->instance, plain_buffer, encoded_buffer, check_handle (receiving_participant_crypto), check_handle (sending_participant_crypto), ex); default: @@ -632,6 +830,7 @@ static DDS_Security_boolean preprocess_secure_submsg( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: return impl->instance->preprocess_secure_submsg (impl->instance, datawriter_crypto, datareader_crypto, secure_submessage_category, encoded_rtps_submessage, check_handle (receiving_participant_crypto), check_handle (sending_participant_crypto), ex); default: @@ -651,6 +850,7 @@ static DDS_Security_boolean decode_datawriter_submessage( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: return impl->instance->decode_datawriter_submessage (impl->instance, plain_rtps_submessage, encoded_rtps_submessage, check_handle (receiving_datareader_crypto), check_handle (sending_datawriter_crypto), ex); default: @@ -670,6 +870,7 @@ static DDS_Security_boolean decode_datareader_submessage( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: return impl->instance->decode_datareader_submessage (impl->instance, plain_rtps_submessage, encoded_rtps_submessage, check_handle (receiving_datawriter_crypto), check_handle (sending_datareader_crypto), ex); default: @@ -690,6 +891,7 @@ static DDS_Security_boolean decode_serialized_payload( switch (impl->parent->mode) { case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: return impl->instance->decode_serialized_payload(impl->instance, plain_buffer, encoded_buffer, inline_qos, check_handle (receiving_datareader_crypto), check_handle (sending_datawriter_crypto), ex); default: @@ -815,3 +1017,41 @@ int finalize_test_cryptography_wrapped(void *context) return finalize_test_cryptography_common(impl, true); } +static void init_print_lock(void) +{ + ddsrt_mutex_init (&g_print_token_lock); +} + +int32_t init_test_cryptography_store_tokens(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + struct dds_security_cryptography_impl *impl = init_test_cryptography_common(argument, true, gv); + if (!impl) + return DDS_SECURITY_FAILED; + impl->mode = PLUGIN_MODE_TOKEN_LOG; + ddsrt_once (&lock_inited, &init_print_lock); + ddsrt_mutex_init (&impl->token_data_lock); + ddsrt_circlist_init (&impl->token_data_list); + *context = impl; + return DDS_SECURITY_SUCCESS; +} + +int32_t finalize_test_cryptography_store_tokens(void *context) +{ + struct dds_security_cryptography_impl* impl = (struct dds_security_cryptography_impl*) context; + assert(impl->mode == PLUGIN_MODE_TOKEN_LOG); + ddsrt_mutex_lock (&impl->token_data_lock); + while (!ddsrt_circlist_isempty (&impl->token_data_list)) + { + struct ddsrt_circlist_elem *list_elem = ddsrt_circlist_oldest (&impl->token_data_list); + struct crypto_token_data *token_data = DDSRT_FROM_CIRCLIST (struct crypto_token_data, e, list_elem); + ddsrt_circlist_remove (&impl->token_data_list, list_elem); + ddsrt_free (token_data); + } + ddsrt_mutex_unlock (&impl->token_data_lock); + ddsrt_mutex_destroy (&impl->token_data_lock); + /* don't detroy g_print_token_lock as this will result in multiple + calls to mutex_destroy for this lock in case of multiple domains */ + + return finalize_test_cryptography_common(impl, true); +} + diff --git a/src/security/core/tests/common/cryptography_wrapper.h b/src/security/core/tests/common/cryptography_wrapper.h index 0c50adc..b9384c9 100644 --- a/src/security/core/tests/common/cryptography_wrapper.h +++ b/src/security/core/tests/common/cryptography_wrapper.h @@ -12,13 +12,37 @@ #ifndef SECURITY_CORE_TEST_CRYPTO_WRAPPER_H_ #define SECURITY_CORE_TEST_CRYPTO_WRAPPER_H_ +#include "dds/ddsrt/circlist.h" #include "dds/ddsi/ddsi_domaingv.h" #include "dds/security/dds_security_api.h" #include "dds/security/dds_security_api_defs.h" #include "dds/security/cryptography_wrapper_export.h" +#define CRYPTO_TOKEN_MAXLEN 10 +#define CRYPTO_TOKEN_SIZE 256 + struct dds_security_cryptography_impl; +enum crypto_tokens_type { + LOCAL_PARTICIPANT_TOKENS, + LOCAL_WRITER_TOKENS, + LOCAL_READER_TOKENS, + REMOTE_PARTICIPANT_TOKENS, + REMOTE_WRITER_TOKENS, + REMOTE_READER_TOKENS, + TOKEN_TYPE_INVALID +}; + +struct crypto_token_data { + struct ddsrt_circlist_elem e; + enum crypto_tokens_type type; + DDS_Security_ParticipantCryptoHandle local_handle; + DDS_Security_ParticipantCryptoHandle remote_handle; + uint32_t n_tokens; + unsigned char data[CRYPTO_TOKEN_MAXLEN][CRYPTO_TOKEN_SIZE]; + size_t data_len[CRYPTO_TOKEN_MAXLEN]; +}; + SECURITY_EXPORT void set_protection_kinds( struct dds_security_cryptography_impl * impl, DDS_Security_ProtectionKind rtps_protection_kind, @@ -34,6 +58,10 @@ SECURITY_EXPORT void set_disc_protection_kinds( SECURITY_EXPORT void set_entity_data_secret(struct dds_security_cryptography_impl * impl, const char * pp_secret, const char * groupdata_secret, const char * ep_secret); +SECURITY_EXPORT const char *get_crypto_token_type_str (enum crypto_tokens_type type); +SECURITY_EXPORT struct ddsrt_circlist * get_crypto_tokens (struct dds_security_cryptography_impl * impl); +SECURITY_EXPORT struct crypto_token_data * find_crypto_token (struct dds_security_cryptography_impl * impl, enum crypto_tokens_type type, unsigned char * data, size_t data_len); + /* Init in all-ok mode: all functions return success without calling the actual plugin */ SECURITY_EXPORT int init_test_cryptography_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv); SECURITY_EXPORT int finalize_test_cryptography_all_ok(void *context); @@ -46,4 +74,8 @@ SECURITY_EXPORT int finalize_test_cryptography_missing_func(void *context); SECURITY_EXPORT int init_test_cryptography_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv); SECURITY_EXPORT int finalize_test_cryptography_wrapped(void *context); +/* Init in store-token mode (stores all exchanged security tokens) */ +SECURITY_EXPORT int32_t init_test_cryptography_store_tokens(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int32_t finalize_test_cryptography_store_tokens(void *context); + #endif /* SECURITY_CORE_TEST_CRYPTO_WRAPPER_H_ */ diff --git a/src/security/core/tests/common/test_utils.c b/src/security/core/tests/common/test_utils.c index a75c6b9..3f94a85 100644 --- a/src/security/core/tests/common/test_utils.c +++ b/src/security/core/tests/common/test_utils.c @@ -18,6 +18,10 @@ #include "dds/ddsrt/string.h" #include "dds/ddsrt/threads.h" #include "dds/ddsrt/heap.h" +#include "dds/ddsi/q_entity.h" +#include "dds/ddsi/ddsi_entity_index.h" +#include "dds/ddsi/ddsi_security_omg.h" +#include "dds__entity.h" #include "dds/security/dds_security_api.h" #include "authentication_wrapper.h" #include "test_utils.h" @@ -449,3 +453,21 @@ void write_read_for(dds_entity_t wr, dds_entity_t pp_rd, dds_entity_t rd, dds_du CU_ASSERT_EQUAL_FATAL (write_fail, exp_write_fail); CU_ASSERT_EQUAL_FATAL (read_fail, exp_read_fail); } + +struct dds_security_cryptography_impl * get_crypto_context(dds_entity_t participant) +{ + struct dds_entity *pp_entity = NULL; + struct participant *pp; + struct dds_security_cryptography_impl *context; + dds_return_t ret; + + ret = dds_entity_lock (participant, DDS_KIND_PARTICIPANT, &pp_entity); + CU_ASSERT_EQUAL_FATAL (ret, 0); + thread_state_awake (lookup_thread_state(), &pp_entity->m_domain->gv); + pp = entidx_lookup_participant_guid (pp_entity->m_domain->gv.entity_index, &pp_entity->m_guid); + CU_ASSERT_FATAL (pp != NULL); + context = (struct dds_security_cryptography_impl *) q_omg_participant_get_cryptography (pp); + thread_state_asleep (lookup_thread_state ()); + dds_entity_unlock (pp_entity); + return context; +} diff --git a/src/security/core/tests/common/test_utils.h b/src/security/core/tests/common/test_utils.h index ac1e8a7..919affe 100644 --- a/src/security/core/tests/common/test_utils.h +++ b/src/security/core/tests/common/test_utils.h @@ -69,5 +69,6 @@ void rd_wr_init_fail( bool exp_pubtp_fail, bool exp_wr_fail, bool exp_subtp_fail, bool exp_rd_fail); void write_read_for(dds_entity_t wr, dds_entity_t pp_rd, dds_entity_t rd, dds_duration_t dur, bool exp_write_fail, bool exp_read_fail); +struct dds_security_cryptography_impl * get_crypto_context(dds_entity_t participant); #endif /* SECURITY_CORE_TEST_UTILS_H_ */ diff --git a/src/security/core/tests/handshake.c b/src/security/core/tests/handshake.c index 66a77f9..5947a8f 100644 --- a/src/security/core/tests/handshake.c +++ b/src/security/core/tests/handshake.c @@ -20,6 +20,7 @@ #include "dds/ddsrt/environ.h" #include "dds/ddsrt/heap.h" #include "dds/ddsrt/string.h" +#include "dds/ddsrt/string.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_misc.h" @@ -29,9 +30,11 @@ #include "common/config_env.h" #include "common/authentication_wrapper.h" +#include "common/cryptography_wrapper.h" #include "common/plugin_wrapper_msg_q.h" #include "common/test_utils.h" #include "common/test_identity.h" +#include "common/security_config_test_utils.h" static const char *config = "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}" @@ -42,7 +45,7 @@ static const char *config = " " " " " " - " " + " " " data:,"TEST_IDENTITY1_CERTIFICATE"" " data:,"TEST_IDENTITY1_PRIVATE_KEY"" " data:,"TEST_IDENTITY_CA1_CERTIFICATE"" @@ -54,43 +57,120 @@ static const char *config = " file:" COMMON_ETC_PATH("default_permissions.p7s") "" " " " " - " " + " " " " " " ""; -#define DDS_DOMAINID_PART1 0 -#define DDS_DOMAINID_PART2 1 +#define DDS_DOMAINID1 0 +#define DDS_DOMAINID2 1 -static dds_entity_t g_part1_domain = 0; -static dds_entity_t g_part1_participant = 0; +static dds_entity_t g_domain1 = 0; +static dds_entity_t g_participant1 = 0; -static dds_entity_t g_part2_domain = 0; -static dds_entity_t g_part2_participant = 0; +static dds_entity_t g_domain2 = 0; +static dds_entity_t g_participant2 = 0; -static void handshake_init(void) +static uint32_t g_topic_nr = 0; +static dds_entity_t g_pub = 0, g_pub_tp = 0, g_wr = 0, g_sub = 0, g_sub_tp = 0, g_rd = 0; + +static void handshake_init(const char * auth_init, const char * auth_fini, const char * crypto_init, const char * crypto_fini) { - char *conf_part1 = ddsrt_expand_envvars_sh (config, DDS_DOMAINID_PART1); - char *conf_part2 = ddsrt_expand_envvars_sh (config, DDS_DOMAINID_PART2); - g_part1_domain = dds_create_domain (DDS_DOMAINID_PART1, conf_part1); - g_part2_domain = dds_create_domain (DDS_DOMAINID_PART2, conf_part2); - dds_free (conf_part1); - dds_free (conf_part2); + struct kvp config_vars[] = { + { "AUTH_INIT", auth_init, 1}, + { "AUTH_FINI", auth_fini, 1}, + { "CRYPTO_INIT", crypto_init, 1 }, + { "CRYPTO_FINI", crypto_fini, 1 }, + { NULL, NULL, 0 } + }; - CU_ASSERT_FATAL ((g_part1_participant = dds_create_participant (DDS_DOMAINID_PART1, NULL, NULL)) > 0); - CU_ASSERT_FATAL ((g_part2_participant = dds_create_participant (DDS_DOMAINID_PART2, NULL, NULL)) > 0); + char *conf = ddsrt_expand_vars_sh (config, &expand_lookup_vars_env, config_vars); + int32_t unmatched = expand_lookup_unmatched (config_vars); + CU_ASSERT_EQUAL_FATAL (unmatched, 0); + g_domain1 = dds_create_domain (DDS_DOMAINID1, conf); + g_domain2 = dds_create_domain (DDS_DOMAINID2, conf); + dds_free (conf); + + g_participant1 = dds_create_participant (DDS_DOMAINID1, NULL, NULL); + CU_ASSERT_FATAL (g_participant1 > 0); + g_participant2 = dds_create_participant (DDS_DOMAINID2, NULL, NULL); + CU_ASSERT_FATAL (g_participant2 > 0); } static void handshake_fini(void) { - CU_ASSERT_EQUAL_FATAL (dds_delete (g_part1_participant), DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL (dds_delete (g_part2_participant), DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL (dds_delete (g_part1_domain), DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL (dds_delete (g_part2_domain), DDS_RETCODE_OK); + dds_return_t ret = dds_delete (g_domain1); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + ret = dds_delete (g_domain2); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); } -CU_Test(ddssec_handshake, happy_day, .init = handshake_init, .fini = handshake_fini) +CU_Test(ddssec_handshake, happy_day) { - validate_handshake_nofail (DDS_DOMAINID_PART1); - validate_handshake_nofail (DDS_DOMAINID_PART2); + handshake_init ( + "init_test_authentication_wrapped", "finalize_test_authentication_wrapped", + "init_test_cryptography_wrapped", "finalize_test_cryptography_wrapped"); + validate_handshake_nofail (DDS_DOMAINID1); + validate_handshake_nofail (DDS_DOMAINID2); + handshake_fini (); +} + +CU_Test(ddssec_handshake, check_tokens) +{ + handshake_init ( + "init_test_authentication_wrapped", "finalize_test_authentication_wrapped", + "init_test_cryptography_store_tokens", "finalize_test_cryptography_store_tokens"); + validate_handshake_nofail (DDS_DOMAINID1); + validate_handshake_nofail (DDS_DOMAINID2); + + char topic_name[100]; + create_topic_name("ddssec_authentication_", g_topic_nr++, topic_name, sizeof (topic_name)); + rd_wr_init (g_participant1, &g_pub, &g_pub_tp, &g_wr, g_participant2, &g_sub, &g_sub_tp, &g_rd, topic_name); + write_read_for (g_wr, g_participant2, g_rd, DDS_MSECS (100), false, false); + + // Get subscriber and publisher crypto tokens + struct dds_security_cryptography_impl * crypto_context_pub = get_crypto_context (g_participant1); + CU_ASSERT_FATAL (crypto_context_pub != NULL); + struct ddsrt_circlist *pub_tokens = get_crypto_tokens (crypto_context_pub); + + struct dds_security_cryptography_impl * crypto_context_sub = get_crypto_context (g_participant2); + CU_ASSERT_FATAL (crypto_context_sub != NULL); + struct ddsrt_circlist *sub_tokens = get_crypto_tokens (crypto_context_sub); + + // Find all publisher tokens in subscribers token store + while (!ddsrt_circlist_isempty (pub_tokens)) + { + struct ddsrt_circlist_elem *list_elem = ddsrt_circlist_oldest (pub_tokens); + struct crypto_token_data *token_data = DDSRT_FROM_CIRCLIST (struct crypto_token_data, e, list_elem); + enum crypto_tokens_type exp_type = TOKEN_TYPE_INVALID; + for (size_t n = 0; n < token_data->n_tokens; n++) + { + switch (token_data->type) + { + case LOCAL_PARTICIPANT_TOKENS: exp_type = REMOTE_PARTICIPANT_TOKENS; break; + case REMOTE_PARTICIPANT_TOKENS: exp_type = LOCAL_PARTICIPANT_TOKENS; break; + case LOCAL_WRITER_TOKENS: exp_type = REMOTE_WRITER_TOKENS; break; + case REMOTE_WRITER_TOKENS: exp_type = LOCAL_WRITER_TOKENS; break; + case LOCAL_READER_TOKENS: exp_type = REMOTE_READER_TOKENS; break; + case REMOTE_READER_TOKENS: exp_type = LOCAL_READER_TOKENS; break; + default: CU_FAIL ("Unexpected token type"); + } + printf("- find token %s #%"PRIuSIZE", len %"PRIuSIZE"\n", get_crypto_token_type_str (token_data->type), n, token_data->data_len[n]); + struct crypto_token_data *st = find_crypto_token (crypto_context_sub, exp_type, token_data->data[n], token_data->data_len[n]); + CU_ASSERT_FATAL (st != NULL); + } + ddsrt_circlist_remove (pub_tokens, list_elem); + ddsrt_free (token_data); + } + + // Cleanup + while (!ddsrt_circlist_isempty (sub_tokens)) + { + struct ddsrt_circlist_elem *list_elem = ddsrt_circlist_oldest (sub_tokens); + ddsrt_circlist_remove (sub_tokens, list_elem); + ddsrt_free (list_elem); + } + ddsrt_free (sub_tokens); + ddsrt_free (pub_tokens); + handshake_fini (); } diff --git a/src/security/core/tests/secure_communication.c b/src/security/core/tests/secure_communication.c index 92b40a4..186944c 100644 --- a/src/security/core/tests/secure_communication.c +++ b/src/security/core/tests/secure_communication.c @@ -27,14 +27,11 @@ #include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/q_misc.h" #include "dds/ddsi/ddsi_xqos.h" -#include "dds/ddsi/q_entity.h" -#include "dds/ddsi/ddsi_entity_index.h" -#include "dds/ddsi/ddsi_security_omg.h" -#include "dds__entity.h" #include "dds/security/dds_security_api.h" #include "common/config_env.h" #include "common/test_identity.h" +#include "common/test_utils.h" #include "common/security_config_test_utils.h" #include "common/cryptography_wrapper.h" @@ -119,25 +116,6 @@ typedef void (*set_crypto_params_fn)(struct dds_security_cryptography_impl *, co typedef dds_entity_t (*pubsub_create_fn)(dds_entity_t, const dds_qos_t *qos, const dds_listener_t *listener); typedef dds_entity_t (*ep_create_fn)(dds_entity_t, dds_entity_t, const dds_qos_t *qos, const dds_listener_t *listener); - -static struct dds_security_cryptography_impl * get_crypto_context(dds_entity_t participant) -{ - struct dds_entity *pp_entity = NULL; - struct participant *pp; - struct dds_security_cryptography_impl *context; - dds_return_t ret; - - ret = dds_entity_lock (participant, DDS_KIND_PARTICIPANT, &pp_entity); - CU_ASSERT_EQUAL_FATAL (ret, 0); - thread_state_awake (lookup_thread_state(), &pp_entity->m_domain->gv); - pp = entidx_lookup_participant_guid (pp_entity->m_domain->gv.entity_index, &pp_entity->m_guid); - CU_ASSERT_FATAL (pp != NULL); - context = (struct dds_security_cryptography_impl *) q_omg_participant_get_cryptography (pp); - thread_state_asleep (lookup_thread_state ()); - dds_entity_unlock (pp_entity); - return context; -} - static const char * pk_to_str(DDS_Security_ProtectionKind pk) { switch (pk) @@ -181,14 +159,6 @@ static dds_qos_t *get_qos() return qos; } -static char *create_topic_name(const char *prefix, uint32_t nr, char *name, size_t size) -{ - ddsrt_pid_t pid = ddsrt_getpid (); - ddsrt_tid_t tid = ddsrt_gettid (); - (void)snprintf(name, size, "%s%d_pid%" PRIdPID "_tid%" PRIdTID "", prefix, nr, pid, tid); - return name; -} - static dds_entity_t create_pp (dds_domainid_t domain_id, const struct domain_sec_config * domain_config, set_crypto_params_fn set_crypto_params) { dds_qos_t *qos = dds_create_qos (); @@ -280,45 +250,6 @@ static void test_fini(size_t n_sub_domain, size_t n_pub_domain) printf("Test finished\n"); } -static void sync_writer_to_readers(dds_entity_t pub_participant, dds_entity_t writer, size_t n_exp_rd) -{ - dds_attach_t triggered; - dds_return_t ret; - dds_entity_t waitset_wr = dds_create_waitset (pub_participant); - CU_ASSERT_FATAL (waitset_wr > 0); - dds_publication_matched_status_t pub_matched; - - /* Sync writer to reader. */ - ret = dds_waitset_attach (waitset_wr, writer, writer); - CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); - while (true) - { - ret = dds_waitset_wait (waitset_wr, &triggered, 1, DDS_SECS(5)); - CU_ASSERT_FATAL (ret >= 1); - CU_ASSERT_EQUAL_FATAL (writer, (dds_entity_t)(intptr_t) triggered); - ret = dds_get_publication_matched_status(writer, &pub_matched); - CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); - if (pub_matched.total_count >= n_exp_rd) - break; - }; - dds_delete (waitset_wr); -} - -static void reader_wait_for_data(dds_entity_t sub_participant, dds_entity_t reader) -{ - dds_attach_t triggered; - dds_return_t ret; - dds_entity_t waitset_rd = dds_create_waitset (sub_participant); - CU_ASSERT_FATAL (waitset_rd > 0); - - ret = dds_waitset_attach (waitset_rd, reader, reader); - CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); - ret = dds_waitset_wait (waitset_rd, &triggered, 1, DDS_SECS(5)); - CU_ASSERT_EQUAL_FATAL (ret, 1); - CU_ASSERT_EQUAL_FATAL (reader, (dds_entity_t)(intptr_t)triggered); - dds_delete (waitset_rd); -} - static void create_eps (dds_entity_t **endpoints, dds_entity_t **topics, size_t n_dom, size_t n_pp, size_t n_eps, const char * topic_name, const dds_topic_descriptor_t *topic_descriptor, const dds_entity_t * pps, const dds_qos_t * qos, ep_create_fn ep_create, unsigned status_mask) { @@ -381,7 +312,7 @@ static void test_write_read(struct domain_sec_config *domain_config, for (size_t w = 0; w < n_writers; w++) { size_t wr_index = pp_index * n_writers + w; - sync_writer_to_readers (g_pub_participants[pp_index], writers[wr_index], n_sub_domains * n_sub_participants * n_readers); + sync_writer_to_readers (g_pub_participants[pp_index], writers[wr_index], (uint32_t)(n_sub_domains * n_sub_participants * n_readers)); sample.id = (int32_t) wr_index; printf("writer %"PRId32" writing sample %d\n", writers[wr_index], sample.id); ret = dds_write (writers[wr_index], &sample); @@ -404,7 +335,7 @@ static void test_write_read(struct domain_sec_config *domain_config, ret = dds_take (readers[rd_index], samples, info, 1, 1); if (ret == 0) { - reader_wait_for_data (g_sub_participants[pp_index], readers[rd_index]); + reader_wait_for_data (g_sub_participants[pp_index], readers[rd_index], DDS_SECS(5)); continue; } printf("reader %"PRId32" received sample %d\n", readers[rd_index], rd_sample.id); @@ -500,7 +431,7 @@ static void test_payload_secret(DDS_Security_ProtectionKind rtps_pk, DDS_Securit { if ((ret = dds_take (readers[0], samples, info, 1, 1)) == 0) { - reader_wait_for_data (g_sub_participants[0], readers[0]); + reader_wait_for_data (g_sub_participants[0], readers[0], DDS_SECS(5)); continue; } CU_ASSERT_EQUAL_FATAL (ret, 1);