From fde05810c6b53d8ddd829b3c6f08eb39ceedd816 Mon Sep 17 00:00:00 2001 From: Erik Boasson Date: Wed, 2 Oct 2019 17:29:51 +0200 Subject: [PATCH] Drop broken protection against casual eavesdroppers From a distant past came code to encrypt data on the wire, but it hasn't been functional in Cyclone for a long time and it only ever provided protection against casual eavesdroppers. It is better to delete it. Signed-off-by: Erik Boasson --- src/core/ddsi/CMakeLists.txt | 2 - src/core/ddsi/include/dds/ddsi/q_config.h | 38 - .../ddsi/include/dds/ddsi/q_feature_check.h | 9 - src/core/ddsi/include/dds/ddsi/q_globals.h | 11 - src/core/ddsi/include/dds/ddsi/q_security.h | 46 - src/core/ddsi/src/q_config.c | 136 -- src/core/ddsi/src/q_init.c | 18 - src/core/ddsi/src/q_receive.c | 64 - src/core/ddsi/src/q_security.c | 1743 ----------------- src/core/ddsi/src/q_xmsg.c | 81 +- 10 files changed, 13 insertions(+), 2135 deletions(-) delete mode 100644 src/core/ddsi/include/dds/ddsi/q_security.h delete mode 100644 src/core/ddsi/src/q_security.c diff --git a/src/core/ddsi/CMakeLists.txt b/src/core/ddsi/CMakeLists.txt index 988b58c..8ba1f8f 100644 --- a/src/core/ddsi/CMakeLists.txt +++ b/src/core/ddsi/CMakeLists.txt @@ -47,7 +47,6 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src" q_qosmatch.c q_radmin.c q_receive.c - q_security.c q_sockwaitset.c q_thread.c q_time.c @@ -106,7 +105,6 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi" q_radmin.h q_receive.h q_rtps.h - q_security.h q_sockwaitset.h q_thread.h q_time.h diff --git a/src/core/ddsi/include/dds/ddsi/q_config.h b/src/core/ddsi/include/dds/ddsi/q_config.h index f06a8cd..def6e66 100644 --- a/src/core/ddsi/include/dds/ddsi/q_config.h +++ b/src/core/ddsi/include/dds/ddsi/q_config.h @@ -14,9 +14,6 @@ #include "dds/ddsi/q_log.h" #include "dds/ddsi/q_thread.h" -#ifdef DDSI_INCLUDE_ENCRYPTION -#include "dds/ddsi/q_security.h" -#endif /* DDSI_INCLUDE_ENCRYPTION */ #include "dds/ddsi/q_xqos.h" #include "dds/ddsi/q_feature_check.h" @@ -73,34 +70,6 @@ struct config_listelem { struct config_listelem *next; }; -#ifdef DDSI_INCLUDE_ENCRYPTION -struct q_security_plugins -{ - c_bool (*encode) (q_securityEncoderSet, uint32_t, void *, uint32_t, uint32_t *); - c_bool (*decode) (q_securityDecoderSet, void *, size_t, size_t *); - q_securityEncoderSet (*new_encoder) (void); - q_securityDecoderSet (*new_decoder) (void); - c_bool (*free_encoder) (q_securityEncoderSet); - c_bool (*free_decoder) (q_securityDecoderSet); - ssize_t (*send_encoded) (ddsi_tran_conn_t, const nn_locator_t *dst, size_t niov, ddsrt_iovec_t *iov, q_securityEncoderSet *, uint32_t, uint32_t); - char * (*cipher_type) (q_cipherType); - c_bool (*cipher_type_from_string) (const char *, q_cipherType *); - uint32_t (*header_size) (q_securityEncoderSet, uint32_t); - q_cipherType (*encoder_type) (q_securityEncoderSet, uint32_t); - c_bool (*valid_uri) (q_cipherType, const char *); -}; - -struct q_security_plugins q_security_plugin; - -struct config_securityprofile_listelem -{ - struct config_securityprofile_listelem *next; - char *name; - q_cipherType cipher; - char *key; -}; -#endif /* DDSI_INCLUDE_ENCRYPTION */ - #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS struct config_networkpartition_listelem { struct config_networkpartition_listelem *next; @@ -108,10 +77,6 @@ struct config_networkpartition_listelem { char *address_string; struct addrset *as; int connected; -#ifdef DDSI_INCLUDE_ENCRYPTION - char *profileName; - struct config_securityprofile_listelem *securityProfile; -#endif /* DDSI_INCLUDE_ENCRYPTION */ uint32_t partitionHash; uint32_t partitionId; }; @@ -311,9 +276,6 @@ struct config struct config_channel_listelem *channels; struct config_channel_listelem *max_channel; /* channel with highest prio; always computed */ #endif /* DDSI_INCLUDE_NETWORK_CHANNELS */ -#ifdef DDSI_INCLUDE_ENCRYPTION - struct config_securityprofile_listelem *securityProfiles; -#endif /* DDSI_INCLUDE_ENCRYPTION */ #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS struct config_networkpartition_listelem *networkPartitions; unsigned nof_networkPartitions; diff --git a/src/core/ddsi/include/dds/ddsi/q_feature_check.h b/src/core/ddsi/include/dds/ddsi/q_feature_check.h index 9c62c20..f87911e 100644 --- a/src/core/ddsi/include/dds/ddsi/q_feature_check.h +++ b/src/core/ddsi/include/dds/ddsi/q_feature_check.h @@ -11,9 +11,6 @@ */ /* Feature macros: - - ENCRYPTION: support for encryption - requires: NETWORK_PARTITIONS - - SSM: support for source-specific multicast requires: NETWORK_PARTIITONS also requires platform support; SSM is silently disabled if the @@ -31,12 +28,6 @@ */ -#ifdef DDSI_INCLUDE_ENCRYPTION - #ifndef DDSI_INCLUDE_NETWORK_PARTITIONS - #error "ENCRYPTION requires NETWORK_PARTITIONS" - #endif -#endif - #ifdef DDSI_INCLUDE_SSM #ifndef DDSI_INCLUDE_NETWORK_PARTITIONS #error "SSM requires NETWORK_PARTITIONS" diff --git a/src/core/ddsi/include/dds/ddsi/q_globals.h b/src/core/ddsi/include/dds/ddsi/q_globals.h index 3b8ec82..c14b490 100644 --- a/src/core/ddsi/include/dds/ddsi/q_globals.h +++ b/src/core/ddsi/include/dds/ddsi/q_globals.h @@ -26,10 +26,6 @@ #include "dds/ddsi/q_sockwaitset.h" #include "dds/ddsi/q_config.h" -#ifdef DDSI_INCLUDE_ENCRYPTION -#include "dds/ddsi/q_security.h" /* for q_securityDecoderSet */ -#endif /* DDSI_INCLUDE_ENCRYPTION */ - #if defined (__cplusplus) extern "C" { #endif @@ -288,13 +284,6 @@ struct q_globals { int sendq_stop; struct thread_state1 *sendq_ts; -#ifdef DDSI_INCLUDE_ENCRYPTION - /* Codecs needed for decoding incoming encrypted messages - FIXME: should be a property of the receiver thread, and pass down - while processing messages. For now made global */ - q_securityDecoderSet recvSecurityCodec; -#endif /* DDSI_INCLUDE_ENCRYPTION */ - /* File for dumping captured packets, NULL if disabled */ FILE *pcap_fp; ddsrt_mutex_t pcap_lock; diff --git a/src/core/ddsi/include/dds/ddsi/q_security.h b/src/core/ddsi/include/dds/ddsi/q_security.h deleted file mode 100644 index a01dbe1..0000000 --- a/src/core/ddsi/include/dds/ddsi/q_security.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 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 - */ -#ifdef DDSI_INCLUDE_ENCRYPTION -#ifndef Q_SECURITY_H -#define Q_SECURITY_H - -#include "c_typebase.h" - -#if defined (__cplusplus) -extern "C" { -#endif - -/* Generic class */ -C_CLASS(q_securityEncoderSet); -C_CLASS(q_securityDecoderSet); - -/* Set of supported ciphers */ -typedef enum -{ - Q_CIPHER_UNDEFINED, - Q_CIPHER_NULL, - Q_CIPHER_BLOWFISH, - Q_CIPHER_AES128, - Q_CIPHER_AES192, - Q_CIPHER_AES256, - Q_CIPHER_NONE, - Q_CIPHER_MAX -} q_cipherType; - -void ddsi_security_plugin (void); - -#if defined (__cplusplus) -} -#endif - -#endif -#endif diff --git a/src/core/ddsi/src/q_config.c b/src/core/ddsi/src/q_config.c index 8a0982b..6ee4d81 100644 --- a/src/core/ddsi/src/q_config.c +++ b/src/core/ddsi/src/q_config.c @@ -181,9 +181,6 @@ DUPF(retransmit_merging); DUPF(sched_class); DUPF(maybe_memsize); DUPF(maybe_int32); -#ifdef DDSI_INCLUDE_ENCRYPTION -DUPF(cipher); -#endif #ifdef DDSI_INCLUDE_BANDWIDTH_LIMITING DUPF(bandwidth); #endif @@ -207,9 +204,6 @@ DF(ff_networkAddresses); #ifdef DDSI_INCLUDE_NETWORK_CHANNELS DI(if_channel); #endif /* DDSI_INCLUDE_NETWORK_CHANNELS */ -#ifdef DDSI_INCLUDE_ENCRYPTION -DI(if_security_profile); -#endif #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS DI(if_network_partition); DI(if_ignored_partition); @@ -287,33 +281,6 @@ static const struct cfgelem general_cfgelems[] = { END_MARKER }; -#ifdef DDSI_INCLUDE_ENCRYPTION -static const struct cfgelem securityprofile_cfgattrs[] = { - { ATTR("Name"), 1, NULL, RELOFF(config_securityprofile_listelem, name), 0, uf_string, ff_free, pf_string, - BLURB("

This attribute specifies the name of this DDSI2E security profile. Two security profiles cannot have the same name.

") }, - { ATTR("Cipher"), 1, "null", RELOFF(config_securityprofile_listelem, cipher), 0, uf_cipher, 0, pf_cipher, - BLURB("

This attribute specifies the cipher to be used for encrypting traffic over network partitions secured by this security profile. The possible ciphers are:

\n\ -\n\ -

SHA1 is used on conjunction with all ciphers except \"null\" to ensure data integrity.

") }, - { ATTR("CipherKey"), 1, "", RELOFF(config_securityprofile_listelem, key), 0, uf_string, ff_free, pf_key, - BLURB("

The CipherKey attribute is used to define the secret key required by the cipher selected using the Cipher attribute. The value can be a URI referencing an external file containing the secret key, or the secret key can be defined in-place as a string value.

\n\ -

The key must be specified as a hexadecimal string with each character representing 4 bits of the key. E.g., 1ABC represents the 16-bit key 0001 1010 1011 1100. The key should not follow a well-known pattern and must exactly match the key length of the selected cipher.

\n\ -

A malformed key will cause the security profile to be marked as invalid, and disable all network partitions secured by the (invalid) security profile to prevent information leaks.

\n\ -

As all DDS applications require read access to the XML configuration file, for security reasons it is recommended to store the secret key in an external file in the file system, referenced by its URI. The file should be protected against read and write access from other users on the host.

") }, - END_MARKER -}; - -static const struct cfgelem security_cfgelems[] = { - { LEAF_W_ATTRS("SecurityProfile", securityprofile_cfgattrs), INT_MAX, 0, ABSOFF(securityProfiles), if_security_profile, 0, 0, 0, - BLURB("

This element defines a DDSI2E security profile.

") }, - END_MARKER -}; -#endif /* DDSI_INCLUDE_ENCRYPTION */ - #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS static const struct cfgelem networkpartition_cfgattrs[] = { { ATTR("Name"), 1, NULL, RELOFF(config_networkpartition_listelem, name), 0, uf_string, ff_free, pf_string, @@ -322,10 +289,6 @@ static const struct cfgelem networkpartition_cfgattrs[] = { BLURB("

This attribute specifies the multicast addresses associated with the network partition as a comma-separated list. Readers matching this network partition (cf. Partitioning/PartitionMappings) will listen for multicasts on all of these addresses and advertise them in the discovery protocol. The writers will select the most suitable address from the addresses advertised by the readers.

") }, { ATTR("Connected"), 1, "true", RELOFF(config_networkpartition_listelem, connected), 0, uf_boolean, 0, pf_boolean, BLURB("

This attribute is a placeholder.

") }, -#ifdef DDSI_INCLUDE_ENCRYPTION - { ATTR("SecurityProfile"), 1, "null", RELOFF(config_networkpartition_listelem, profileName), 0, uf_string, ff_free, pf_string, - BLURB("

This attribute selects the DDSI2E security profile for encrypting the traffic mapped to this DDSI2E network partition. The default \"null\" means the network partition is unsecured; any other name refers to a security profile defined using the Security/SecurityProfile elements.

") }, -#endif /* DDSI_INCLUDE_ENCRYPTION */ END_MARKER }; @@ -810,10 +773,6 @@ static const struct cfgelem domain_cfgelems[] = { { MOVED("Id", "CycloneDDS/Domain[@Id]") }, { GROUP("General", general_cfgelems), BLURB("

The General element specifies overall DDSI2E service settings.

") }, -#ifdef DDSI_INCLUDE_ENCRYPTION - { GROUP("Security", security_cfgelems), - BLURB("

The Security element specifies DDSI2E security profiles that can be used to encrypt traffic mapped to DDSI2E network partitions.

") }, -#endif #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS { GROUP("Partitioning", partitioning_cfgelems), BLURB("

The Partitioning element specifies DDSI2E network partitions and how DCPS partition/topic combinations are mapped onto the network partitions.

") }, @@ -849,9 +808,6 @@ static const struct cfgelem root_cfgelems[] = { { GROUP_W_ATTRS("Domain", domain_cfgelems, domain_cfgattrs), BLURB("

The General element specifying Domain related settings.

") }, { MOVED("General", "CycloneDDS/Domain/General") }, -#ifdef DDSI_INCLUDE_ENCRYPTION - { MOVED("Security", "CycloneDDS/Domain/Security") }, -#endif #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS { MOVED("Partitioning", "CycloneDDS/Domain/Partitioning") }, #endif @@ -1263,15 +1219,6 @@ static int if_channel(struct cfgst *cfgst, void *parent, struct cfgelem const * } #endif /* DDSI_INCLUDE_NETWORK_CHANNELS */ -#ifdef DDSI_INCLUDE_ENCRYPTION -static int if_security_profile (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) -{ - if (if_common (cfgst, parent, cfgelem, sizeof (struct config_securityprofile_listelem)) == NULL) - return -1; - return 0; -} -#endif /* DDSI_INCLUDE_ENCRYPTION */ - #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS static int if_network_partition (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) { @@ -1279,10 +1226,6 @@ static int if_network_partition (struct cfgst *cfgst, void *parent, struct cfgel if (new == NULL) return -1; new->address_string = NULL; -#ifdef DDSI_INCLUDE_ENCRYPTION - new->profileName = NULL; - new->securityProfile = NULL; -#endif /* DDSI_INCLUDE_ENCRYPTION */ return 0; } @@ -1683,31 +1626,6 @@ static void pf_memsize (struct cfgst *cfgst, void *parent, struct cfgelem const pf_int64_unit (cfgst, *elem, sources, unittab_memsize, "B"); } -#ifdef DDSI_INCLUDE_ENCRYPTION -static enum update_result uf_cipher(struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, UNUSED_ARG(int first), const char *value) -{ - if (q_security_plugin.cipher_type_from_string) - { - q_cipherType * const elem = cfg_address (cfgst, parent, cfgelem); - if (! q_security_plugin.cipher_type_from_string (value, elem)) - return cfg_error (cfgst, "%s: undefined value", value); - } - return URES_SUCCESS; -} - -static void pf_cipher (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem, uint32_t sources) -{ - q_cipherType const * const p = cfg_address (cfgst, parent, cfgelem); - if (q_security_plugin.cipher_type) - cfg_logelem (cfgst, sources, "%s", (q_security_plugin.cipher_type) (*p)); -} - -static void pf_key (struct cfgst *cfgst, UNUSED_ARG (void *parent), UNUSED_ARG (struct cfgelem const * const cfgelem), uint32_t sources) -{ - cfg_logelem (cfgst, sources, ""); -} -#endif /* DDSI_INCLUDE_ENCRYPTION */ - static enum update_result uf_tracingOutputFileName (struct cfgst *cfgst, UNUSED_ARG (void *parent), UNUSED_ARG (struct cfgelem const * const cfgelem), UNUSED_ARG (int first), const char *value) { struct config * const cfg = cfgst->cfg; @@ -2848,67 +2766,13 @@ struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domi ok = 0; #endif -#ifdef DDSI_INCLUDE_ENCRYPTION - /* Check security profiles */ - { - struct config_securityprofile_listelem *s = cfgst->cfg->securityProfiles; - while (s) - { - switch (s->cipher) - { - case Q_CIPHER_UNDEFINED: - case Q_CIPHER_NULL: - /* nop */ - if (s->key && strlen(s->key) > 0) - DDS_ILOG (DDS_LC_INFO, domid, "config: DDSI2Service/Security/SecurityProfile[@cipherkey]: %s: cipher key not required\n", s->key); - break; - - default: - /* read the cipherkey if present */ - if (!s->key || strlen(s->key) == 0) - { - DDS_ILOG (DDS_LC_ERROR, domid, "config: DDSI2Service/Security/SecurityProfile[@cipherkey]: cipher key missing\n"); - ok = 0; - } - else if (q_security_plugin.valid_uri && !(q_security_plugin.valid_uri) (s->cipher, s->key)) - { - DDS_ILOG (DDS_LC_ERROR, domid, "config: DDSI2Service/Security/SecurityProfile[@cipherkey]: %s : incorrect key\n", s->key); - ok = 0; - } - } - s = s->next; - } - } -#endif /* DDSI_INCLUDE_ENCRYPTION */ - #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS /* Assign network partition ids */ -#ifdef DDSI_INCLUDE_ENCRYPTION - /* also create links from the network partitions to the - securityProfiles and signal errors if profiles do not exist */ -#endif /* DDSI_INCLUDE_ENCRYPTION */ { struct config_networkpartition_listelem *p = cfgst->cfg->networkPartitions; cfgst->cfg->nof_networkPartitions = 0; while (p) { -#ifdef DDSI_INCLUDE_ENCRYPTION - if (ddsrt_strcasecmp(p->profileName, "null") == 0) - p->securityProfile = NULL; - else - { - struct config_securityprofile_listelem *s = cfgst->cfg->securityProfiles; - while (s && ddsrt_strcasecmp(p->profileName, s->name) != 0) - s = s->next; - if (s) - p->securityProfile = s; - else - { - DDS_ILOG (DDS_LC_ERROR, domid, "config: DDSI2Service/Partitioning/NetworkPartitions/NetworkPartition[@securityprofile]: %s: unknown securityprofile\n", p->profileName); - ok = 0; - } - } -#endif /* DDSI_INCLUDE_ENCRYPTION */ cfgst->cfg->nof_networkPartitions++; /* also use crc32 just like native nw and ordinary ddsi2e, only for interoperability because it is asking for trouble & diff --git a/src/core/ddsi/src/q_init.c b/src/core/ddsi/src/q_init.c index 78414a2..f2bb0d9 100644 --- a/src/core/ddsi/src/q_init.c +++ b/src/core/ddsi/src/q_init.c @@ -1001,14 +1001,6 @@ int rtps_init (struct q_globals *gv) gv->xmsgpool = nn_xmsgpool_new (); gv->serpool = ddsi_serdatapool_new (); -#ifdef DDSI_INCLUDE_ENCRYPTION - if (q_security_plugin.new_decoder) - { - gv->recvSecurityCodec = (q_security_plugin.new_decoder) (); - GVLOG (DDS_LC_CONFIG, "decoderset created\n"); - } -#endif - nn_plist_init_default_participant (&gv->default_plist_pp); nn_plist_init_default_participant (&gv->default_local_plist_pp); nn_xqos_init_default_reader (&gv->default_xqos_rd); @@ -1337,10 +1329,6 @@ err_unicast_sockets: ddsrt_cond_destroy (&gv->participant_set_cond); ddsrt_mutex_destroy (&gv->participant_set_lock); free_special_topics (gv); -#ifdef DDSI_INCLUDE_ENCRYPTION - if (q_security_plugin.free_decoder) - q_security_plugin.free_decoder (gv->recvSecurityCodec); -#endif nn_xqos_fini (&gv->builtin_endpoint_xqos_wr); nn_xqos_fini (&gv->builtin_endpoint_xqos_rd); nn_xqos_fini (&gv->spdp_endpoint_xqos); @@ -1498,12 +1486,6 @@ void rtps_stop (struct q_globals *gv) nn_reorder_free (gv->spdp_reorder); nn_defrag_free (gv->spdp_defrag); ddsrt_mutex_destroy (&gv->spdp_lock); -#ifdef DDSI_INCLUDE_ENCRYPTION - if (q_security_plugin.free_decoder) - { - (q_security_plugin.free_decoder) (gv->recvSecurityCodec); - } -#endif /* DDSI_INCLUDE_ENCRYPTION */ { struct ephash_enum_proxy_participant est; diff --git a/src/core/ddsi/src/q_receive.c b/src/core/ddsi/src/q_receive.c index f08d9bb..65ac23f 100644 --- a/src/core/ddsi/src/q_receive.c +++ b/src/core/ddsi/src/q_receive.c @@ -206,19 +206,6 @@ static int valid_InfoTS (InfoTS_t *msg, size_t size, int byteswap) } } -static int valid_PT_InfoContainer (PT_InfoContainer_t *msg, size_t size, int byteswap) -{ - if (size < sizeof (PT_InfoContainer_t)) - return 0; -#if 0 - if (msg->smhdr.flags) - return 0; -#endif - if (byteswap) - msg->id = bswap4u (msg->id); - return 1; -} - static int valid_Heartbeat (Heartbeat_t *msg, size_t size, int byteswap) { if (size < sizeof (*msg)) @@ -2474,22 +2461,6 @@ static int handle_DataFrag (struct receiver_state *rst, nn_etime_t tnow, struct return 1; } -#ifdef DDSI_INCLUDE_ENCRYPTION -static size_t decode_container (unsigned char *submsg, size_t len) -{ - size_t result = len; - if (gv.recvSecurityCodec && len > 0) - { - if (! (q_security_plugin.decode) - (gv.recvSecurityCodec, submsg, len, &result /* in/out, decrements the length*/)) - { - result = 0; - } - } - return result; -} -#endif /* DDSI_INCLUDE_ENCRYPTION */ - static void malformed_packet_received_nosubmsg (const struct q_globals *gv, const unsigned char * msg, ssize_t len, const char *state, nn_vendorid_t vendorid ) { @@ -2829,41 +2800,6 @@ static int handle_submsg_sequence ts_for_latmeas = 0; } break; - - case SMID_PT_INFO_CONTAINER: - if (vendor_is_eclipse_or_prismtech (rst->vendor)) - { - state = "parse:pt_info_container"; - GVTRACE ("PT_INFO_CONTAINER("); - if (!valid_PT_InfoContainer (&sm->pt_infocontainer, submsg_size, byteswap)) - goto malformed; - switch (sm->pt_infocontainer.id) - { - case PTINFO_ID_ENCRYPT: -#ifdef DDSI_INCLUDE_ENCRYPTION - if (q_security_plugin.decode) - { - /* we have: msg .. submsg .. submsg+submsg_size-1 submsg .. msg+len-1 - our container: data starts immediately following the pt_infocontainer */ - const size_t len1 = submsg_size - sizeof (PT_InfoContainer_t); - unsigned char * const submsg1 = submsg + sizeof (PT_InfoContainer_t); - size_t len2 = decode_container (submsg1, len1); - if ( len2 != 0 ) { - TRACE ((")\n")); - thread_state_asleep (ts1); - if (handle_submsg_sequence (conn, srcloc, tnowWC, tnowE, src_prefix, dst_prefix, msg, (size_t) (submsg1 - msg) + len2, submsg1, rmsg) < 0) - goto malformed_asleep; - thread_state_awake (ts1); - } - TRACE (("PT_INFO_CONTAINER END")); - } -#endif /* DDSI_INCLUDE_ENCRYPTION */ - break; - default: - GVTRACE ("(unknown id %"PRIu32"?)\n", sm->pt_infocontainer.id); - } - } - break; case SMID_PT_MSG_LEN: { #if 0 diff --git a/src/core/ddsi/src/q_security.c b/src/core/ddsi/src/q_security.c deleted file mode 100644 index 0a94204..0000000 --- a/src/core/ddsi/src/q_security.c +++ /dev/null @@ -1,1743 +0,0 @@ -/* - * Copyright(c) 2006 to 2018 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 - */ -#ifdef DDSI_INCLUDE_ENCRYPTION - -#include "dds/ddsi/q_security.h" -#include "dds/ddsi/q_config.h" -#include "dds/ddsi/q_log.h" -#include "os/os_stdlib.h" -#include "os/os_process.h" -#include "os/os_thread.h" -#include "os/os_heap.h" - -#include /* for memcpy */ -#include /* for isspace */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Supported URI schema by parser */ -#define URI_FILESCHEMA "file://" - -/* The max. key-length is defined by crypto-lib, here set to 32 bytes by - * OpenSSL */ -#define Q_MAX_KEY_LENGTH EVP_MAX_KEY_LENGTH - -/* The block-size defines the range of sequence-counter, it varies per - * cipher */ -#define Q_BLOWFISH_BLOCK_SIZE (8) -#define Q_AES_BLOCK_SIZE (16) -#define Q_BLOCK_SIZE_MAX (16) - -/** The counter length corresponds to the specific blocksize */ -#define Q_NULL_COUNTER_SIZE (0L) -#define Q_BLOWFISH_COUNTER_SIZE Q_BLOWFISH_BLOCK_SIZE -#define Q_AES_COUNTER_SIZE Q_AES_BLOCK_SIZE - -/* Define macros for 20 bytes digest, but as a single bit-flip shall change - * half of the digests bits, only 12 bytes of them are transfered in security - * header (CHECKME, shall we take lower 12 bytes or higher 12 bytes?) - * Assure the used digest length is 4bytes alligned, to ensure proper alignment of headersize*/ -#define Q_DIGEST_LENGTH (SHA_DIGEST_LENGTH) -#define Q_DIGEST_LENGTH_2 (12) -#define Q_SHA1 SHA1 - -/* For future usage, byte-size of unique value to define lower 4 bytes of each - * counter, shall be chosen randomly */ -#define Q_KEYID_LENGTH 4 - -#define Q_REPORT_OPENSSL_ERR(x) \ -while ( ERR_peek_error() ) \ - DDS_ERROR(x "%s", ERR_error_string(ERR_get_error(), NULL)); - - - -typedef unsigned char q_sha1Digest[SHA_DIGEST_LENGTH]; /* 20 bytes + '\0' */ - - -C_STRUCT(q_sha1Header) { - unsigned char hash[Q_DIGEST_LENGTH_2]; /* hash over body and security attributes */ - /* ----- up to here encrypted ------*/ -}; - - -/* class declarations */ -C_CLASS(q_nullHeader); -C_CLASS(q_blowfishHeader); -C_CLASS(q_aesHeader); - - -/* structure declarations */ -C_STRUCT(q_nullHeader) { - q_cipherType cipherType; /* network order */ /* OPTME */ - os_uint32 partitionId; /* network order */ -}; - -C_STRUCT(q_blowfishHeader) { - unsigned char keyId[Q_KEYID_LENGTH]; /* required for re-keying (reserved for future usage) */ - unsigned char counter[Q_BLOWFISH_BLOCK_SIZE]; /* cipher block length */ - q_cipherType cipherType; /* network order */ /* OPTME */ - os_uint32 partitionId; /* network order */ -}; - -C_STRUCT(q_aesHeader) { - unsigned char keyId[Q_KEYID_LENGTH]; /* required for re-keying (reserved for future usage)*/ - unsigned char counter[Q_AES_BLOCK_SIZE]; /* cipher block length */ - q_cipherType cipherType; /* network order */ /* OPTME */ - os_uint32 partitionId; /* network order */ -}; - -/* To prevent fragmentations of heap and costly pointer dereferencing with - * possible lot of cache-misses, we declare a union that allows us to allocate - * a single array of codecs, each entry realizing a different cipher and - * header-size. */ -C_STRUCT(q_securityHeader) { - union { - C_STRUCT(q_nullHeader) null; /* obsolete */ - C_STRUCT(q_blowfishHeader) blowfish; - C_STRUCT(q_aesHeader) aes; - } u; -}; - - -/* a number of error states, each codec within the set can be in: - * - * Q_CODEC_STATE_OK: everything is Ok, encryption/decryption is performed - * - * Q_CODEC_STATE_REQUIRES_REKEYING: same as Q_CODEC_STATE_OK, but codec has - * reached a state which requires re-keying, shall be used as signal for codec - * manegement - * - * Q_CODEC_STATE_DROP_TEMP: drop encodings/decodings temporarily, caused by - * faulty cipher-keys read form file. Updating the key-file will solve the - * problem and release the block. - * - * Q_CODEC_STATE_DROP_PERM: drop encodings/decodings permanently, caused by - * 'un-connected' partitions, or faulty security-profiles, eg. un-known - * cipher. -*/ -typedef enum { - Q_CODEC_STATE_OK=0, - Q_CODEC_STATE_REQUIRES_REKEYING=1, - Q_CODEC_STATE_DROP_TEMP=2, - Q_CODEC_STATE_DROP_PERM=4 -} q_securityCodecState; - -/* if not 0, the codec is blocked */ -#define IS_DROP_STATE(state) \ - ((state)&(Q_CODEC_STATE_DROP_TEMP|Q_CODEC_STATE_DROP_PERM)) - -/* declaration of codec */ -C_CLASS(q_securityPartitionDecoder); -C_CLASS(q_securityPartitionEncoder); - -C_STRUCT(q_securityPartitionDecoder) { - q_securityCodecState state; - char *cipherKeyURL; - q_cipherType cipherType; - os_char * partitionName; - EVP_CIPHER_CTX cipherContext; - /* this codec does hold state and therfor does not require securityHeader - * attributes */ -}; - - -C_STRUCT(q_securityPartitionEncoder){ - q_securityCodecState state; - char *cipherKeyURL; - q_cipherType cipherType; - os_char * partitionName; - EVP_CIPHER_CTX cipherContext; - /* The current state will be appendend to message and will be used by - * receiver to decrypt the message in question. To avoid cache misses - * store the current state close to EVP_CIPHER_CTX */ - C_STRUCT(q_securityHeader) securityHeader; /* holds the state */ -}; - - -C_STRUCT(q_securityDecoderSet) { - os_uint32 nofPartitions; - q_securityPartitionDecoder decoders; -}; - -C_STRUCT(q_securityEncoderSet) { - os_uint32 nofPartitions; - os_uint32 headerSizeMax; - q_securityPartitionEncoder encoders; -}; - - -#if 1 -/* no dumping of buffer before and after en-/decrypting */ -#define DUMP_BUFFER(partitionName,chan,buffer,length,label,counter,counterLength, bufferLength) -#else -/* Use this line to dump to the ddsi tracefile */ -#define DUMP_BUFFER(partitionName,chan,buffer,length,label,counter,counterLength,bufferLenght) tdumpBuffer(partitionName,chan,buffer,length,label,counter,counterLength, bufferLength) -/* Use this line to dump to a file in the /tmp/directory */ -#define DUMP_BUFFER(partitionName,chan,buffer,length,label,counter,counterLength,bufferLenght) dumpBuffer(partitionName,chan,buffer,length,label,counter,counterLength, bufferLength) -#endif - -/** private operations */ - -#if 0 -static void dumpCounter (FILE *of, unsigned char* counter, int counterLength) -{ - int i = 0; - if (counter) { - for (i=0; iheaderSizeMax; -} - - -static c_bool decoderIsBlocked (q_securityPartitionDecoder codec) -{ - return (IS_DROP_STATE(codec->state) > 0); -} - -static c_bool encoderIsBlocked (q_securityPartitionEncoder codec) -{ - return (IS_DROP_STATE(codec->state) > 0); -} - -/* returns -1 on error */ -static short hex2bin(char hexChar) -{ - switch (hexChar) { - case '0': return 0; - case '1': return 1; - case '2': return 2; - case '3': return 3; - case '4': return 4; - case '5': return 5; - case '6': return 6; - case '7': return 7; - case '8': return 8; - case '9': return 9; - - case 'a': return 10; - case 'b': return 11; - case 'c': return 12; - case 'd': return 13; - case 'e': return 14; - case 'f': return 15; - - case 'A': return 10; - case 'B': return 11; - case 'C': return 12; - case 'D': return 13; - case 'E': return 14; - case 'F': return 15; - default: - return -1; /* error */ - } -} - -/* returns NULL on error, eg bad hex-string */ -static c_bool hex2key -( - const char* hexKey, - os_uint32 expectedLength, - unsigned char *result /* out */ ) -{ - size_t i, len=0; - short val; - - len = strlen(hexKey); - - for (i=0; i 0) return "unknown"; - else return "ok"; -} - -/* this function is based on original code of - * components/configuration/parser/code/cfg_parser.y */ - -static c_bool q_securityResolveCipherKeyFromUri -( - const char *uriStr, - os_uint32 expectedLength, - unsigned char *cipherKey /* out buffer */ -) -{ - char *filename; - FILE *file = NULL; - char readBuffer[256]; /*at most strings of 255 chars */ - char *hexStr = NULL; - int ret; - c_bool result = FALSE; - - if ((uriStr != NULL) && - (strncmp(uriStr, URI_FILESCHEMA, strlen(URI_FILESCHEMA)) == 0)) { - - /* TBD: compare file-permissions with uid/gid of this process, the - * file should be protected against read/write by others, otherwise we - * should refuse to read from it */ - const char *justPath = - (char *)(uriStr + strlen(URI_FILESCHEMA)); - - filename = ddsrt_strdup (justPath); - file = fopen(filename, "r"); - if (file) { - /* read at most 255 chars from file, this should suffice if the - * secret key has atmost 32 chars */ - ret = fscanf (file, "%255s", readBuffer); - - if (ret != EOF) - { - /* skip leading white spaces */ - for (hexStr=readBuffer; - isspace((unsigned char) *hexStr); - ++hexStr); - - result = hex2key(hexStr, expectedLength, cipherKey); - } - - fclose(file); - } else { - DDS_ERROR("q_securityResolveCipherKeyFromUri: Could not open %s",uriStr); - } - - ddsrt_free(filename); - - } else if (uriStr != NULL) { - /* seems to be a hex string */ - result = hex2key(uriStr, expectedLength, cipherKey); - } - - return result; -} - - -/* Validate the cipherkey, parsing the hex-string directly or the content of - * file */ -static c_bool q_securityIsValidCipherKeyUri -( - q_cipherType cipherType, - const char* cipherKeyUri -) -{ - unsigned char tmpCipherKey[Q_MAX_KEY_LENGTH]; /* transient */ - os_uint32 expectedLength = q_securityCipherKeyLength(cipherType); - - assert(expectedLength > 0); - - /* we are not interested in the key, jsut doing the syntax check */ - return q_securityResolveCipherKeyFromUri(cipherKeyUri, expectedLength, tmpCipherKey); -} - -/* compare cipherName to known identifiers, comparison is case-insensitive */ -static c_bool q_securityCipherTypeFromString(const char* cipherName, - q_cipherType *cipherType) /* out */ -{ - if (cipherName == NULL) - { - DDS_ERROR("q_securityCipherTypeFromString:internal error, empty cipher string"); - *cipherType = Q_CIPHER_UNDEFINED; - return FALSE; - } - - if (ddsrt_strcasecmp(cipherName, "null") == 0) { - *cipherType = Q_CIPHER_NULL; - } else if (ddsrt_strcasecmp(cipherName, "blowfish") == 0 || - ddsrt_strcasecmp(cipherName, "blowfish-sha1") == 0) { - *cipherType = Q_CIPHER_BLOWFISH; - } else if (ddsrt_strcasecmp(cipherName, "aes128") == 0 || - ddsrt_strcasecmp(cipherName, "aes128-sha1") == 0) { - *cipherType = Q_CIPHER_AES128; - } else if (ddsrt_strcasecmp(cipherName, "aes192") == 0 || - ddsrt_strcasecmp(cipherName, "aes192-sha1") == 0) { - *cipherType = Q_CIPHER_AES192; - } else if (ddsrt_strcasecmp(cipherName, "aes256") == 0 || - ddsrt_strcasecmp(cipherName, "aes256-sha1") == 0) { - *cipherType = Q_CIPHER_AES256; -#if 0 - } else if (ddsrt_strcasecmp(cipherName, "rsa-null") == 0) { - *cipherType = Q_CIPHER_RSA_WITH_NULL; - } else if (ddsrt_strcasecmp(cipherName, "rsa-blowfish") == 0 || - ddsrt_strcasecmp(cipherName, "rsa-blowfish-sha1") == 0) { - *cipherType = Q_CIPHER_RSA_WITH_BLOWFISH; - } else if (ddsrt_strcasecmp(cipherName, "rsa-aes128") == 0 || - ddsrt_strcasecmp(cipherName, "rsa-aes128-sha1") == 0) { - *cipherType = Q_CIPHER_RSA_WITH_AES128; - } else if (ddsrt_strcasecmp(cipherName, "rsa-aes192") == 0 || - ddsrt_strcasecmp(cipherName, "rsa-aes192-sha1") == 0) { - *cipherType = Q_CIPHER_RSA_WITH_AES192; - } else if (ddsrt_strcasecmp(cipherName, "rsa-aes256") == 0 || - ddsrt_strcasecmp(cipherName, "rsa-aes256-sha1") == 0) { - *cipherType = Q_CIPHER_RSA_WITH_AES256; -#endif - } else { - *cipherType = Q_CIPHER_UNDEFINED; - return FALSE; - } - return TRUE; -} - -static os_uint32 cipherTypeToHeaderSize(q_cipherType cipherType) { - switch (cipherType) { - case Q_CIPHER_UNDEFINED: - case Q_CIPHER_NONE: - return 0; - case Q_CIPHER_NULL: - return sizeof(C_STRUCT(q_nullHeader)); - - case Q_CIPHER_BLOWFISH: - return sizeof(C_STRUCT(q_sha1Header)) + - sizeof(C_STRUCT(q_blowfishHeader)); - - case Q_CIPHER_AES128: - case Q_CIPHER_AES192: - case Q_CIPHER_AES256: - return sizeof(C_STRUCT(q_sha1Header)) + - sizeof(C_STRUCT(q_aesHeader)); - - default: - assert(0 && "unsupported cipher"); - } - - assert(FALSE); - return 0; -} - -/*these two methods are not static for the moment because of tests*/ - -static -void q_securityRNGSeed (void) -{ - int32_t nsec; - dds_time_t time = ddsrt_time_monotonic(); - nsec = time % DDS_NSECS_IN_SEC; - RAND_seed(nsec,sizeof(nsec)); -} - -static -void q_securityRNGGetRandomNumber(int number_length,unsigned char * randNumber) -{ - RAND_bytes(randNumber,number_length); -} - - -static -c_bool -q_securityPartitionEncoderInit(q_securityPartitionEncoder encoder,struct config_networkpartition_listelem *p) -{ - unsigned char cipherKey[Q_MAX_KEY_LENGTH]; - char *cipherKeyURL = p->securityProfile?p->securityProfile->key:NULL; - os_char * partitionName = p->name; - c_bool connected = (c_bool) p->connected; - q_cipherType cipherType = p->securityProfile?p->securityProfile->cipher: Q_CIPHER_NONE; - os_uint32 hash = p->partitionHash; - os_uint32 partitionId = p->partitionId; - - /* init */ - memset(encoder, 0, sizeof(*encoder)); - memset(cipherKey, 0, sizeof(*cipherKey)); - - - if (!connected) { - DDS_TRACE("Network Partition '%s' (%d) not connected, dropping outbound traffic permanently", partitionName, partitionId); - - encoder->state = Q_CODEC_STATE_DROP_PERM; - encoder->cipherType = Q_CIPHER_UNDEFINED; - encoder->partitionName = partitionName; - - return TRUE; - } - - assert(cipherType != Q_CIPHER_UNDEFINED); - - { - /* init the cipher */ - - const os_uint32 partitionHashNetworkOrder = htonl(hash); - const q_cipherType cipherTypeNetworkOrder = htonl(cipherType); - const unsigned char *iv = NULL; /* ignored by ECBs ciphers */ - const EVP_CIPHER *cipher = NULL; - const os_uint32 cipherKeyLength = q_securityCipherKeyLength(cipherType); - unsigned char randCounter[Q_KEYID_LENGTH]; - - /*TRACE(("Security Encoder init: partition '%s' (%d) (connected), cipherType %d, cipherKey %s\n", - partitionName,partitionId, cipherType, cipherKeyURL));*/ - - encoder->state = Q_CODEC_STATE_OK; - encoder->cipherKeyURL = cipherKeyURL; /* const, required for re-keying */ - encoder->cipherType = cipherType; - encoder->partitionName = partitionName; /* const */ - - q_securityRNGGetRandomNumber(Q_KEYID_LENGTH, randCounter); - - switch (cipherType) { - case Q_CIPHER_NULL: - case Q_CIPHER_NONE: - cipher = EVP_enc_null(); - encoder->securityHeader.u.null.cipherType = cipherTypeNetworkOrder; - encoder->securityHeader.u.null.partitionId = partitionHashNetworkOrder; - break; - - case Q_CIPHER_BLOWFISH: - cipher = EVP_bf_ecb(); - assert(8 == EVP_CIPHER_block_size(cipher)); - assert(16 == cipherKeyLength); - - encoder->securityHeader.u.blowfish.cipherType = cipherTypeNetworkOrder; - encoder->securityHeader.u.blowfish.partitionId = partitionHashNetworkOrder; - - memcpy(encoder->securityHeader.u.blowfish.counter,&randCounter, sizeof(randCounter)); - break; - - case Q_CIPHER_AES128: - cipher = EVP_aes_128_ecb(); - assert(16 == EVP_CIPHER_block_size(cipher)); - assert(16 == cipherKeyLength); - - encoder->securityHeader.u.aes.cipherType = cipherTypeNetworkOrder; - encoder->securityHeader.u.aes.partitionId = partitionHashNetworkOrder; - - memcpy(encoder->securityHeader.u.aes.counter, &randCounter, sizeof(randCounter)); - break; - - case Q_CIPHER_AES192: - cipher = EVP_aes_192_ecb(); - - assert(16 == EVP_CIPHER_block_size(cipher)); - assert(24 == cipherKeyLength); - - encoder->securityHeader.u.aes.cipherType = cipherTypeNetworkOrder; - encoder->securityHeader.u.aes.partitionId = partitionHashNetworkOrder; - - memcpy(encoder->securityHeader.u.aes.counter, &randCounter, sizeof(randCounter)); - break; - - case Q_CIPHER_AES256: - cipher = EVP_aes_256_ecb(); - - assert(16 == EVP_CIPHER_block_size(cipher)); - assert(32 == cipherKeyLength); - - encoder->securityHeader.u.aes.cipherType = cipherTypeNetworkOrder; - encoder->securityHeader.u.aes.partitionId = partitionHashNetworkOrder; - - memcpy(encoder->securityHeader.u.aes.counter, &randCounter, sizeof(randCounter)); - break; - - default: - assert(0 && "never reach"); - } - - /* intitialize the key-buffer */ - if (cipherType != Q_CIPHER_NULL && cipherType != Q_CIPHER_NONE && - !q_securityResolveCipherKeyFromUri(cipherKeyURL,cipherKeyLength,cipherKey)) { - DDS_ERROR("DDSI Security Encoder: dropping traffic of partition '%s' (%d) due to invalid cipher key", - encoder->partitionName, partitionId); - encoder->state = Q_CODEC_STATE_DROP_TEMP; - } - - EVP_CIPHER_CTX_init(&(encoder->cipherContext)); - - EVP_EncryptInit_ex(&(encoder->cipherContext), - cipher, - NULL, - cipherKey, - iv); /* IV is ignored by ECB ciphers */ - } - - return TRUE; -} - - -static -c_bool -q_securityPartitionEncoderFini(q_securityPartitionEncoder encoder) -{ - if (encoder->cipherType != Q_CIPHER_UNDEFINED) { - /* release the cipher */ - EVP_CIPHER_CTX *ctx = NULL; - - ctx = &(encoder->cipherContext); - - EVP_CIPHER_CTX_cleanup(ctx); - } - - return TRUE; -} - -static -c_bool -q_securityPartitionDecoderInit(q_securityPartitionDecoder decoder,struct config_networkpartition_listelem *p) -{ - unsigned char cipherKey[Q_MAX_KEY_LENGTH]; - char *cipherKeyURL = p->securityProfile?p->securityProfile->key:NULL; - os_char * partitionName = p->name; - c_bool connected = (c_bool) p->connected; - q_cipherType cipherType = p->securityProfile?p->securityProfile->cipher: Q_CIPHER_NONE; - os_uint32 partitionId = p->partitionId; - - - /* init */ - memset(decoder, 0, sizeof(*decoder)); - memset(cipherKey, 0, sizeof(cipherKey)); - - if (!connected) { - DDS_TRACE("Network Partition '%s' (%d) not connected, dropping inbound traffic permanently\n", partitionName, partitionId); - - decoder->state = Q_CODEC_STATE_DROP_PERM; - decoder->cipherType = Q_CIPHER_UNDEFINED; - decoder->partitionName = partitionName; - return TRUE; - } - - - assert(cipherType != Q_CIPHER_UNDEFINED); - - { - /* init the cipher */ - const unsigned char *iv = NULL; /* ignored by ECBs ciphers */ - const EVP_CIPHER *cipher = NULL; - const os_uint32 cipherKeyLength = q_securityCipherKeyLength(cipherType); - - /*TRACE(("Security Decoder init: partition '%s' (%d) (connected), cipherType %d, cipherKey %s \n", - partitionName,partitionId, cipherType, cipherKeyURL));*/ - - decoder->state = Q_CODEC_STATE_OK; - decoder->cipherKeyURL = cipherKeyURL; /* const, required for re-keying */ - decoder->cipherType = cipherType; - decoder->partitionName = partitionName; /* const */ - - switch (cipherType) { - case Q_CIPHER_NULL: - case Q_CIPHER_NONE: - cipher = EVP_enc_null(); - break; - - case Q_CIPHER_BLOWFISH: - cipher = EVP_bf_ecb(); - - assert(8 == EVP_CIPHER_block_size(cipher)); - assert(16 == cipherKeyLength); - break; - - case Q_CIPHER_AES128: - cipher = EVP_aes_128_ecb(); - - assert(16 == EVP_CIPHER_block_size(cipher)); - assert(16 == cipherKeyLength); - break; - - case Q_CIPHER_AES192: - cipher = EVP_aes_192_ecb(); - - assert(16 == EVP_CIPHER_block_size(cipher)); - assert(24 == cipherKeyLength); - break; - - case Q_CIPHER_AES256: - cipher = EVP_aes_256_ecb(); - - assert(16 == EVP_CIPHER_block_size(cipher)); - assert(32 == cipherKeyLength); - break; - - default: - assert(0 && "never reach"); - } - - /* init key-buffer from URL */ - if (cipherType != Q_CIPHER_NULL && cipherType != Q_CIPHER_NONE && - !q_securityResolveCipherKeyFromUri(cipherKeyURL,cipherKeyLength,cipherKey)) { - DDS_ERROR("DDSI Security Decoder: dropping traffic of partition '%s' (%d) due to invalid cipher key", - decoder->partitionName, partitionId); - /* can be solved by re-keying, rewriting the file */ - decoder->state = Q_CODEC_STATE_DROP_TEMP; - } - - EVP_CIPHER_CTX_init(&(decoder->cipherContext)); - - EVP_EncryptInit_ex(&(decoder->cipherContext), - cipher, - NULL, - cipherKey, - iv); /* IV is ignored by ECB ciphers */ - - } - - return TRUE; -} - - -static c_bool q_securityPartitionDecoderFini (q_securityPartitionDecoder decoder) -{ - if (decoder->cipherType != Q_CIPHER_UNDEFINED) { - /* release the cipher */ - EVP_CIPHER_CTX *ctx = NULL; - - ctx = &(decoder->cipherContext); - - EVP_CIPHER_CTX_cleanup(ctx); - } - - return 1; /* true */ -} - -/* returns NULL on error */ - -static q_securityEncoderSet q_securityEncoderSetNew (void) -{ - const os_uint32 nofPartitions = config.nof_networkPartitions; - - q_securityEncoderSet result = - ddsrt_malloc(sizeof(C_STRUCT(q_securityEncoderSet))); - - if (!result) { - return NULL; - } - - result->nofPartitions = 0; /* init */ - result->headerSizeMax = 0; - if (nofPartitions == 0) { - result->encoders = NULL; - } else { - result->encoders = ddsrt_malloc(sizeof(C_STRUCT(q_securityPartitionEncoder)) * nofPartitions); - memset(result->encoders, - 0, - sizeof(C_STRUCT(q_securityPartitionEncoder)) * - nofPartitions); - } - - /* if not done yet, init the RNG within this thread*/ - if(!RAND_status()) { - q_securityRNGSeed(); - } - - /* init each codec per network parition */ - { - q_securityPartitionEncoder currentEncoder = NULL; - os_uint32 headerSizeProfile = 0; - - struct config_networkpartition_listelem *p = config.networkPartitions; - - while (p) { - - currentEncoder = - &(result->encoders[p->partitionId-1]); - - if (p->securityProfile) { - if (!q_securityPartitionEncoderInit(currentEncoder,p)) { - /* the codec config is faulty, the codec has been set into - * DROP_TERMP or DROP_PERM state, depending on the kind of - * fault. Continue to intitialize remaining codecs */ - DDS_ERROR("q_securityEncoderSet:failed to initialize codec of partition '%s' (%d)\n", - p->name,p->partitionId ); - } - - DDS_TRACE("Network Partition '%s' (%d) encoder secured by %s cipher, in status '%s'\n", - p->name, - p->partitionId, - cipherTypeAsString(currentEncoder->cipherType), - stateAsString(currentEncoder->state)); - - headerSizeProfile = cipherTypeToHeaderSize(currentEncoder->cipherType); - result->headerSizeMax = (headerSizeProfile > (result->headerSizeMax)) ? headerSizeProfile: (result->headerSizeMax); - result->headerSizeMax = (result->headerSizeMax + 4u) & ~4u; /* enforce mutiple of 4 */ - } else { - memset(currentEncoder, 0, sizeof(*currentEncoder)); - currentEncoder->state = Q_CODEC_STATE_DROP_PERM; - currentEncoder->cipherType = Q_CIPHER_NONE; - currentEncoder->partitionName = p->name; - - DDS_TRACE("Network Partition '%s' (%d) is not secured by a cipher\n", - p->name, - p->partitionId); - } - /* count up step by step, so in case of error - * q_securityEncoderSetFree will only iterate those already - * intialized */ - ++(result->nofPartitions); - p = p->next; - - } - - - DDS_TRACE("reserving %d bytes for security header\n", result->headerSizeMax); - } - - return result; -} - -/* returns NULL on error */ - -static q_securityDecoderSet q_securityDecoderSetNew (void) -{ - q_securityDecoderSet result; - const os_uint32 nofPartitions = config.nof_networkPartitions; - - if (nofPartitions == 0) - { - return NULL; - } - - result = ddsrt_malloc (sizeof(C_STRUCT(q_securityDecoderSet))); - result->nofPartitions = 0; - - result->decoders = - ddsrt_malloc(sizeof(C_STRUCT(q_securityPartitionDecoder)) * nofPartitions); - - /* init the memory region */ - memset(result->decoders, - 0, - sizeof(C_STRUCT(q_securityPartitionDecoder)) * - nofPartitions); - - /* if not done yet, init the RNG within this thread*/ - if(!RAND_status()) { - q_securityRNGSeed(); - } - - /* init codec per network partition */ - { - q_securityPartitionDecoder currentDecoder = NULL; - - struct config_networkpartition_listelem *p = config.networkPartitions; - - while (p) { - currentDecoder = - &(result->decoders[p->partitionId-1]); - if ( p->securityProfile ) { - if (!q_securityPartitionDecoderInit(currentDecoder,p)) { - /* the codec config is faulty, the codec has been set into - * DROP_TERMP or DROP_PERM state, depending on the kind of - * fault. Continue to intitialize remaining codecs */ - DDS_ERROR("q_securityDecoderSet:failed to initialize codec of partition '%s' (%d)\n", - p->name,p->partitionId); - } - - DDS_TRACE("Network Partition '%s' (%d) decoder secured by %s cipher, in status '%s'\n", - p->name, - p->partitionId, - cipherTypeAsString(currentDecoder->cipherType), - stateAsString(currentDecoder->state)); - } else { - memset(currentDecoder, 0, sizeof(*currentDecoder)); - currentDecoder->state = Q_CODEC_STATE_DROP_PERM; - currentDecoder->cipherType = Q_CIPHER_NONE; - currentDecoder->partitionName = p->name; - - DDS_TRACE("Network Partition '%s' (%d) is not secured by a cipher\n", - p->name, - p->partitionId); - } - /* count up step by step, so in case of error - * q_securityEncoderSetFree will only iterate those already - * intialized */ - ++(result->nofPartitions); - p = p->next; - } - } - - return result; - -} - -static c_bool q_securityEncoderSetFree (q_securityEncoderSet codec) -{ - q_securityPartitionEncoder currentEncoder = NULL; - os_uint32 ix; - - if (!codec) { - /* parameter is NULL */ - return TRUE; - } - - for (ix=0; ixnofPartitions; ++ix) { - currentEncoder = - &(codec->encoders[ix]); - - q_securityPartitionEncoderFini(currentEncoder); - } - ddsrt_free(codec->encoders); - ddsrt_free(codec); - - return 1; /* true */ -} - -static c_bool q_securityDecoderSetFree (q_securityDecoderSet codec) -{ - q_securityPartitionDecoder currentDecoder = NULL; - os_uint32 ix; - - if (!codec) { - /* parameter is NULL */ - return TRUE; - } - - for (ix=0; ixnofPartitions; ++ix) { - currentDecoder = - &(codec->decoders[ix]); - - q_securityPartitionDecoderFini(currentDecoder); - } - ddsrt_free(codec->decoders); - ddsrt_free(codec); - - return TRUE; /* true */ -} - -static os_uint32 q_securityEncoderHeaderSize (q_securityEncoderSet codec, os_uint32 partitionId) -{ - assert(partitionId > 0); - if (!codec) { - /* security not initialized or disabled */ - return 0; - } - assert(partitionId <= codec->nofPartitions); - return cipherTypeToHeaderSize(codec->encoders[partitionId-1].cipherType); -} - -static q_cipherType q_securityEncoderCipherType (q_securityEncoderSet codec, os_uint32 partitionId) -{ - assert(partitionId > 0); - if (!codec) { - /* security not initialized or disabled */ - return 0; - } - assert(partitionId <= codec->nofPartitions); - return codec->encoders[partitionId-1].cipherType; -} - - - -/* returns 0 on error, otherwise 1, */ -static c_bool counterEncryptOrDecryptInPlace -( - EVP_CIPHER_CTX *ctx, - unsigned char *counter, /* in/out */ - unsigned char *buffer, - int length -) -{ - int i, j, num; - int where = 0; - int bl = EVP_CIPHER_CTX_block_size(ctx); - unsigned char keyStream[Q_BLOCK_SIZE_MAX]; - - /* <= is correct, so that we handle any possible non-aligned data */ - for (i = 0; i <= length / bl && where < length; ++i) { - /* encrypt the current counter */ - if (!EVP_EncryptUpdate(ctx, keyStream, &num, counter, bl)) { /* ECB encrypts exactly 'bl' bytes */ - - DDS_WARNING("Incoming encrypted sub-message dropped: Decrypt failed (bufferLength %u, blockSize %u, where %u)\n",length, bl, where); - - return FALSE; - } - - /* use the keystream to encrypt a single block of buffer */ - { - if ( ((int) (length - where)) < bl) { - /* non aligned data, encrypt remaining block-fragment only */ - for (j = 0; j < ((int) (length - where)); ++j) { - buffer[where+j] ^= keyStream[j]; - } - } else { - /* default case, encrypt full block */ - for (j = 0; j < bl; ++j) { - buffer[where+j] ^= keyStream[j]; - } - } - } - - /* increment the counter, remember it's an array of single characters */ - for (j = Q_KEYID_LENGTH; j < bl; ++j) { /*the four first bytes=random value. It is kept unchanged */ - if (++(counter[j])) - break; - } - - where += num; - } - - return TRUE; -} - - -static void -attachHeaderAndDoSha1(unsigned char* data, os_uint32 dataLength, - const void *symCipherHeader, os_uint32 symCipherHeaderLength) -{ - const os_uint32 sha1HeaderLength = sizeof(C_STRUCT(q_sha1Header)); - const os_uint32 overallLength = dataLength + - sha1HeaderLength + - symCipherHeaderLength; - - unsigned char md[Q_DIGEST_LENGTH]; - - /* put the fixed attributes into buffer to calculate the digest */ - void *digStart = &(data[dataLength]); - void *cipStart = &(data[dataLength + sha1HeaderLength]); - - memset(digStart, 0, sha1HeaderLength); /* zero out */ - memcpy(cipStart, symCipherHeader, symCipherHeaderLength); - - /* calculate over complete send buffer */ - Q_SHA1(data, overallLength, md); - - /* Finally place the (half of) digest */ - memcpy(digStart, md, Q_DIGEST_LENGTH_2); -} - -static void -attachHeader(unsigned char* data, os_uint32 dataLength, - const void *symCipherHeader, os_uint32 symCipherHeaderLength) -{ - /* pur the fixed attributes into buffer to calculate the digest */ - void *cipStart = &(data[dataLength]); - memcpy(cipStart, symCipherHeader, symCipherHeaderLength); -} - -static c_bool -verifySha1(unsigned char* data, os_uint32 dataLength, void *digStart) -{ - const os_uint32 sha1HeaderLength = sizeof(C_STRUCT(q_sha1Header)); - C_STRUCT(q_sha1Header) sha1Header; - unsigned char md[Q_DIGEST_LENGTH]; - - /* backup the sha1 digest */ - memcpy(&sha1Header, digStart, sha1HeaderLength); - - /* zero out the bytes in buffer */ - memset(digStart, 0, sha1HeaderLength); - - /* verify digest */ - Q_SHA1(data, dataLength, md); - - return !memcmp(md, sha1Header.hash, Q_DIGEST_LENGTH_2); -} - -static c_bool q_securityEncodeInPlace_Generic -( - q_securityPartitionEncoder encoder, - os_uint32 partitionId, /* debugging */ - unsigned char *buffer, - os_uint32 *dataLength, /* in/out */ - os_uint32 bufferLength /* for debug */ -) -{ - const os_uint32 overallHeaderSize = cipherTypeToHeaderSize(encoder->cipherType); - - EVP_CIPHER_CTX *ctx = &(encoder->cipherContext); - unsigned char *plainText = buffer; - os_uint32 plainTextLength = *dataLength; - c_bool result = TRUE; - - - TRACE((":ENCRYPT:'%s'(%d)",encoder->partitionName, partitionId)); - - (void) bufferLength; - - switch (encoder->cipherType) { - case Q_CIPHER_NULL: { - const os_uint32 symCipherHeaderLength = sizeof(C_STRUCT(q_nullHeader)); - - q_nullHeader symCipherHeader = &((encoder->securityHeader).u.null); - - DUMP_BUFFER(encoder->partitionName, partitionId, buffer, *dataLength, "encode->", - NULL, Q_NULL_COUNTER_SIZE, bufferLength); - - attachHeader(plainText, plainTextLength, - symCipherHeader, symCipherHeaderLength); - - TRACE((":NULL:%s", result?"OK":"ERROR")); /* debug */ - - DUMP_BUFFER(encoder->partitionName, partitionId, buffer, *dataLength+overallHeaderSize, "<-encode", NULL, - Q_NULL_COUNTER_SIZE, bufferLength); - } - break; - - case Q_CIPHER_BLOWFISH: { - const os_uint32 symCipherHeaderLength = sizeof(C_STRUCT(q_blowfishHeader)); - q_blowfishHeader symCipherHeader = &((encoder->securityHeader).u.blowfish); - unsigned char *counter = symCipherHeader->counter; - - DUMP_BUFFER(encoder->partitionName, partitionId, buffer, *dataLength, "encode->", counter, - Q_BLOWFISH_COUNTER_SIZE, bufferLength); - - attachHeaderAndDoSha1(plainText, plainTextLength, - symCipherHeader, symCipherHeaderLength); - - /* encrypt load and digest */ - result = counterEncryptOrDecryptInPlace(ctx, - counter, - plainText, - (int) (plainTextLength + sizeof(C_STRUCT(q_sha1Header)))); - - TRACE((":BLF:%s", result?"OK":"ERROR")); /* debug */ - - DUMP_BUFFER(encoder->partitionName, partitionId, buffer, *dataLength+overallHeaderSize, "<-encode", counter, - Q_BLOWFISH_COUNTER_SIZE, bufferLength); - } - break; - - case Q_CIPHER_AES128: - case Q_CIPHER_AES192: - case Q_CIPHER_AES256: { - const os_uint32 symCipherHeaderLength = sizeof(C_STRUCT(q_aesHeader)); - q_aesHeader symCipherHeader = &((encoder->securityHeader).u.aes); - unsigned char *counter = symCipherHeader->counter; - - DUMP_BUFFER(encoder->partitionName, partitionId, buffer, *dataLength, "encode->", counter, - Q_AES_COUNTER_SIZE, bufferLength); - - attachHeaderAndDoSha1(plainText, plainTextLength, - symCipherHeader, symCipherHeaderLength); - - /* encrypt load and digest */ - result = counterEncryptOrDecryptInPlace(ctx, - counter, - plainText, - (int) (plainTextLength + sizeof(C_STRUCT(q_sha1Header)))); - - TRACE((":AES:%s", result?"OK":"ERROR")); /* debug */ - - DUMP_BUFFER(encoder->partitionName, partitionId, buffer, *dataLength+overallHeaderSize, "<-encode", counter, - Q_AES_COUNTER_SIZE, bufferLength); - } - break; - default: - assert(0 && "do not reach"); - } - TRACE((":(%d->%d)", *dataLength, *dataLength + overallHeaderSize)); - - *dataLength += overallHeaderSize; - return result; -} - - -static c_bool q_securityDecodeInPlace_Generic -( - q_securityPartitionDecoder decoder, - os_uint32 partitionId, - unsigned char *buffer, - os_uint32 *dataLength, /* in/out */ - q_cipherType sendersCipherType, - os_uint32 bufferLength -) -{ - const os_uint32 overallHeaderSize = cipherTypeToHeaderSize(sendersCipherType); - EVP_CIPHER_CTX *ctx = &(decoder->cipherContext); - c_bool result = TRUE; - - TRACE((":DECRYPT:'%s'(%d)",decoder->partitionName, partitionId)); - - (void) bufferLength; - - switch (sendersCipherType) { - case Q_CIPHER_NULL: - { - DUMP_BUFFER(decoder->partitionName, partitionId, buffer, *dataLength, "decode->", - NULL, - Q_NULL_COUNTER_SIZE, bufferLength); - - /* nothing todo here, just decreasing the buffer length at end of this function */ - TRACE((":NULL:%s", result?"OK":"ERROR")); /* debug */ - - DUMP_BUFFER(decoder->partitionName, partitionId, buffer, *dataLength - overallHeaderSize, "<-decode", - NULL, - Q_NULL_COUNTER_SIZE, bufferLength); - } - break; - - case Q_CIPHER_BLOWFISH: - { - const os_uint32 sha1HeaderLength = sizeof(C_STRUCT(q_sha1Header)); - const os_uint32 cipherTextLength = *dataLength - overallHeaderSize + sha1HeaderLength; - C_STRUCT(q_blowfishHeader) symCipherHeader; - - void *cipherText = buffer; - void *sha1HeaderStart = &(buffer[*dataLength - overallHeaderSize]); - void *symCipherHeaderStart = &(buffer[*dataLength - overallHeaderSize + sha1HeaderLength]); - - /* copy from buffer into aligned memory */ - memcpy(&symCipherHeader, symCipherHeaderStart, sizeof(C_STRUCT(q_blowfishHeader))); - - DUMP_BUFFER(decoder->partitionName, partitionId, buffer, *dataLength, "decode->", symCipherHeader.counter,Q_BLOWFISH_COUNTER_SIZE, bufferLength); - - /* decrypt the load and the digest */ - result = counterEncryptOrDecryptInPlace(ctx, - symCipherHeader.counter, - cipherText, - (int) cipherTextLength); - if (result) { - /* will zero out the sha1Header values in buffer */ - result = verifySha1(cipherText, *dataLength, sha1HeaderStart); - TRACE((":BLF:%s", result?"OK":"ERROR")); /* debug */ - if (!result) { - DDS_WARNING("Incoming encrypted sub-message dropped: Decrypt (blowfish) verification failed for partition '%s' - possible Key-mismatch\n", decoder->partitionName); - } - } - - DUMP_BUFFER(decoder->partitionName, partitionId, buffer, *dataLength - overallHeaderSize, "<-decode",symCipherHeader.counter, Q_BLOWFISH_COUNTER_SIZE, bufferLength); - } - break; - - case Q_CIPHER_AES128: - case Q_CIPHER_AES192: - case Q_CIPHER_AES256: - { - const os_uint32 sha1HeaderLength = sizeof(C_STRUCT(q_sha1Header)); - const os_uint32 cipherTextLength = *dataLength - overallHeaderSize + sha1HeaderLength; - C_STRUCT(q_aesHeader) symCipherHeader; - - void *cipherText = buffer; - void *sha1HeaderStart = &(buffer[*dataLength - overallHeaderSize]); - void *symCipherHeaderStart = &(buffer[*dataLength - overallHeaderSize + sha1HeaderLength]); - - /* copy from buffer into aligned memory */ - memcpy(&symCipherHeader, symCipherHeaderStart, sizeof(C_STRUCT(q_aesHeader))); - - DUMP_BUFFER(decoder->partitionName, partitionId, buffer, *dataLength, "decode->",symCipherHeader.counter, Q_AES_COUNTER_SIZE, bufferLength); - - /* decrypt the load and the digest */ - result = counterEncryptOrDecryptInPlace(ctx, - symCipherHeader.counter, - cipherText, - (int) cipherTextLength); - if ( result){ - /* will zero out the sha1Header values in buffer */ - result = verifySha1(cipherText, *dataLength, sha1HeaderStart); - DDS_TRACE(":AES:%s", result?"OK":"ERROR"); /* debug */ - if (!result) { - DDS_WARNING("Incoming encrypted sub-message dropped: Decrypt (AES) verification failed for partition '%s' - possible Key-mismatch", decoder->partitionName); - } - } - - DUMP_BUFFER(decoder->partitionName, partitionId, buffer, *dataLength - overallHeaderSize, "<-decode", symCipherHeader.counter, Q_AES_COUNTER_SIZE, bufferLength); - } - break; - default: - assert(0 && "do not reach"); - } - - DDS_TRACE(":(%d->%d)", *dataLength, *dataLength - overallHeaderSize); - - *dataLength -= overallHeaderSize; /* out */ - - return result; -} - - - -/* returns 0 on error, otherwise 1, - @param codec the security context object - @param partitionId defines the security policy to be used - @param buffer with content, with reserved space at end - @param fragmentLength overall length of buffer - @param dataLength the occupied space of buffer, must leave enough space for security attribute header */ - -static c_bool q_securityEncodeInPlace -( - q_securityEncoderSet codec, - os_uint32 partitionId, - void *buffer, - os_uint32 fragmentLength, - os_uint32 *dataLength /* in/out */ -) -{ - q_securityPartitionEncoder encoder = NULL; - os_uint32 overallHeaderSize; - c_bool result = FALSE; - - assert(codec); - - - if (partitionId == 0 || partitionId > codec->nofPartitions) { - /* if partitionId is larger than number of partitions, network service - * seems to be in undefined state */ - DDS_ERROR("q_securityEncodeInPlace:Sending message blocked, bad partitionid '%d'\n", - partitionId); - return FALSE; - } - - encoder = &(codec->encoders[partitionId-1]); - - - if (encoderIsBlocked(encoder)) { - DDS_ERROR("q_securityEncodeInPlace:Sending message blocked, encoder of partitionid '%d' in bad state\n", - partitionId); - return FALSE; - } - - if (*dataLength <= 0) { - DDS_WARNING("q_securityEncodeInPlace:encoder called with empty buffer\n"); - return FALSE; - } - - overallHeaderSize = cipherTypeToHeaderSize(encoder->cipherType); - - if (*dataLength + overallHeaderSize > fragmentLength) { - DDS_ERROR("q_securityEncodeInPlace:sending message of %"PA_PRIu32" bytes overlaps with reserved space of %"PA_PRIu32" bytes\n", - *dataLength, overallHeaderSize); - return FALSE; - } - - assert(sizeof(os_uint32) == sizeof(os_uint32)); - - /* do the encoding now */ - result = q_securityEncodeInPlace_Generic(encoder, partitionId, buffer, dataLength, fragmentLength); - - return result; -} - -static c_bool q_securityGetHashFromCipherText -( - unsigned char* buffer, - os_uint32 dataLength, - os_uint32 *hash, - q_cipherType *sendersCipherType -) -{ - C_STRUCT(q_nullHeader) header; - - const os_uint32 headerSize = sizeof(C_STRUCT(q_nullHeader)); - - unsigned char* end = NULL; - - assert(dataLength >= headerSize); - assert(sizeof(os_uint32) == sizeof(os_uint32)); - - end = &(buffer[dataLength - headerSize]); - - memcpy(&header, end, headerSize); - *hash = ntohl(header.partitionId); - *sendersCipherType = ntohl(header.cipherType); - return TRUE; -} - -/* returns 0 on error, otherwise 1, - @param codec the security context object - @param buffer containing the ciphertext - @param fragmentLength overall length of buffer - @param dataLength the occupied space within buffer, on return it contains the length of plaintext in buffer */ -static c_bool q_securityDecodeInPlace -( - q_securityDecoderSet codec, - void *buffer, - size_t fragmentLength, - size_t *dataLength /* in/out */ -) -{ - q_securityPartitionDecoder decoder = NULL; - c_bool result = FALSE; - os_uint32 hash; - os_uint32 partitionId = 0; - os_uint32 dataLength32 = (os_uint32) *dataLength; - os_uint32 overallHeaderSize; - q_cipherType sendersCipherType; - struct config_networkpartition_listelem *p = config.networkPartitions; - - assert(codec); - - q_securityGetHashFromCipherText(buffer,dataLength32,&hash,&sendersCipherType); - - /* lookup hash in config to determine partitionId */ - while(p && ! partitionId) { - if (p->partitionHash == hash) partitionId = p->partitionId; - p = p->next; - } - - if ((partitionId < 1) || (partitionId > codec->nofPartitions)) { - DDS_WARNING("Incoming encrypted sub-message dropped, bad partition hash '%u'\n", hash); - return FALSE; - } - - decoder = &(codec->decoders[partitionId-1]); - - overallHeaderSize = cipherTypeToHeaderSize(sendersCipherType); - - if (sendersCipherType!=decoder->cipherType) { - DDS_WARNING("Incoming encrypted sub-message dropped: cipherType mismatch (%d != %d) for partition '%s'\n", sendersCipherType,decoder->cipherType, decoder->partitionName); - return FALSE; - } - if (decoderIsBlocked(decoder)) { - DDS_WARNING("Incoming encrypted sub-message dropped: decoder is blocked for partition '%s'\n", decoder->partitionName); - return FALSE; - } - - if (overallHeaderSize > dataLength32) { - DDS_WARNING("Incoming encrypted sub-message dropped: submessage too small(%"PA_PRIu32" bytes),for partition '%s'\n", dataLength32, decoder->partitionName); - return FALSE; - } - - result = q_securityDecodeInPlace_Generic(decoder, partitionId, buffer, &dataLength32, sendersCipherType, (os_uint32) fragmentLength); - *dataLength = dataLength32; - - return result; -} - -/* - * Substitute for the sendmsg call that send the message encrypted: - * iov[0] contains the RTPS header and is not encrypted - * iov[1] contains the security header and is also not encrypted - * iov[2..n] are concatenated into one buffer - * Buffer is encrypted and will be the new third iov. - * The size of the encrypted data is set in the second iov as the "octets to next message" - * - */ - -static os_ssize_t q_security_sendmsg -( - ddsi_tran_conn_t conn, - const nn_locator_t *dst, - size_t niov, os_iovec_t *iov, - q_securityEncoderSet *codec, - os_uint32 encoderId, - os_uint32 flags -) -{ - char stbuf[2048], *buf; - size_t sz, data_size; - uint32_t sz32, data_size32; - ssize_t ret = DDS_RETCODE_ERROR; - PT_InfoContainer_t * securityHeader; - - assert (niov > 2); - securityHeader = iov[1].iov_base; - /* first determine the size of the message, then select the - on-stack buffer or allocate one on the heap ... */ - sz = q_securityEncoderSetHeaderSize (*codec); /* reserve appropriate headersize */ - for (uint32_t i = 2; i < niov; i++) - { - sz += iov[i].iov_len; - } - if (sz <= sizeof (stbuf)) - { - buf = stbuf; - } - else - { - buf = ddsrt_malloc (sz); - } - /* ... then copy data into buffer */ - data_size = 0; - for (uint32_t i = 2; i < niov; i++) - { - memcpy (buf + data_size, iov[i].iov_base, iov[i].iov_len); - data_size += iov[i].iov_len; - } - sz = data_size + q_securityEncoderSetHeaderSize (*codec); - assert(sz <= UINT32_MAX); - sz32 = (uint32_t) sz; - data_size32 = (uint32_t) data_size; - - /* Encrypt the buf in place with the given encoder */ - - if (q_securityEncodeInPlace (*codec, encoderId, buf, sz32, &data_size32)) - { - os_size_t nbytes; - /* replace encrypted buffer into iov */ - - iov[2].iov_base = buf; - iov[2].iov_len = data_size; - niov = 3; - /* correct size in security header */ - securityHeader->smhdr.octetsToNextHeader = (unsigned short) (data_size + 4); - - /* send the encrypted data to the connection */ - - nbytes = message->msg_iov[0].iov_len + message->msg_iov[1].iov_len + message->msg_iov[2].iov_len; - if (!gv.mute) - ret = ddsi_conn_write (conn, dst, niov, iov, flags); - else - { - TRACE (("(dropped)")); - ret = (ssize_t) (iov[0].iov_len + iov[1].iov_len + iov[2].iov_len); - } - } - - if (buf != stbuf) - { - ddsrt_free (buf); - } - return ret; -} - -void ddsi_security_plugin (void) -{ - q_security_plugin.encode = q_securityEncodeInPlace; - q_security_plugin.decode = q_securityDecodeInPlace; - q_security_plugin.new_encoder = q_securityEncoderSetNew; - q_security_plugin.new_decoder = q_securityDecoderSetNew; - q_security_plugin.free_encoder = q_securityEncoderSetFree; - q_security_plugin.free_decoder = q_securityDecoderSetFree; - q_security_plugin.send_encoded = q_security_sendmsg; - q_security_plugin.cipher_type = cipherTypeAsString; - q_security_plugin.cipher_type_from_string = q_securityCipherTypeFromString; - q_security_plugin.header_size = q_securityEncoderHeaderSize; - q_security_plugin.encoder_type = q_securityEncoderCipherType; - q_security_plugin.valid_uri = q_securityIsValidCipherKeyUri; -} - -#else - -int ddsi_dummy_val = 0; - -#endif /* DDSI_INCLUDE_ENCRYPTION */ diff --git a/src/core/ddsi/src/q_xmsg.c b/src/core/ddsi/src/q_xmsg.c index e9ec8e6..61be691 100644 --- a/src/core/ddsi/src/q_xmsg.c +++ b/src/core/ddsi/src/q_xmsg.c @@ -223,13 +223,6 @@ struct nn_xpack #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS uint32_t encoderId; #endif /* DDSI_INCLUDE_NETWORK_PARTITIONS */ - -#ifdef DDSI_INCLUDE_ENCRYPTION - /* each partion is associated with a SecurityPolicy, this codecset will serve */ - /* all of them, different cipher for each partition */ - q_securityEncoderSet codec; - PT_InfoContainer_t SecurityHeader; -#endif /* DDSI_INCLUDE_ENCRYPTION */ }; static size_t align4u (size_t x) @@ -1001,16 +994,6 @@ struct nn_xpack * nn_xpack_new (ddsi_tran_conn_t conn, uint32_t bw_limit, bool a if (xp->gv->thread_pool) ddsi_sem_init (&xp->sem, 0); -#ifdef DDSI_INCLUDE_ENCRYPTION - if (q_security_plugin.new_encoder) - { - xp->codec = (q_security_plugin.new_encoder) (); - xp->SecurityHeader.smhdr.submessageId = SMID_PT_INFO_CONTAINER; - xp->SecurityHeader.smhdr.flags = (DDSRT_LITTLE_ENDIAN ? SMFLAG_ENDIANNESS : 0); - xp->SecurityHeader.smhdr.octetsToNextHeader = 4; - xp->SecurityHeader.id = PTINFO_ID_ENCRYPT; - } -#endif #ifdef DDSI_INCLUDE_BANDWIDTH_LIMITING nn_bw_limit_init (&xp->limiter, bw_limit); #else @@ -1023,12 +1006,6 @@ void nn_xpack_free (struct nn_xpack *xp) { assert (xp->niov == 0); assert (xp->included_msgs.latest == NULL); -#ifdef DDSI_INCLUDE_ENCRYPTION - if (q_security_plugin.free_encoder) - { - (q_security_plugin.free_encoder) (xp->codec); - } -#endif if (xp->gv->thread_pool) ddsi_sem_destroy (&xp->sem); ddsrt_free (xp->iov); @@ -1059,34 +1036,23 @@ static ssize_t nn_xpack_send1 (const nn_locator_t *loc, void * varg) } } -#ifdef DDSI_INCLUDE_ENCRYPTION - if (q_security_plugin.send_encoded && xp->encoderId != 0 && (q_security_plugin.encoder_type) (xp->codec, xp->encoderId) != Q_CIPHER_NONE) + if (!gv->mute) { - struct iovec iov[NN_XMSG_MAX_MESSAGE_IOVECS]; - memcpy (iov, xp->iov, sizeof (iov)); - nbytes = (q_security_plugin.send_encoded) (xp->conn, loc, xp->niov, iov, &xp->codec, xp->encoderId, xp->call_flags); + nbytes = ddsi_conn_write (xp->conn, loc, xp->niov, xp->iov, xp->call_flags); +#ifndef NDEBUG + { + size_t i, len; + for (i = 0, len = 0; i < xp->niov; i++) { + len += xp->iov[i].iov_len; + } + assert (nbytes == -1 || (size_t) nbytes == len); + } +#endif } else -#endif { - if (!gv->mute) - { - nbytes = ddsi_conn_write (xp->conn, loc, xp->niov, xp->iov, xp->call_flags); -#ifndef NDEBUG - { - size_t i, len; - for (i = 0, len = 0; i < xp->niov; i++) { - len += xp->iov[i].iov_len; - } - assert (nbytes == -1 || (size_t) nbytes == len); - } -#endif - } - else - { - GVTRACE ("(dropped)"); - nbytes = (ssize_t) xp->msg_len.length; - } + GVTRACE ("(dropped)"); + nbytes = (ssize_t) xp->msg_len.length; } /* Clear call flags, as used on a per call basis */ @@ -1352,16 +1318,6 @@ static int nn_xpack_mayaddmsg (const struct nn_xpack *xp, const struct nn_xmsg * payload_size = m->refd_payload ? (unsigned) m->refd_payload_iov.iov_len : 0; -#ifdef DDSI_INCLUDE_ENCRYPTION - if (xp->encoderId) - { - unsigned security_header; - security_header = (q_security_plugin.header_size) (xp->codec, xp->encoderId); - assert (security_header < max_msg_size); - max_msg_size -= security_header; - } -#endif - /* Check if max message size exceeded */ if (xp->msg_len.length + m->sz + payload_size > max_msg_size) @@ -1477,17 +1433,6 @@ int nn_xpack_addmsg (struct nn_xpack *xp, struct nn_xmsg *m, const uint32_t flag #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS xp->encoderId = m->encoderid; -#endif -#ifdef DDSI_INCLUDE_ENCRYPTION - if (xp->encoderId > 0 && (q_security_plugin.encoder_type) (xp->codec, xp->encoderId) != Q_CIPHER_NONE) - { - /* Insert a reference to the security header - the correct size will be set upon encryption in q_xpack_sendmsg_encoded */ - xp->iov[niov].iov_base = (void*) &xp->SecurityHeader; - xp->iov[niov].iov_len = sizeof (xp->SecurityHeader); - sz += xp->iov[niov].iov_len; - niov++; - } #endif xp->last_src = &xp->hdr.guid_prefix; xp->last_dst = NULL;