diff --git a/src/core/ddsc/src/dds_topic.c b/src/core/ddsc/src/dds_topic.c index d85eb91..743e9b9 100644 --- a/src/core/ddsc/src/dds_topic.c +++ b/src/core/ddsc/src/dds_topic.c @@ -32,6 +32,7 @@ #include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/ddsi_cdrstream.h" +#include "dds/ddsi/ddsi_security_omg.h" #include "dds__serdata_builtintopic.h" DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_topic) @@ -317,10 +318,12 @@ dds_entity_t dds_create_topic_impl (dds_entity_t participant, struct ddsi_sertop * reliable ... (and keep behaviour unchanged) */ struct ddsi_domaingv * const gv = &pp->m_entity.m_domain->gv; if ((rc = ddsi_xqos_valid (&gv->logconfig, new_qos)) != DDS_RETCODE_OK) + goto error; + + if (!q_omg_security_check_create_topic (&pp->m_entity.m_domain->gv, &pp->m_entity.m_guid, sertopic->name, new_qos)) { - dds_delete_qos (new_qos); - dds_entity_unpin (&pp->m_entity); - return rc; + rc = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; + goto error; } /* See if we're allowed to create the topic; ktp is returned pinned & locked @@ -333,9 +336,8 @@ dds_entity_t dds_create_topic_impl (dds_entity_t participant, struct ddsi_sertop if ((rc = lookup_and_check_ktopic (&ktp, pp, sertopic->name, sertopic->type_name, new_qos)) != DDS_RETCODE_OK) { GVTRACE ("dds_create_topic_arbitrary: failed after compatibility check: %s\n", dds_strretcode (rc)); - dds_participant_unlock (pp); - dds_delete_qos (new_qos); - return rc; + ddsrt_mutex_unlock (&pp->m_entity.m_mutex); + goto error; } /* Create a ktopic if it doesn't exist yet, else reference existing one and delete the @@ -378,6 +380,11 @@ dds_entity_t dds_create_topic_impl (dds_entity_t participant, struct ddsi_sertop dds_participant_unlock (pp); GVTRACE ("dds_create_topic_arbitrary: new topic %"PRId32"\n", hdl); return hdl; + + error: + dds_entity_unpin (&pp->m_entity); + dds_delete_qos (new_qos); + return rc; } dds_entity_t dds_create_topic_arbitrary (dds_entity_t participant, struct ddsi_sertopic *sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist) diff --git a/src/core/ddsi/CMakeLists.txt b/src/core/ddsi/CMakeLists.txt index ddd07fd..4c466bd 100644 --- a/src/core/ddsi/CMakeLists.txt +++ b/src/core/ddsi/CMakeLists.txt @@ -18,6 +18,7 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src" ddsi_raweth.c ddsi_ipaddr.c ddsi_mcgroup.c + ddsi_security_util.c ddsi_security_omg.c ddsi_portmapping.c ddsi_handshake.c @@ -83,6 +84,7 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi" ddsi_ipaddr.h ddsi_mcgroup.h ddsi_plist_generic.h + ddsi_security_util.h ddsi_security_omg.h ddsi_portmapping.h ddsi_handshake.h @@ -148,10 +150,12 @@ target_sources(ddsc if(ENABLE_SECURITY) PREPEND(security_srcs "${CMAKE_CURRENT_LIST_DIR}/src" - ddsi_security_msg.c) + ddsi_security_msg.c + ddsi_security_exchange.c) PREPEND(security_hdrs "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi" - ddsi_security_msg.h) + ddsi_security_msg.h + ddsi_security_exchange.h) target_sources(ddsc PRIVATE ${security_srcs} ${security_hdrs}) diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_domaingv.h b/src/core/ddsi/include/dds/ddsi/ddsi_domaingv.h index 17fc797..f7227bd 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_domaingv.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_domaingv.h @@ -47,6 +47,8 @@ struct ddsrt_thread_pool_s; struct debug_monitor; struct ddsi_tkmap; struct dds_security_context; +struct dds_security_match_index; +struct ddsi_hsadmin; typedef struct config_in_addr_node { nn_locator_t loc; @@ -299,7 +301,10 @@ struct ddsi_domaingv { /* security globals */ #ifdef DDSI_INCLUDE_SECURITY struct dds_security_context *security_context; + struct dds_security_match_index *security_matches; + struct ddsi_hsadmin *hsadmin; #endif + }; #if defined (__cplusplus) diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_handshake.h b/src/core/ddsi/include/dds/ddsi/ddsi_handshake.h index 91300d4..f473d0f 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_handshake.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_handshake.h @@ -12,9 +12,7 @@ #ifndef DDSI_HANDSHAKE_H #define DDSI_HANDSHAKE_H -#include "q_unused.h" -#include "q_entity.h" -#include "ddsi_security_msg.h" +#include "dds/ddsi/q_entity.h" #if defined (__cplusplus) extern "C" { @@ -37,10 +35,9 @@ enum ddsi_handshake_state { /* The handshake will not use the related handshake object after this callback * was executed. This means that it can be deleted in this callback. */ typedef void (*ddsi_handshake_end_cb_t)( - struct ddsi_domaingv const * const gv, struct ddsi_handshake *handshake, - const ddsi_guid_t *lpguid, /* Local participant */ - const ddsi_guid_t *ppguid, /* Proxy participant */ + struct participant *pp, + struct proxy_participant *proxypp, enum ddsi_handshake_state result); #ifdef DDSI_INCLUDE_SECURITY @@ -123,7 +120,7 @@ int64_t ddsi_handshake_get_handle(const struct ddsi_handshake *handshake); * @param[in] callback The callback function. * */ -void ddsi_handshake_register(const struct participant *pp, const struct proxy_participant *proxypp, ddsi_handshake_end_cb_t callback); +void ddsi_handshake_register(struct participant *pp, struct proxy_participant *proxypp, ddsi_handshake_end_cb_t callback); /** * @brief Remove the handshake associated with the specified participants. @@ -137,7 +134,7 @@ void ddsi_handshake_register(const struct participant *pp, const struct proxy_pa * @param[in] handshake The handshake. * */ -void ddsi_handshake_remove(const struct participant *pp, const struct proxy_participant *proxypp, struct ddsi_handshake *handshake); +void ddsi_handshake_remove(struct participant *pp, struct proxy_participant *proxypp, struct ddsi_handshake *handshake); /** * @brief Searches for the handshake associated with the specified participants @@ -150,12 +147,42 @@ void ddsi_handshake_remove(const struct participant *pp, const struct proxy_part * * @returns The handshake */ -struct ddsi_handshake * ddsi_handshake_find(const struct participant *pp, const struct proxy_participant *proxypp); +struct ddsi_handshake * ddsi_handshake_find(struct participant *pp, struct proxy_participant *proxypp); + +/** + * @brief Searches for the handshake associated with the specified participants + * + * This function will search through the handshake administration to find the handshake + * corresponding the to specified local and remote participant. + * + * @param[in] pp The local participant. + * @param[in] proxypp The remote participant. + * + * @returns The handshake + */ +struct ddsi_handshake * ddsi_handshake_find(struct participant *pp, struct proxy_participant *proxypp); + +/** + * @brief Initialize the handshake administration + * + * @param[in] gv The global parameters + */ +void ddsi_handshake_admin_init(struct ddsi_domaingv *gv); + +/** + * @brief Deinitialze the handshake administration. + * + * @param[in] gv The global parameters + */ +void ddsi_handshake_admin_deinit(struct ddsi_domaingv *gv); #else /* DDSI_INCLUDE_SECURITY */ #include "dds/ddsi/q_unused.h" +inline void ddsi_handshake_register(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp), UNUSED_ARG(ddsi_handshake_end_cb_t callback)) +{ +} inline void ddsi_handshake_release(UNUSED_ARG(struct ddsi_handshake *handshake)) { @@ -175,15 +202,11 @@ inline int64_t ddsi_handshake_get_handle(UNUSED_ARG(const struct ddsi_handshake return 0; } -inline void ddsi_handshake_register(UNUSED_ARG(const struct participant *pp), UNUSED_ARG(const struct proxy_participant *proxypp), UNUSED_ARG(ddsi_handshake_end_cb_t callback)) +inline void ddsi_handshake_remove(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp), UNUSED_ARG(struct ddsi_handshake *handshake)) { } -inline void ddsi_handshake_remove(UNUSED_ARG(const struct participant *pp), UNUSED_ARG(const struct proxy_participant *proxypp), UNUSED_ARG(struct ddsi_handshake *handshake)) -{ -} - -inline struct ddsi_handshake * ddsi_handshake_find(UNUSED_ARG(const struct participant *pp), UNUSED_ARG(const struct proxy_participant *proxypp)) +inline struct ddsi_handshake * ddsi_handshake_find(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp)) { return NULL; } diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_plist.h b/src/core/ddsi/include/dds/ddsi/ddsi_plist.h index c6f5a8d..4f8b07f 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_plist.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_plist.h @@ -309,6 +309,7 @@ DDS_EXPORT void ddsi_plist_fini (ddsi_plist_t *ps); DDS_EXPORT void ddsi_plist_fini_mask (ddsi_plist_t *plist, uint64_t pmask, uint64_t qmask); DDS_EXPORT void ddsi_plist_unalias (ddsi_plist_t *plist); DDS_EXPORT void ddsi_plist_addtomsg (struct nn_xmsg *m, const ddsi_plist_t *ps, uint64_t pwanted, uint64_t qwanted); +DDS_EXPORT void ddsi_plist_addtomsg_bo (struct nn_xmsg *m, const ddsi_plist_t *ps, uint64_t pwanted, uint64_t qwanted, bool be); DDS_EXPORT void ddsi_plist_init_default_participant (ddsi_plist_t *plist); DDS_EXPORT void ddsi_plist_delta (uint64_t *pdelta, uint64_t *qdelta, const ddsi_plist_t *x, const ddsi_plist_t *y, uint64_t pmask, uint64_t qmask); DDS_EXPORT void ddsi_plist_log (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const ddsi_plist_t *plist); diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_security_exchange.h b/src/core/ddsi/include/dds/ddsi/ddsi_security_exchange.h new file mode 100644 index 0000000..4495cdf --- /dev/null +++ b/src/core/ddsi/include/dds/ddsi/ddsi_security_exchange.h @@ -0,0 +1,49 @@ +/* + * 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 + */ +#ifndef DDSI_SECURITY_EXCHANGE_H +#define DDSI_SECURITY_EXCHANGE_H + +#ifdef DDSI_INCLUDE_SECURITY + +#if defined (__cplusplus) +extern "C" { +#endif + +#include "dds/ddsi/q_rtps.h" +#include "dds/ddsi/q_radmin.h" +#include "dds/ddsi/q_entity.h" +#include "dds/ddsi/ddsi_security_msg.h" + + +#define GMCLASSID_SECURITY_PARTICIPANT_CRYPTO_TOKENS "dds.sec.participant_crypto_tokens" +#define GMCLASSID_SECURITY_DATAWRITER_CRYPTO_TOKENS "dds.sec.datawriter_crypto_tokens" +#define GMCLASSID_SECURITY_DATAREADER_CRYPTO_TOKENS "dds.sec.datareader_crypto_tokens" + +bool write_auth_handshake_message(const struct participant *pp, const struct proxy_participant *proxypp, nn_dataholderseq_t *mdata, bool request, const nn_message_identity_t *related_message_id); +void handle_auth_handshake_message(const struct receiver_state *rst, ddsi_entityid_t wr_entity_id, nn_wctime_t timestamp, unsigned statusinfo, const void *vdata, size_t len); +void handle_crypto_exchange_message(const struct receiver_state *rst, ddsi_entityid_t wr_entity_id, nn_wctime_t timestamp, unsigned statusinfo, const void *vdata, unsigned len); +void auth_get_serialized_participant_data(struct participant *pp, ddsi_octetseq_t *seq); +bool write_crypto_participant_tokens(const struct participant *pp, const struct proxy_participant *proxypp, const nn_dataholderseq_t *tokens); +bool write_crypto_writer_tokens(const struct writer *wr, const struct proxy_reader *prd, const nn_dataholderseq_t *tokens); +bool write_crypto_reader_tokens(const struct reader *rd, const struct proxy_writer *pwr, const nn_dataholderseq_t *tokens); + +#if defined (__cplusplus) +} +#endif + +#else /* DDSI_INCLUDE_SECURITY */ + +#define volatile_secure_data_filter NULL + +#endif /* DDSI_INCLUDE_SECURITY */ + +#endif /* DDSI_SECURITY_EXCHANGE_H */ diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_security_msg.h b/src/core/ddsi/include/dds/ddsi/ddsi_security_msg.h index a35a43d..072a3eb 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_security_msg.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_security_msg.h @@ -28,8 +28,13 @@ struct writer; struct proxy_reader; struct ddsi_serdata; -#define GMCLASSID_SECURITY_AUTH_REQUEST "dds.sec.auth_request" -#define GMCLASSID_SECURITY_AUTH_HANDSHAKE "dds.sec.auth" +#define DDS_SECURITY_AUTH_REQUEST "dds.sec.auth_request" +#define DDS_SECURITY_AUTH_HANDSHAKE "dds.sec.auth" +#define DDS_SECURITY_AUTH_REQUEST_TOKEN_CLASS_ID "DDS:Auth:PKI-DH:1.0+AuthReq" +#define DDS_SECURITY_AUTH_HANDSHAKE_REQUEST_TOKEN_ID "DDS:Auth:PKI-DH:1.0+Req" +#define DDS_SECURITY_AUTH_HANDSHAKE_REPLY_TOKEN_ID "DDS:Auth:PKI-DH:1.0+Reply" +#define DDS_SECURITY_AUTH_HANDSHAKE_FINAL_TOKEN_ID "DDS:Auth:PKI-DH:1.0+Final" + typedef struct nn_message_identity { ddsi_guid_t source_guid; @@ -91,15 +96,6 @@ nn_participant_generic_message_serialize( DDS_EXPORT extern const enum pserop pserop_participant_generic_message[]; -DDS_EXPORT int -write_crypto_exchange_message( - const struct participant *pp, - const ddsi_guid_t *dst_pguid, - const ddsi_guid_t *src_eguid, - const ddsi_guid_t *dst_eguid, - const char *classid, - const nn_dataholderseq_t *tokens); - DDS_EXPORT int volatile_secure_data_filter( struct writer *wr, diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_security_omg.h b/src/core/ddsi/include/dds/ddsi/ddsi_security_omg.h index d6a36ea..534a762 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_security_omg.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_security_omg.h @@ -12,6 +12,9 @@ #ifndef DDSI_OMG_SECURITY_H #define DDSI_OMG_SECURITY_H +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/avl.h" + #include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/ddsi_domaingv.h" @@ -20,7 +23,11 @@ #include "dds/ddsrt/retcode.h" #include "dds/ddsrt/types.h" #include "dds/ddsrt/sync.h" +#include "dds/ddsi/ddsi_xqos.h" +#ifdef DDSI_INCLUDE_SECURITY +#include "dds/security/dds_security_api.h" +#endif #if defined (__cplusplus) extern "C" { @@ -34,26 +41,123 @@ typedef enum { #ifdef DDSI_INCLUDE_SECURITY -#include "dds/security/dds_security_api.h" -#include "dds/security/core/dds_security_plugins.h" +struct ddsi_hsadmin; +struct participant_sec_attributes; +struct proxy_participant_sec_attributes; +struct writer_sec_attributes; +struct reader_sec_attributes; +struct dds_security_context; typedef struct nn_msg_sec_info { + unsigned encoded:1; + unsigned use_rtps_encoding:1; int64_t src_pp_handle; int64_t dst_pp_handle; - bool use_rtps_encoding; } nn_msg_sec_info_t; +struct guid_pair { + ddsi_guid_t src; + ddsi_guid_t dst; +}; +struct security_entity_match { + ddsrt_avl_node_t avlnode; + struct guid_pair guids; + bool matched; + int64_t crypto_handle; + DDS_Security_ParticipantCryptoTokenSeq *tokens; +}; +struct dds_security_match_index { + ddsrt_mutex_t lock; + ddsrt_avl_tree_t matches; +}; + +struct pp_proxypp_match { + ddsrt_avl_node_t avlnode; + ddsi_guid_t proxypp_guid; + DDS_Security_ParticipantCryptoHandle proxypp_crypto_handle; +}; + +struct proxypp_pp_match { + ddsrt_avl_node_t avlnode; + ddsi_guid_t pp_guid; + DDS_Security_ParticipantCryptoHandle pp_crypto_handle; + DDS_Security_PermissionsHandle permissions_handle; + DDS_Security_SharedSecretHandle shared_secret; +}; + +struct participant_sec_attributes { + ddsrt_avl_node_t avlnode; + ddsi_guid_t pp_guid; + DDS_Security_ParticipantSecurityAttributes attr; + DDS_Security_IdentityHandle local_identity_handle; + DDS_Security_PermissionsHandle permissions_handle; + DDS_Security_ParticipantCryptoHandle crypto_handle; + bool plugin_attr; + ddsrt_mutex_t lock; + ddsrt_avl_ctree_t proxy_participants; + bool initialized; +}; + +struct proxy_participant_sec_attributes { + struct dds_security_context *sc; + DDS_Security_IdentityHandle remote_identity_handle; + DDS_Security_ParticipantCryptoHandle crypto_handle; + ddsrt_mutex_t lock; + ddsrt_avl_tree_t participants; + bool initialized; +}; + +struct writer_sec_attributes { + DDS_Security_EndpointSecurityAttributes attr; + DDS_Security_DatawriterCryptoHandle crypto_handle; + bool plugin_attr; +}; + +struct reader_sec_attributes { + DDS_Security_EndpointSecurityAttributes attr; + DDS_Security_DatareaderCryptoHandle crypto_handle; + bool plugin_attr; +}; + +struct dds_security_authentication *q_omg_participant_get_authentication(const struct participant *pp); + +void q_omg_log_exception(const struct ddsrt_log_cfg *lc, uint32_t cat, DDS_Security_SecurityException *exception, const char *file, uint32_t line, const char *func, const char *fmt, ...); + +/** + * @brief Check if access control is enabled for the participant. + * + * @param[in] pp Participant to check. + * + * @returns bool True if access control is enabled for participant + */ +bool q_omg_participant_is_access_protected(const struct participant *pp); + +/** + * @brief Check if protection at RTPS level is enabled for the participant. + * + * @param[in] pp Participant to check. + * + * @returns bool True if RTPS protection enabled for participant + */ +bool q_omg_participant_is_rtps_protected(const struct participant *pp); + +/** + * @brief Check if liveliness is protected for the participant. + * + * @param[in] pp Participant to check. + * + * @returns bool True if liveliness data for participant is protected + */ +bool q_omg_participant_is_liveliness_protected(const struct participant *pp); /** * @brief Check if security is enabled for the participant. * * @param[in] pp Participant to check if it is secure. * - * @returns bool - * @retval true Participant is secure - * @retval false Participant is not secure + * @returns bool True if participant is secure */ bool q_omg_participant_is_secure(const struct participant *pp); @@ -62,31 +166,150 @@ bool q_omg_participant_is_secure(const struct participant *pp); * * @param[in] proxypp Proxy participant to check if it is secure. * - * @returns bool - * @retval true Proxy participant is secure - * @retval false Proxy participant is not secure + * @returns bool True if proxy participant is secure */ bool q_omg_proxy_participant_is_secure(const struct proxy_participant *proxypp); /** - * @brief Get the security handle of the given local participant. + * @brief Check security if it is allowed to create the participant. + * + * When security is enabled for this participant it is checked if the + * participant is authenticated by checking the provided security + * certificates. When that is ok the participant is registered with + * access control and with cryptography. When that is all successful + * this function return true; + * + * @param[in] pp The participant to check if alloweed by security. + * #param[in] domain_id The domain_id + * + * @returns bool + * @retval true Participant is allowed + * @retval false Participant is not allowed + */ +bool q_omg_security_check_create_participant(struct participant *pp, uint32_t domain_id); + +void q_omg_security_participant_set_initialized(struct participant *pp); + +bool q_omg_security_participant_is_initialized(struct participant *pp); + +/** + * @brief Remove the participant from the security plugins. + * + * When the participant was registered with the security + * plugins then this function will release the allocated + * security resources. + * + * @param[in] pp Participant to remove. + */ +void q_omg_security_deregister_participant(struct participant *pp); + +/** + * @brief Get the identity handle associate with this participant. + * + * This function returns the identity handle that was created + * when the participant was authenticated. This handle corresponds + * with the handle returned by calling validate_local_identity on + * the authentication plugin. * * @param[in] pp Participant to check if it is secure. * * @returns int64_t - * @retval Local participant security handle + * @retval !0 Identity handle associated with the participant. + * @retval 0 Invalid handle the participant was not registered */ -int64_t q_omg_security_get_local_participant_handle(struct participant *pp); +int64_t q_omg_security_get_local_participant_handle(const struct participant *pp); /** - * @brief Get the security handle of the given remote participant. + * @brief Get security info flags of the given participant. * - * @param[in] proxypp Participant to check if it is secure. + * @param[in] pp Participant to get the security info from. + * @param[out] info The security info. * - * @returns int64_t - * @retval Remote participant security handle + * @returns bool + * @retval true Security info set. + * @retval false Security info not set. */ -int64_t q_omg_security_get_remote_participant_handle(struct proxy_participant *proxypp); +bool q_omg_get_participant_security_info(const struct participant *pp, nn_security_info_t *info); + +/** + * @brief Get the is_rtps_protected flag of the given remote participant. + * + * @param[in] pp The participant. + * @param[in] entityid ID of the entity to check. + * + * @returns bool + * @retval true RTPS protected is set. + * @retval false RTPS protected is not set. + */ +bool q_omg_security_is_local_rtps_protected(const struct participant *pp, ddsi_entityid_t entityid); + +/** + * @brief Check if the participant and the proxy participant + * have compatible security info settings. + * + * Associated with a secure participant is the ParticipantSecurityInfo parameter. + * This parameter contains the setting of the security attributes and the associated + * plugin security attributes of the secure participant. + * This function will check if the received ParticipantSecurityInfo parameter is + * compatible with the local ParticipantSecurityInfo parameter. + * + * @param[in] pp The participant. + * @param[in] proxypp The proxy participant. + * + * @returns bool + * @retval true The participant and the proxy participant have compatible + * security info settings. + * @retval false Otherwise. + */ +bool q_omg_is_similar_participant_security_info(struct participant *pp, struct proxy_participant *proxypp); + +/** + * @brief Check if the parameter list key hash is protected + * + * @param[in] plist The parameter list + * + * @returns bool True if the parameter list key hash is protected + */ +bool q_omg_plist_keyhash_is_protected(const ddsi_plist_t *plist); + +/** + * @brief Check if the endpoint is protected + * + * Checks whether the provided parameter list has the flag + * ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID set. When this flag + * is set, this implies that the remote endpoint has protection + * enabled. + * + * @param[in] plist The parameter list + * + * @returns bool True if the endpoint is protected + */ +bool q_omg_is_endpoint_protected(const ddsi_plist_t *plist); + +/** + * @brief Writes the security attributes and security plugin attributes to log (category discovery) + * + * @param[in] gv Global variable + * @param[in] plist The parameter list + */ +void q_omg_log_endpoint_protection(struct ddsi_domaingv * const gv, const ddsi_plist_t *plist); + +/** + * @brief Check if security allows to create the topic. + * + * This function checks with access control if is allowed to create + * this topic for the specified domain. + * + * @param[in] gv The domain global information. + * @param[in] pp_guid The participant guid. + * @param[in] topic_name The name of the topic. + * @param[in] qos The topic QoS used. + * + * @returns bool + * @retval true Creation of the topic is allowed + * @retval false Otherwise. + */ +bool q_omg_security_check_create_topic(const struct ddsi_domaingv *gv, const ddsi_guid_t *pp_guid, const char *topic_name, const struct dds_qos *qos); /** * @brief Get security info flags of the given writer. @@ -100,6 +323,65 @@ int64_t q_omg_security_get_remote_participant_handle(struct proxy_participant *p */ bool q_omg_get_writer_security_info(const struct writer *wr, nn_security_info_t *info); +/** + * @brief Return the builtin writer id for this writers' discovery. + * + * Return builtin entity id of the writer to use for the publication + * discovery information. + * Depending on whether the discovery is protected or not (for the + * given writer), either the default writer or protected writer needs + * to be used. + * + * @param[in] wr Writer to determine the publication writer from. + * + * @returns unsigned + * @retval NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER + * @retval NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER + */ +unsigned determine_publication_writer(const struct writer *wr); + +/** + * @brief Check if security allows to create the writer. + * + * This function checks with access control if is allowed to create + * this writer for the specified domain. + * + * @param[in] pp Participant on which the topic is being created. + * @param[in] domain_id The corresponding domain_id. + * @param[in] topic_name The name of the topic. + * @param[in] writer_qos The writer QoS used. + * + * @returns bool + * @retval true Creation of the writer is allowed + * @retval false Otherwise. + */ +bool q_omg_security_check_create_writer(struct participant *pp, uint32_t domain_id, const char *topic_name, const struct dds_qos *writer_qos); + +/** + * @brief Register the writer with security. + * + * This function registers the writer with security + * when the associated participant has security enabled. + * The security settings associated with this writer are determined + * and the writer is registered with cryptography when needed by + * the security settings which indicate if payload protection and or + * submessage protection is enabled for this writer. + * + * @param[in] wr The writer to register. + */ +void q_omg_security_register_writer(struct writer *wr); + +/** + * @brief Remove the writer from security. + * + * When the writer was registered with security then this function + * will remove the writer from security which will free the allocated + * security resource created for this writer. + * + * @param[in] wr The writer to remove. + */ +void q_omg_security_deregister_writer(struct writer *wr); + /** * @brief Get security info flags of the given reader. * @@ -128,23 +410,47 @@ bool q_omg_get_reader_security_info(const struct reader *rd, nn_security_info_t * @retval NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER */ unsigned determine_subscription_writer(const struct reader *rd); +/** + * @brief Check if security allows to create the reader. + * + * This function checks with access control if is allowed to create + * this reader for the specified domain. + * + * @param[in] pp Participant on which the topic is being created. + * @param[in] domain_id The corresponding domain_id. + * @param[in] topic_name The name of the topic. + * @param[in] reader_qos The reader QoS used. + * + * @returns bool + * @retval true Creation of the writer is allowed + * @retval false Otherwise. + */ +bool q_omg_security_check_create_reader(struct participant *pp, uint32_t domain_id, const char *topic_name, const struct dds_qos *reader_qos); /** - * @brief Return the builtin writer id for this writers' discovery. + * @brief Register the reader with security. * - * Return builtin entity id of the writer to use for the publication - * discovery information. - * Depending on whether the discovery is protected or not (for the - * given writer), either the default writer or protected writer needs - * to be used. + * This function registers the reader with security + * when the associated participant has security enabled. + * The security settings associated with this reader are determined + * and the reader is registered with cryptography when needed by + * the security settings which indicate if submessage protection is + * enabled for this reader. * - * @param[in] wr Writer to determine the publication writer from. - * - * @returns unsigned - * @retval NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER - * @retval NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER + * @param[in] rd The reader to register. */ -unsigned determine_publication_writer(const struct writer *wr); +void q_omg_security_register_reader(struct reader *rd); + +/** + * @brief Remove the reader from security. + * + * When the reader was registered with security then this function + * will remove the reader from security which will free the allocated + * security resource created for this reader. + * + * @param[in] rd The reader to remove. + */ +void q_omg_security_deregister_reader(struct reader *rd); /** * @brief Determine if the proxy participant is allowed to be deleted @@ -162,11 +468,7 @@ unsigned determine_publication_writer(const struct writer *wr); * @retval true The proxy participant may be deleted. * @retval false The proxy participant may not be deleted by this writer. */ -bool -is_proxy_participant_deletion_allowed( - struct ddsi_domaingv * const gv, - const struct ddsi_guid *guid, - const ddsi_entityid_t pwr_entityid); +bool is_proxy_participant_deletion_allowed(struct ddsi_domaingv * const gv, const struct ddsi_guid *guid, const ddsi_entityid_t pwr_entityid); /** * @brief Determine if the messages, related to the given remote @@ -179,26 +481,7 @@ is_proxy_participant_deletion_allowed( * @retval true The entity messages are RTPS protected. * @retval false The entity messages are not RTPS protected. */ -bool -q_omg_security_is_remote_rtps_protected( - const struct proxy_participant *proxy_pp, - ddsi_entityid_t entityid); - -/** - * @brief Determine if the messages, related to the given local - * entity, are RTPS protected or not. - * - * @param[in] pp Related participant. - * @param[in] entityid ID of the entity to check. - * - * @returns bool - * @retval true The entity messages are RTPS protected. - * @retval false The entity messages are not RTPS protected. - */ -bool -q_omg_security_is_local_rtps_protected( - const struct participant *pp, - ddsi_entityid_t entityid); +bool q_omg_security_is_remote_rtps_protected(const struct proxy_participant *proxy_pp, ddsi_entityid_t entityid); /** * @brief Set security information, depending on plist, into the given @@ -207,22 +490,120 @@ q_omg_security_is_local_rtps_protected( * @param[in] proxypp Proxy participant to set security info on. * @param[in] plist Paramater list, possibly contains security info. */ -void -set_proxy_participant_security_info( - struct proxy_participant *proxypp, - const ddsi_plist_t *plist); +void set_proxy_participant_security_info(struct proxy_participant *proxypp, const ddsi_plist_t *plist); /** - * @brief Set security information, depending on plist and proxy participant, - * into the given proxy reader. + * @brief Check if the participant and the proxy participant + * have compatible security info settings. * - * @param[in] prd Proxy reader to set security info on. - * @param[in] plist Paramater list, possibly contains security info. + * Associated with a secure participant is the ParticipantSecurityInfo parameter. + * This parameter contains the setting of the security attributes and the associated + * plugin security attributes of the secure participant. + * This function will check if the received ParticipantSecurityInfo parameter is + * compatible with the local ParticipantSecurityInfo parameter. + * + * @param[in] pp The participant. + * @param[in] proxypp The proxy participant. + * + * @returns bool + * @retval true The participant and the proxy participant have compatible + * security info settings. + * @retval false Otherwise. */ -void -set_proxy_reader_security_info( - struct proxy_reader *prd, - const ddsi_plist_t *plist); +bool q_omg_security_is_local_rtps_protected(const struct participant *pp, ddsi_entityid_t entityid); + +/** + * @brief Check if the participant allows communication with unauthenticated + * participants + * + * @param[in] pp The participant. + * + * @returns bool + * @retval true The participant allows unauthenticated communication + * @retval false Otherwise. + */ +bool q_omg_participant_allow_unauthenticated(struct participant *pp); + +/** + * @brief Initialize the proxy participant security attributes + * + * @param[in] proxypp The proxy participant. + * + */ +void q_omg_security_init_remote_participant(struct proxy_participant *proxypp); + +void q_omg_security_remote_participant_set_initialized(struct proxy_participant *proxypp); + +bool q_omg_security_remote_participant_is_initialized(struct proxy_participant *proxypp); + +/** + * @brief Registers the matched proxy participant with the crypto plugin + * + * When the proxy participant is authenticated and allowed by access control then the match between the local and + * the remote participant must be registered with the cypto factory provided by the crypto plugin. The + * shared secret handle obtained from the authentication phase and the permission handle returned when validating + * the proxy participant with access control plugin have to be provided. + * + * + * @param[in] pp The participant. + * @param[in] proxypp The proxy participant. + * @param[in] shared_secret The shared_secret handle. + * + * @returns bool + * @retval true The proxy participant is allowed. + * @retval false The proxy participant is not allowed. + */ +bool q_omg_security_register_remote_participant(struct participant *pp, struct proxy_participant *proxypp, int64_t shared_secret); + +/** + * @brief Removes a registered proxy participant from administation of the authentication, + * access control and crypto plugins. + * + * @param[in] proxypp The proxy participant. + */ +void q_omg_security_deregister_remote_participant(struct proxy_participant *proxypp); + +/** + * @brief Generate and send the crypto tokens needed for encoding RTPS messages. + * + * When the security settings indicate that RTPS message encoding or signing is + * configured for the participant then this function will ask the cypto echange for + * the corresponding cypto tokens and send these to the proxy participant. + * + * @param[in] pp The participant. + * @param[in] proxypp The proxy participant. + */ +void q_omg_security_participant_send_tokens(struct participant *pp, struct proxy_participant *proxypp); + +/** + * @brief Get the cypto handle associated with the proxy participant. + * + * This function returns the handle which is the association between + * the proxy participant and the crypto plugin. This handle is created + * when the proxy participant is registered with the crypto plugin. + * + * @param[in] proxypp The proxy participant. + * + * @returns handle + * @retval !0 Valid crypto handle associated with the proxy participant. + * @retval 0 Otherwise. + */ +int64_t q_omg_security_get_remote_participant_handle(struct proxy_participant *proxypp); + +/** + * @brief Set the crypto tokens used for the encryption and decryption of RTPS messages. + * + * The remote participant will send the crypto tokens when the security settings determine that the + * communication between the participants must be secure. These tokens are used for the necryption and + * decryption of complete RTPS messages. When these tokens are received this function will register these tokens + * with the crypto plugin. The crypto plugin will return a crypto handle that will be used to associate the + * stored tokens with the remote participant. + * + * @param[in] pp The local participant. + * @param[in] proxypp The remote participant. + * @param[in] tokens The crypto token received from the remote participant for the local participant. + */ +void q_omg_security_set_participant_crypto_tokens(struct participant *pp, struct proxy_participant *proxypp, const nn_dataholderseq_t *tokens); /** * @brief Set security information, depending on plist and proxy participant, @@ -231,10 +612,220 @@ set_proxy_reader_security_info( * @param[in] pwr Proxy writer to set security info on. * @param[in] plist Paramater list, possibly contains security info. */ -void -set_proxy_writer_security_info( - struct proxy_writer *pwr, - const ddsi_plist_t *plist); +void set_proxy_writer_security_info(struct proxy_writer *pwr, const ddsi_plist_t *plist); + +/** + * @brief Determine the security settings associated with the remote writer. + * + * From the security information contained in the parameter list from the remote writer + * the corresponding security settings are determined and returned in the info parameter. + * + * @param[in] pwr The remote writer. + * @param[in] plist The parameter list from the remote writer. + * @param[out] info The security settings associated with the remote writer. + */ +void q_omg_get_proxy_writer_security_info(struct proxy_writer *pwr, const ddsi_plist_t *plist, nn_security_info_t *info); + +/** + * @brief Check if the writer has the is_discovery_protected flag set + * + * @param[in] wr The local writer. + * + * @returns bool True if the writer has the is_discovery_protected flag set + */ +bool q_omg_writer_is_discovery_protected(const struct writer *wr); + +/** + * @brief Check if the writer has the is_submessage_protected flag set + * + * @param[in] wr The local writer. + * + * @returns bool True if the writer has the is_submessage_protected flag set + */ +bool q_omg_writer_is_submessage_protected(const struct writer *wr); + +/** + * @brief Check if the writer has the is_payload_protected flag set + * + * @param[in] wr The local writer. + * + * @returns bool True if the writer has the is_payload_protected flag set + */ +bool q_omg_writer_is_payload_protected(const struct writer *wr); + +/** + * @brief Check if the remote writer is allowed to communicate with endpoints of the + * local participant. + * + * This function will check with the access control plugin if the remote writer + * is allowed to communicate with this participant. + * + * @param[in] pwr The remote writer. + * @param[in] domain_id The domain id. + * @param[in] pp The local participant. + * + * @returns bool + * @retval true The remote writer is allowed to communicate. + * @retval false Otherwise. + */ +bool q_omg_security_check_remote_writer_permissions(const struct proxy_writer *pwr, uint32_t domain_id, struct participant *pp); + +/** + * @brief Check it the remote writer is allowed to communicate with the local reader. + * + * When a remote writer is allowed by access control it has to be checked if the remote + * writer is allowed to communicate with a particular local reader. This function will + * check if the provided security end-point attributes are compatible, When the security + * attributes are compatible then the function will register the reader and remote writer + * match with the crypto factory and will also ask the crypto exchange to generate the + * crypto tokens associate with the local reader which will be sent to the remote entity. + * Note that the reader crypto tokens are used to encrypt the reader specific submessages + * when submessage encoding or signing is configured. + * + * @param[in] rd The local reader. + * @param[in] pwr The remote writer. + * @param[out] crypto_handle The crypto handle associated with the match. + * + * @returns bool + * @retval true The local reader and remote writer are allowed to communicate. + * @retval false Otherwise. + */ +bool q_omg_security_match_remote_writer_enabled(struct reader *rd, struct proxy_writer *pwr, int64_t *crypto_handle); + +/** + * @brief Release the security information associated with the match between a reader and + * a remote writer. + * + * This function releases the security resources that were allocated for this reader and remote + * writer match. For example it will release the security tokens that where associated with this + * reader and the remote writer. + * + * @param[in] gv The global parameters. + * @param[in] rd_guid The guid of the reader. + * @param[in] match The reader-proxy_writer match. + */ +void q_omg_security_deregister_remote_writer_match(const struct ddsi_domaingv *gv, const ddsi_guid_t *rd_guid, struct rd_pwr_match *match); + +/** + * @brief Set the crypto tokens used for the secure communication from the remote writer to the reader. + * + * The remote writer instance will send the crypto tokens when the security settings determine that the + * communication between the remote writer and the reader must be secure. When these tokens are received + * this function will register these tokens with the crypto plugin and set the corresponding crypto handle returned + * by the crypto plugin which is then used for decrypting messages received from that remote writer to the reader. + * + * @param[in] rd The local reader. + * @param[in] pwr_guid The guid of the remote writer. + * @param[in] tokens The crypto token received from the remote writer for the reader. + */ +void q_omg_security_set_remote_writer_crypto_tokens(struct reader *rd, const ddsi_guid_t *pwr_guid, const nn_dataholderseq_t *tokens); + +/** + * @brief Set security information, depending on plist and proxy participant, + * into the given proxy reader. + * + * @param[in] prd Proxy reader to set security info on. + * @param[in] plist Paramater list, possibly contains security info. + */ +void set_proxy_reader_security_info(struct proxy_reader *prd, const ddsi_plist_t *plist); + +/** + * @brief Determine the security settings associated with the remote reader. + * + * From the security information contained in the parameter list from the remote reader + * the corresponding security settings are determined and returned in the info parameter. + * + * @param[in] prd The remote reader. + * @param[in] plist The parameter list from the remote reader. + * @param[out] info The security settings associated with the remote reader. + */ +void q_omg_get_proxy_reader_security_info(struct proxy_reader *prd, const ddsi_plist_t *plist, nn_security_info_t *info); + +/** + * @brief Check if the reader has the is_discovery_protected flag set + * + * @param[in] rd The local reader. + * + * @returns bool True if the reader has the is_discovery_protected flag set + */ +bool q_omg_reader_is_discovery_protected(const struct reader *rd); + +/** + * @brief Check if the reader has the is_submessage_protected flag set + * + * @param[in] rd The local reader. + * + * @returns bool True if the reader has the is_submessage_protected flag set + */ +bool q_omg_reader_is_submessage_protected(const struct reader *rd); + +/** + * @brief Check if the remote reader is allowed to communicate with endpoints of the + * local participant. + * + * This function will check with the access control plugin if the remote reader + * is allowed to communicate with this participant. + * + * @param[in] prd The remote reader. + * @param[in] domain_id The domain id. + * @param[in] pp The local participant. + * + * @returns bool + * @retval true The remote reader is allowed to communicate. + * @retval false Otherwise. + */ +bool q_omg_security_check_remote_reader_permissions(const struct proxy_reader *prd, uint32_t domain_id, struct participant *pp); + +/** + * @brief Check it the local writer is allowed to communicate with the remote reader. + * + * When a remote reader is allowed by accessstruct dds_security_garbage control it has to be checked if the local + * writer is allowed to communicate with a particular local writer. This function will + * check if the provided security end-point attributes are compatible, When the security + * attributes are compatible then the function will register the writer and remote reader + * match with the crypto factory and will also ask the crypto exchange to generate the + * crypto tokens associate with the local writer which will be sent to the remote entity. + * Note that the writer crypto tokens are used to encrypt the writer specific submessages + * when submessage encoding or signing is configured and also the crypto tokens used + * for encoding the payload of data or datafrag messages. + * + * @param[in] wr The local writer. + * @param[in] prd The remote reader. + * @param[out] crypto_handle The crypto handle associated with the match. + * + * @returns bool + * @retval true The local writer and remote reader are allowed to communicate. + * @retval false Otherwise. + */ +bool q_omg_security_match_remote_reader_enabled(struct writer *wr, struct proxy_reader *prd, int64_t *crypto_handle); + +/** + * @brief Release the security information associated with the match between a writer and + * a remote reader. + * + * This function releases the security resources that were allocated for this writer and remote + * reader match. For example it will release the security tokens that where associated with this + * writer and the remote reader. + * + * @param[in] gv The global parameters. + * @param[in] wr_guid The guid of the writer. + * @param[in] match The writer-proxy_reader match. + */ +void q_omg_security_deregister_remote_reader_match(const struct ddsi_domaingv *gv, const ddsi_guid_t *wr_guid, struct wr_prd_match *match); + +/** + * @brief Set the crypto tokens used for the secure communication from the remote reader to the writer. + * + * The remote reader instance will send the crypto tokens when the security settings determine that the + * communication between the remote reader and the writer must be secure. When these tokens are received + * this function will register these tokens with the crypto plugin and set the corresponding crypto handle returned + * by the crypto plugin which is then used for decrypting messages received from that remote reader to the writer. + * + * @param[in] wr The local writer. + * @param[in] prd_guid The guid of the remote reader. + * @param[in] tokens The crypto token received from the remote reader for the writer. + */ +void q_omg_security_set_remote_reader_crypto_tokens(struct writer *wr, const ddsi_guid_t *prd_guid, const nn_dataholderseq_t *tokens); /** * @brief Encode RTPS message. @@ -253,8 +844,9 @@ set_proxy_writer_security_info( */ bool q_omg_security_encode_rtps_message( + const struct ddsi_domaingv *gv, int64_t src_handle, - ddsi_guid_t *src_guid, + const ddsi_guid_t *src_guid, const unsigned char *src_buf, size_t src_len, unsigned char **dst_buf, @@ -283,11 +875,7 @@ q_omg_security_encode_rtps_message( * contains the payload that should be send. * @retval false Encoding was necessary, but failed. */ -bool -encode_payload( - struct writer *wr, - ddsrt_iovec_t *vec, - unsigned char **buf); +bool encode_payload(struct writer *wr, ddsrt_iovec_t *vec, unsigned char **buf); /** * @brief Decode the payload of a Data submessage. @@ -309,13 +897,7 @@ encode_payload( * contains the data that should be deserialized. * @retval false Decoding was necessary, but failed. */ -bool -decode_Data( - const struct ddsi_domaingv *gv, - struct nn_rsample_info *sampleinfo, - unsigned char *payloadp, - uint32_t payloadsz, - size_t *submsg_len); +bool decode_Data(const struct ddsi_domaingv *gv, struct nn_rsample_info *sampleinfo, unsigned char *payloadp, uint32_t payloadsz, size_t *submsg_len); /** * @brief Decode the payload of a DataFrag submessage. @@ -337,13 +919,7 @@ decode_Data( * contains the data that should be deserialized. * @retval false Decoding was necessary, but failed. */ -bool -decode_DataFrag( - const struct ddsi_domaingv *gv, - struct nn_rsample_info *sampleinfo, - unsigned char *payloadp, - uint32_t payloadsz, - size_t *submsg_len); +bool decode_DataFrag(const struct ddsi_domaingv *gv, struct nn_rsample_info *sampleinfo, unsigned char *payloadp, uint32_t payloadsz, size_t *submsg_len); /** * @brief Encode datareader submessage when necessary. @@ -359,12 +935,7 @@ decode_DataFrag( * @param[in] pwr Writer for which the message is intended. * @param[in] rd_guid Origin reader guid. */ -void -encode_datareader_submsg( - struct nn_xmsg *msg, - struct nn_xmsg_marker sm_marker, - struct proxy_writer *pwr, - const struct ddsi_guid *rd_guid); +void encode_datareader_submsg(struct nn_xmsg *msg, struct nn_xmsg_marker sm_marker, struct proxy_writer *pwr, const struct ddsi_guid *rd_guid); /** * @brief Encode datawriter submessage when necessary. @@ -379,11 +950,7 @@ encode_datareader_submsg( * @param[in,out] sm_marker Submessage location within message. * @param[in] wr Origin writer guid. */ -void -encode_datawriter_submsg( - struct nn_xmsg *msg, - struct nn_xmsg_marker sm_marker, - struct writer *wr); +void encode_datawriter_submsg(struct nn_xmsg *msg, struct nn_xmsg_marker sm_marker, struct writer *wr); /** * @brief Check if given submessage is properly decoded. @@ -461,16 +1028,7 @@ decode_SecPrefix( * @retval NN_RTPS_MSG_STATE_ENCODED Decoding succeeded. * @retval NN_RTPS_MSG_STATE_ERROR Decoding failed. */ -nn_rtps_msg_state_t -decode_rtps_message( - struct thread_state1 * const ts1, - struct ddsi_domaingv *gv, - struct nn_rmsg **rmsg, - Header_t **hdr, - unsigned char **buff, - ssize_t *sz, - struct nn_rbufpool *rbpool, - bool isstream); +nn_rtps_msg_state_t decode_rtps_message(struct thread_state1 * const ts1, struct ddsi_domaingv *gv, struct nn_rmsg **rmsg, Header_t **hdr, unsigned char **buff, ssize_t *sz, struct nn_rbufpool *rbpool, bool isstream); /** * @brief Send the RTPS message securely. @@ -491,6 +1049,7 @@ decode_rtps_message( */ ssize_t secure_conn_write( + const struct ddsi_domaingv *gv, ddsi_tran_conn_t conn, const nn_locator_t *dst, size_t niov, @@ -518,239 +1077,58 @@ secure_conn_write( dds_return_t q_omg_security_load( struct dds_security_context *security_context, const dds_qos_t *qos ); -void q_omg_security_init( struct dds_security_context **sc, const struct ddsrt_log_cfg *logcfg); +void q_omg_security_init( struct ddsi_domaingv *gv ); -void q_omg_security_deinit( struct dds_security_context **sc); +void q_omg_security_deinit( struct ddsi_domaingv *gv ); bool q_omg_is_security_loaded( struct dds_security_context *sc ); -/** - * @brief Check if the participant and the proxy participant - * have compatible security info settings. - * - * Associated with a secure participant is the ParticipantSecurityInfo parameter. - * This parameter contains the setting of the security attributes and the associated - * plugin security attributes of the secure participant. - * This function will check if the received ParticipantSecurityInfo parameter is - * compatible with the local ParticipantSecurityInfo parameter. - * - * @param[in] pp The participant. - * @param[in] proxypp The proxy participant. - * - * @returns bool - * @retval true The participant and the proxy participant have compatible - * security info settings. - * @retval false Otherwise. - */ -bool q_omg_is_similar_participant_security_info(struct participant *pp, struct proxy_participant *proxypp); - -/** - * @brief Check if the participant allows communication with unauthenticated - * participants - * - * @param[in] pp The participant. - * - * @returns bool - * @retval true The participant allows unauthenticated communication - * @retval false Otherwise. - */ -bool q_omg_participant_allow_unauthenticated(struct participant *pp); - -/** - * @brief Register participant with security plugin and check if the - * participant is allowed by security. - * - * This function will register the participant with the authentication - * plugin which will check if the provided security QoS parameters are - * correct, e.g. is the provided certificate valid, etc. - * When that is successful it is checked with access control if the - * participant has the correct permissions and is allowed to be created. - * - * @param[in] pp The participant. - * @param[in] domain_id The domain id. - * - * @returns bool - * @retval true The security check on the participant succeeded. - * @retval false The security check on the participant failed. - */ -bool q_omg_security_check_create_participant(struct participant *pp, uint32_t domain_id); - -/** - * @brief Initialize the proxy participant security attributes - * - * @param[in] proxypp The proxy participant. - * - */ -void q_omg_security_init_remote_participant(struct proxy_participant *proxypp); - -/** - * @brief Check the if the proxy participant is allowed by checking the security permissions. - * - * The access control plugin is ask to verify if the proxy participant is allowed to - * communicate with the local participant. When the proxy participant is allowed the - * function will return a valid permission handle which is provided by the access control plugin. - * - * @param[in] domain_id The domain id - * @param[in] pp The participant - * @param[in] proxypp The proxy participant - * - * @returns permission handle - * @retval !0 The proxy participant is allowed - * @retval 0 The proxy participant is not allowed. - */ -int64_t q_omg_security_check_remote_participant_permissions(uint32_t domain_id, struct participant *pp, struct proxy_participant *proxypp); - -/** - * @brief Registers the matched proxy participant with the crypto plugin - * - * When the proxy participant is authenticated and allowed by access control then the match between the local and - * the remote participant must be registered with the cypto factory provided by the crypto plugin. The - * shared secret handle obtained from the authentication phase and the permission handle returned when validating - * the proxy participant with access control plugin have to be provided. - * - * - * @param[in] pp The participant. - * @param[in] proxypp The proxy participant. - * @param[in] shared_secret The shared_secret handle. - * @param[in] proxy_permissions The permission handle associated with the proxy participant. - */ -void q_omg_security_register_remote_participant(struct participant *pp, struct proxy_participant *proxypp, int64_t shared_secret, int64_t proxy_permissions); - -/** - * @brief Removes a registered proxy participant from administation of the authentication, - * access control and crypto plugins. - * - * @param[in] proxypp The proxy participant. - */ -void q_omg_security_deregister_remote_participant(struct proxy_participant *proxypp); - -/** - * @brief Generate and send the crypto tokens needed for encoding RTPS messages. - * - * When the security settings indicate that RTPS message encoding or signing is - * configured for the participant then this function will ask the cypto echange for - * the corresponding cypto tokens and send these to the proxy participant. - * - * @param[in] pp The participant. - * @param[in] proxypp The proxy participant. - */ -void q_omg_security_participant_send_tokens(struct participant *pp, struct proxy_participant *proxypp); - -/** - * @brief Check if the remote writer is allowed to communicate with endpoints of the - * local participant. - * - * This function will check with the access control plugin if the remote writer - * is allowed to communicate with this participant. - * - * @param[in] pwr The remote writer. - * @param[in] domain_id The domain id. - * @param[in] pp The local participant. - * - * @returns bool - * @retval true The remote writer is allowed to communicate. - * @retval false Otherwise. - */ -bool q_omg_security_check_remote_writer_permissions(const struct proxy_writer *pwr, uint32_t domain_id, struct participant *pp); - -/** - * @brief Check if the remote reader is allowed to communicate with endpoints of the - * local participant. - * - * This function will check with the access control plugin if the remote reader - * is allowed to communicate with this participant. - * - * @param[in] prd The remote reader. - * @param[in] domain_id The domain id. - * @param[in] pp The local participant. - * - * @returns bool - * @retval true The remote reader is allowed to communicate. - * @retval false Otherwise. - */ -bool q_omg_security_check_remote_reader_permissions(const struct proxy_reader *prd, uint32_t domain_id, struct participant *pp); - -/** - * @brief Check it the remote writer is allowed to communicate with the local reader. - * - * When a remote writer is allowed by access control it has to be checked if the remote - * writer is allowed to communicate with a particular local reader. This function will - * check if the provided security end-point attributes are compatible, When the security - * attributes are compatible then the function will register the reader and remote writer - * match with the crypto factory and will also ask the crypto exchange to generate the - * crypto tokens associate with the local reader which will be sent to the remote entity. - * Note that the reader crypto tokens are used to encrypt the reader specific submessages - * when submessage encoding or signing is configured. - * - * @param[in] rd The local reader. - * @param[in] pwr The remote writer. - * - * @returns bool - * @retval true The local reader and remote writer are allowed to communicate. - * @retval false Otherwise. - */ -bool q_omg_security_match_remote_writer_enabled(struct reader *rd, struct proxy_writer *pwr); - -/** - * @brief Check it the local writer is allowed to communicate with the remote reader. - * - * When a remote reader is allowed by access control it has to be checked if the local - * writer is allowed to communicate with a particular local writer. This function will - * check if the provided security end-point attributes are compatible, When the security - * attributes are compatible then the function will register the writer and remote reader - * match with the crypto factory and will also ask the crypto exchange to generate the - * crypto tokens associate with the local writer which will be sent to the remote entity. - * Note that the writer crypto tokens are used to encrypt the writer specific submessages - * when submessage encoding or signing is configured and also the crypto tokens used - * for encoding the payload of data or datafrag messages. - * - * @param[in] wr The local writer. - * @param[in] prd The remote reader. - * - * @returns bool - * @retval true The local writer and remote reader are allowed to communicate. - * @retval false Otherwise. - */ -bool q_omg_security_match_remote_reader_enabled(struct writer *wr, struct proxy_reader *prd); - #else /* DDSI_INCLUDE_SECURITY */ #include "dds/ddsi/q_unused.h" -inline bool -q_omg_participant_is_secure( - UNUSED_ARG(const struct participant *pp)) +inline bool q_omg_security_enabled(void) { return false; } -inline bool -q_omg_proxy_participant_is_secure( - UNUSED_ARG(const struct proxy_participant *proxypp)) +inline bool q_omg_participant_is_access_protected(UNUSED_ARG(const struct participant *pp)) { return false; } -inline unsigned -determine_subscription_writer( - UNUSED_ARG(const struct reader *rd)) +inline bool q_omg_participant_is_rtps_protected(UNUSED_ARG(const struct participant *pp)) +{ + return false; +} + +inline bool q_omg_participant_is_liveliness_protected(UNUSED_ARG(const struct participant *pp)) +{ + return false; +} + +inline bool q_omg_participant_is_secure(UNUSED_ARG(const struct participant *pp)) +{ + return false; +} + +inline bool q_omg_proxy_participant_is_secure(UNUSED_ARG(const struct proxy_participant *proxypp)) +{ + return false; +} + +inline unsigned determine_subscription_writer(UNUSED_ARG(const struct reader *rd)) { return NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER; } -inline unsigned -determine_publication_writer( - UNUSED_ARG(const struct writer *wr)) +inline unsigned determine_publication_writer(UNUSED_ARG(const struct writer *wr)) { return NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER; } -inline bool -is_proxy_participant_deletion_allowed( - UNUSED_ARG(struct ddsi_domaingv * const gv), - UNUSED_ARG(const struct ddsi_guid *guid), - UNUSED_ARG(const ddsi_entityid_t pwr_entityid)) +inline bool is_proxy_participant_deletion_allowed(UNUSED_ARG(struct ddsi_domaingv * const gv), UNUSED_ARG(const struct ddsi_guid *guid), UNUSED_ARG(const ddsi_entityid_t pwr_entityid)) { return true; } @@ -765,12 +1143,56 @@ inline bool q_omg_participant_allow_unauthenticated(UNUSED_ARG(struct participan return true; } -inline bool -q_omg_security_check_create_participant(UNUSED_ARG(struct participant *pp), UNUSED_ARG(uint32_t domain_id)) +inline bool q_omg_security_check_create_participant(UNUSED_ARG(struct participant *pp), UNUSED_ARG(uint32_t domain_id)) { return true; } +inline void q_omg_security_deregister_participant(UNUSED_ARG(struct participant *pp)) +{ +} + +inline bool q_omg_security_check_create_topic(UNUSED_ARG(const struct ddsi_domaingv *gv), UNUSED_ARG(const ddsi_guid_t *pp_guid), UNUSED_ARG(const char *topic_name), UNUSED_ARG(const struct dds_qos *qos)) +{ + return true; +} + +inline int64_t q_omg_security_get_local_participant_handle(UNUSED_ARG(const struct participant *pp)) +{ + return 0; +} + +inline bool q_omg_security_check_create_writer(UNUSED_ARG(struct participant *pp), UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(const char *topic_name), UNUSED_ARG(const struct dds_qos *writer_qos)) +{ + return true; +} + +inline void q_omg_security_register_writer(UNUSED_ARG(struct writer *wr)) +{ +} + +inline void q_omg_security_deregister_writer(UNUSED_ARG(struct writer *wr)) +{ +} + +inline bool q_omg_security_check_create_reader(UNUSED_ARG(struct participant *pp), UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(const char *topic_name), UNUSED_ARG(const struct dds_qos *reader_qos)) +{ + return true; +} + +inline void q_omg_security_register_reader(UNUSED_ARG(struct reader *rd)) +{ +} + +inline void q_omg_security_deregister_reader(UNUSED_ARG(struct reader *rd)) +{ +} + +inline bool q_omg_security_is_remote_rtps_protected(UNUSED_ARG(const struct proxy_participant *proxypp), UNUSED_ARG(ddsi_entityid_t entityid)) +{ + return false; +} + inline void q_omg_security_init_remote_participant(UNUSED_ARG(struct proxy_participant *proxypp)) { } @@ -780,8 +1202,9 @@ inline int64_t q_omg_security_check_remote_participant_permissions(UNUSED_ARG(ui return 0LL; } -inline void q_omg_security_register_remote_participant(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp), UNUSED_ARG(int64_t shared_secret), UNUSED_ARG(int64_t proxy_permissions)) +inline bool q_omg_security_register_remote_participant(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp), UNUSED_ARG(int64_t identity_handle), UNUSED_ARG(int64_t shared_secret)) { + return true; } inline void q_omg_security_deregister_remote_participant(UNUSED_ARG(struct proxy_participant *proxypp)) @@ -792,46 +1215,78 @@ inline void q_omg_security_participant_send_tokens(UNUSED_ARG(struct participant { } -inline bool q_omg_security_match_remote_writer_enabled(UNUSED_ARG(struct reader *rd), UNUSED_ARG(struct proxy_writer *pwr)) +inline int64_t q_omg_security_get_remote_participant_handle(UNUSED_ARG(struct proxy_participant *proxypp)) +{ + return 0; +} + +inline bool q_omg_security_match_remote_writer_enabled(UNUSED_ARG(struct reader *rd), UNUSED_ARG(struct proxy_writer *pwr), UNUSED_ARG(int64_t *crypto_handle)) { return true; } -inline bool q_omg_security_match_remote_reader_enabled(UNUSED_ARG(struct writer *wr), UNUSED_ARG(struct proxy_reader *prd)) +inline bool q_omg_security_match_remote_reader_enabled(UNUSED_ARG(struct writer *wr), UNUSED_ARG(struct proxy_reader *prd), UNUSED_ARG(int64_t *crypto_handle)) { return true; } -inline bool -q_omg_security_check_remote_writer_permissions(UNUSED_ARG(const struct proxy_writer *pwr), UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(struct participant *pp)) +inline void q_omg_get_proxy_writer_security_info(UNUSED_ARG(struct proxy_writer *pwr), UNUSED_ARG(const ddsi_plist_t *plist), UNUSED_ARG(nn_security_info_t *info)) +{ +} + +inline bool q_omg_writer_is_discovery_protected(UNUSED_ARG(const struct writer *wr)) +{ + return false; +} + +inline bool q_omg_writer_is_submessage_protected(UNUSED_ARG(const struct writer *wr)) +{ + return false; +} + +inline bool q_omg_writer_is_payload_protected(UNUSED_ARG(const struct writer *wr)) +{ + return false; +} + +inline bool q_omg_security_check_remote_writer_permissions(UNUSED_ARG(const struct proxy_writer *pwr), UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(struct participant *pp)) { return true; } -inline bool -q_omg_security_check_remote_reader_permissions(UNUSED_ARG(const struct proxy_reader *prd), UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(struct participant *pp)) +inline void q_omg_security_deregister_remote_writer_match(UNUSED_ARG(const struct proxy_writer *pwr), UNUSED_ARG(const struct reader *rd), UNUSED_ARG(struct rd_pwr_match *match)) +{ +} + +inline void q_omg_get_proxy_reader_security_info(UNUSED_ARG(struct proxy_reader *prd), UNUSED_ARG(const ddsi_plist_t *plist), UNUSED_ARG(nn_security_info_t *info)) +{ +} + +inline bool q_omg_reader_is_discovery_protected(UNUSED_ARG(const struct reader *rd)) +{ + return false; +} + +inline bool q_omg_reader_is_submessage_protected(UNUSED_ARG(const struct reader *rd)) +{ + return false; +} + + +inline bool q_omg_security_check_remote_reader_permissions(UNUSED_ARG(const struct proxy_reader *prd), UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(struct participant *pp)) { return true; } -inline void -set_proxy_participant_security_info( - UNUSED_ARG(struct proxy_participant *prd), - UNUSED_ARG(const ddsi_plist_t *plist)) +inline void set_proxy_participant_security_info(UNUSED_ARG(struct proxy_participant *prd), UNUSED_ARG(const ddsi_plist_t *plist)) { } -inline void -set_proxy_reader_security_info( - UNUSED_ARG(struct proxy_reader *prd), - UNUSED_ARG(const ddsi_plist_t *plist)) +inline void set_proxy_reader_security_info(UNUSED_ARG(struct proxy_reader *prd), UNUSED_ARG(const ddsi_plist_t *plist)) { } -inline void -set_proxy_writer_security_info( - UNUSED_ARG(struct proxy_writer *pwr), - UNUSED_ARG(const ddsi_plist_t *plist)) +inline void set_proxy_writer_security_info(UNUSED_ARG(struct proxy_writer *pwr), UNUSED_ARG(const ddsi_plist_t *plist)) { } @@ -924,6 +1379,24 @@ inline void q_omg_security_deinit( UNUSED_ARG( struct dds_security_context *sc) inline bool q_omg_is_security_loaded( UNUSED_ARG( struct dds_security_context *sc )) { return false; } +inline void q_omg_security_deregister_remote_reader_match(UNUSED_ARG(const struct proxy_reader *prd), UNUSED_ARG(const struct writer *wr), UNUSED_ARG(struct wr_prd_match *match)) +{ +} + +inline bool q_omg_plist_keyhash_is_protected(UNUSED_ARG(const ddsi_plist_t *plist)) +{ + return false; +} + +inline bool q_omg_is_endpoint_protected(UNUSED_ARG(const ddsi_plist_t *plist)) +{ + return false; +} + +inline void q_omg_log_endpoint_protection(UNUSED_ARG(struct ddsi_domaingv * const gv), UNUSED_ARG(const ddsi_plist_t *plist)) +{ +} + #endif /* DDSI_INCLUDE_SECURITY */ #if defined (__cplusplus) diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_security_util.h b/src/core/ddsi/include/dds/ddsi/ddsi_security_util.h new file mode 100644 index 0000000..7c03496 --- /dev/null +++ b/src/core/ddsi/include/dds/ddsi/ddsi_security_util.h @@ -0,0 +1,91 @@ +/* + * 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 + */ +#ifndef DDSI_SECURITY_UTIL_H +#define DDSI_SECURITY_UTIL_H + +#ifdef DDSI_INCLUDE_SECURITY + +#include "dds/ddsi/ddsi_plist.h" +#include "dds/security/core/dds_security_utils.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +void g_omg_shallow_copy_StringSeq(DDS_Security_StringSeq *dst, const ddsi_stringseq_t *src); + +void g_omg_shallow_free_StringSeq(DDS_Security_StringSeq *obj); + +void q_omg_copy_PropertySeq(DDS_Security_PropertySeq *dst, const dds_propertyseq_t *src); + +void q_omg_shallow_copyin_PropertySeq(DDS_Security_PropertySeq *dst, const dds_propertyseq_t *src); + +void q_omg_shallow_copyout_PropertySeq(dds_propertyseq_t *dst, const DDS_Security_PropertySeq *src); + +void q_omg_shallow_free_PropertySeq(DDS_Security_PropertySeq *obj); + +void q_omg_shallow_copyin_BinaryPropertySeq(DDS_Security_BinaryPropertySeq *dst, const dds_binarypropertyseq_t *src); + +void q_omg_shallow_copyout_BinaryPropertySeq(dds_binarypropertyseq_t *dst, const DDS_Security_BinaryPropertySeq *src); + +void q_omg_shallow_free_BinaryPropertySeq(DDS_Security_BinaryPropertySeq *obj); + +void q_omg_shallow_copy_PropertyQosPolicy(DDS_Security_PropertyQosPolicy *dst, const dds_property_qospolicy_t *src); + +void q_omg_shallow_copy_security_qos(DDS_Security_Qos *dst, const struct dds_qos *src); + +void q_omg_shallow_free_PropertyQosPolicy(DDS_Security_PropertyQosPolicy *obj); + +void q_omg_shallow_free_security_qos(DDS_Security_Qos *obj); + +void q_omg_security_dataholder_copyin(nn_dataholder_t *dh, const DDS_Security_DataHolder *holder); + +void q_omg_security_dataholder_copyout(DDS_Security_DataHolder *holder, const nn_dataholder_t *dh); + +void q_omg_shallow_copyin_DataHolder(DDS_Security_DataHolder *dst, const nn_dataholder_t *src); + +void q_omg_shallow_copyout_DataHolder(nn_dataholder_t *dst, const DDS_Security_DataHolder *src); + +void q_omg_shallow_free_DataHolder(DDS_Security_DataHolder *obj); + +void q_omg_shallow_free_nn_dataholder(nn_dataholder_t *holder); + +void q_omg_shallow_copyin_DataHolderSeq(DDS_Security_DataHolderSeq *dst, const nn_dataholderseq_t *src); + +void q_omg_copyin_DataHolderSeq(DDS_Security_DataHolderSeq *dst, const nn_dataholderseq_t *src); + +void q_omg_shallow_copyout_DataHolderSeq(nn_dataholderseq_t *dst, const DDS_Security_DataHolderSeq *src); + +void q_omg_shallow_free_DataHolderSeq(DDS_Security_DataHolderSeq *obj); + +void q_omg_shallow_free_nn_dataholderseq(nn_dataholderseq_t *obj); + +void q_omg_shallow_copy_ParticipantBuiltinTopicDataSecure(DDS_Security_ParticipantBuiltinTopicDataSecure *dst, const ddsi_guid_t *guid, const ddsi_plist_t *plist); + +void q_omg_shallow_free_ParticipantBuiltinTopicDataSecure(DDS_Security_ParticipantBuiltinTopicDataSecure *obj); + +void q_omg_shallow_copy_SubscriptionBuiltinTopicDataSecure(DDS_Security_SubscriptionBuiltinTopicDataSecure *dst, const ddsi_guid_t *guid, const struct dds_qos *qos, const nn_security_info_t *secinfo); + +void q_omg_shallow_free_SubscriptionBuiltinTopicDataSecure(DDS_Security_SubscriptionBuiltinTopicDataSecure *obj); + +void q_omg_shallow_copy_PublicationBuiltinTopicDataSecure(DDS_Security_PublicationBuiltinTopicDataSecure *dst, const ddsi_guid_t *guid, const struct dds_qos *qos, const nn_security_info_t *secinfo); + +void q_omg_shallow_free_PublicationBuiltinTopicDataSecure(DDS_Security_PublicationBuiltinTopicDataSecure *obj); + +#if defined (__cplusplus) +} +#endif + + +#endif /* DDSI_INCLUDE_SECURITY */ + +#endif /* DDSI_SECURITY_UTIL_H */ diff --git a/src/core/ddsi/include/dds/ddsi/q_ddsi_discovery.h b/src/core/ddsi/include/dds/ddsi/q_ddsi_discovery.h index c5c801e..e18dde9 100644 --- a/src/core/ddsi/include/dds/ddsi/q_ddsi_discovery.h +++ b/src/core/ddsi/include/dds/ddsi/q_ddsi_discovery.h @@ -25,6 +25,8 @@ struct nn_rsample_info; struct nn_rdata; struct ddsi_plist; +void get_participant_builtin_topic_data(const struct participant *pp, struct nn_xmsg *mpayload, bool be); + int spdp_write (struct participant *pp); int spdp_dispose_unregister (struct participant *pp); diff --git a/src/core/ddsi/include/dds/ddsi/q_entity.h b/src/core/ddsi/include/dds/ddsi/q_entity.h index 306029b..37b4fff 100644 --- a/src/core/ddsi/include/dds/ddsi/q_entity.h +++ b/src/core/ddsi/include/dds/ddsi/q_entity.h @@ -45,6 +45,10 @@ struct whc; struct dds_qos; struct ddsi_plist; struct lease; +struct participant_sec_attributes; +struct proxy_participant_sec_attributes; +struct writer_sec_attributes; +struct reader_sec_attributes; struct proxy_group; struct proxy_endpoint_common; @@ -83,6 +87,9 @@ typedef void (*status_cb_t) (void *entity, const status_cb_data_t *data); struct prd_wr_match { ddsrt_avl_node_t avlnode; ddsi_guid_t wr_guid; +#ifdef DDSI_INCLUDE_SECURITY + int64_t crypto_handle; +#endif }; struct rd_pwr_match { @@ -94,6 +101,9 @@ struct rd_pwr_match { nn_locator_t ssm_mc_loc; nn_locator_t ssm_src_loc; #endif +#ifdef DDSI_INCLUDE_SECURITY + int64_t crypto_handle; +#endif }; struct wr_rd_match { @@ -128,6 +138,9 @@ struct wr_prd_match { nn_wctime_t hb_to_ack_latency_tlastlog; uint32_t non_responsive_count; uint32_t rexmit_requests; +#ifdef DDSI_INCLUDE_SECURITY + int64_t crypto_handle; +#endif }; enum pwr_rd_match_syncstate { @@ -156,6 +169,9 @@ struct pwr_rd_match { struct nn_reorder *reorder; /* can be done (mostly) per proxy writer, but that is harder; only when state=OUT_OF_SYNC */ } not_in_sync; } u; +#ifdef DDSI_INCLUDE_SECURITY + int64_t crypto_handle; +#endif }; struct nn_rsample_info; @@ -218,8 +234,6 @@ struct participant ddsrt_atomic_voidp_t minl_man; /* lease object for shortest manual-by-participant liveliness writer's lease */ ddsrt_fibheap_t leaseheap_man; /* keeps leases for this participant's writers (with liveliness manual-by-participant) */ #ifdef DDSI_INCLUDE_SECURITY - int64_t local_identity_handle; /* OMG DDS Security related member */ - int64_t permissions_handle; /* OMG DDS Security related member */ struct participant_sec_attributes *sec_attr; nn_security_info_t security_info; #endif @@ -286,6 +300,7 @@ struct writer uint32_t whc_low, whc_high; /* watermarks for WHC in bytes (counting only unack'd data) */ nn_etime_t t_rexmit_end; /* time of last 1->0 transition of "retransmitting" */ nn_etime_t t_whc_high_upd; /* time "whc_high" was last updated for controlled ramp-up of throughput */ + uint32_t num_readers; /* total number of matching PROXY readers */ int32_t num_reliable_readers; /* number of matching reliable PROXY readers */ ddsrt_avl_tree_t readers; /* all matching PROXY readers, see struct wr_prd_match */ ddsrt_avl_tree_t local_readers; /* all matching LOCAL readers, see struct wr_rd_match */ @@ -301,6 +316,9 @@ struct writer struct xeventq *evq; /* timed event queue to be used by this writer */ struct local_reader_ary rdary; /* LOCAL readers for fast-pathing; if not fast-pathed, fall back to scanning local_readers */ struct lease *lease; /* for liveliness administration (writer can only become inactive when using manual liveliness) */ +#ifdef DDSI_INCLUDE_SECURITY + struct writer_sec_attributes *sec_attr; +#endif }; inline seqno_t writer_read_seq_xmit (const struct writer *wr) { @@ -333,10 +351,14 @@ struct reader struct addrset *as; #endif const struct ddsi_sertopic * topic; /* topic is NULL for built-in readers */ + uint32_t num_writers; /* total number of matching PROXY writers */ ddsrt_avl_tree_t writers; /* all matching PROXY writers, see struct rd_pwr_match */ ddsrt_avl_tree_t local_writers; /* all matching LOCAL writers, see struct rd_wr_match */ ddsi2direct_directread_cb_t ddsi2direct_cb; void *ddsi2direct_cbarg; +#ifdef DDSI_INCLUDE_SECURITY + struct reader_sec_attributes *sec_attr; +#endif }; struct proxy_participant @@ -366,7 +388,6 @@ struct proxy_participant unsigned proxypp_have_spdp: 1; unsigned owns_lease: 1; #ifdef DDSI_INCLUDE_SECURITY - int64_t remote_identity_handle; /* OMG DDS Security related member */ nn_security_info_t security_info; struct proxy_participant_sec_attributes *sec_attr; #endif @@ -435,6 +456,9 @@ struct proxy_writer { ddsi2direct_directread_cb_t ddsi2direct_cb; void *ddsi2direct_cbarg; struct lease *lease; +#ifdef DDSI_INCLUDE_SECURITY + nn_security_info_t security_info; +#endif }; @@ -450,6 +474,9 @@ struct proxy_reader { #endif ddsrt_avl_tree_t writers; /* matching LOCAL writers */ filter_fn_t filter; +#ifdef DDSI_INCLUDE_SECURITY + nn_security_info_t security_info; +#endif }; DDS_EXPORT extern const ddsrt_avl_treedef_t wr_readers_treedef; @@ -533,8 +560,8 @@ nn_vendorid_t get_entity_vendorid (const struct entity_common *e); /** * @brief Create a new participant with a given GUID in the domain. * - * @param[in] ppguid - * The GUID of the new participant. + * @param[in,out] ppguid + * The GUID of the new participant, may be adjusted by security. * @param[in] flags * Zero or more of: * - RTPS_PF_NO_BUILTIN_READERS do not create discovery readers in new ppant @@ -555,7 +582,7 @@ nn_vendorid_t get_entity_vendorid (const struct entity_common *e); * @retval DDS_RETCODE_OUT_OF_RESOURCES * The configured maximum number of participants has been reached. */ -dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct ddsi_domaingv *gv, unsigned flags, const struct ddsi_plist *plist); +dds_return_t new_participant_guid (ddsi_guid_t *ppguid, struct ddsi_domaingv *gv, unsigned flags, const struct ddsi_plist *plist); /** * @brief Create a new participant in the domain. See also new_participant_guid. @@ -720,8 +747,8 @@ void rebuild_or_clear_writer_addrsets(struct ddsi_domaingv *gv, int rebuild); void local_reader_ary_setfastpath_ok (struct local_reader_ary *x, bool fastpath_ok); -void connect_writer_with_proxy_reader_secure(struct writer *wr, struct proxy_reader *prd, nn_mtime_t tnow); -void connect_reader_with_proxy_writer_secure(struct reader *rd, struct proxy_writer *pwr, nn_mtime_t tnow); +void connect_writer_with_proxy_reader_secure(struct writer *wr, struct proxy_reader *prd, nn_mtime_t tnow, int64_t crypto_handle); +void connect_reader_with_proxy_writer_secure(struct reader *rd, struct proxy_writer *pwr, nn_mtime_t tnow, int64_t crypto_handle); struct ddsi_writer_info; diff --git a/src/core/ddsi/include/dds/ddsi/q_misc.h b/src/core/ddsi/include/dds/ddsi/q_misc.h index 22bb720..98a7457 100644 --- a/src/core/ddsi/include/dds/ddsi/q_misc.h +++ b/src/core/ddsi/include/dds/ddsi/q_misc.h @@ -35,6 +35,7 @@ unsigned char normalize_data_datafrag_flags (const SubmessageHeader_t *smhdr); int WildcardOverlap(char * p1, char * p2); #endif +DDS_EXPORT bool guid_prefix_zero (const ddsi_guid_prefix_t *a); DDS_EXPORT int guid_prefix_eq (const ddsi_guid_prefix_t *a, const ddsi_guid_prefix_t *b); DDS_EXPORT int guid_eq (const struct ddsi_guid *a, const struct ddsi_guid *b); DDS_EXPORT int ddsi2_patmatch (const char *pat, const char *str); diff --git a/src/core/ddsi/include/dds/ddsi/q_xevent.h b/src/core/ddsi/include/dds/ddsi/q_xevent.h index a3ba7b5..6542633 100644 --- a/src/core/ddsi/include/dds/ddsi/q_xevent.h +++ b/src/core/ddsi/include/dds/ddsi/q_xevent.h @@ -50,8 +50,10 @@ DDS_EXPORT dds_return_t xeventq_start (struct xeventq *evq, const char *name); / DDS_EXPORT void xeventq_stop (struct xeventq *evq); DDS_EXPORT void qxev_msg (struct xeventq *evq, struct nn_xmsg *msg); + DDS_EXPORT void qxev_pwr_entityid (struct proxy_writer * pwr, const ddsi_guid_t *guid); DDS_EXPORT void qxev_prd_entityid (struct proxy_reader * prd, const ddsi_guid_t *guid); +DDS_EXPORT void qxev_nt_callback (struct xeventq *evq, void (*cb) (void *arg), void *arg); /* Returns 1 if queued, 0 otherwise (no point in returning the event, you can't do anything with it anyway) */ diff --git a/src/core/ddsi/include/dds/ddsi/q_xmsg.h b/src/core/ddsi/include/dds/ddsi/q_xmsg.h index e82a81d..fcd6db1 100644 --- a/src/core/ddsi/include/dds/ddsi/q_xmsg.h +++ b/src/core/ddsi/include/dds/ddsi/q_xmsg.h @@ -128,10 +128,12 @@ void nn_xmsg_submsg_setnext (struct nn_xmsg *msg, struct nn_xmsg_marker marker); void nn_xmsg_submsg_init (struct nn_xmsg *msg, struct nn_xmsg_marker marker, SubmessageKind_t smkind); void nn_xmsg_add_timestamp (struct nn_xmsg *m, nn_wctime_t t); void nn_xmsg_add_entityid (struct nn_xmsg * m); +void *nn_xmsg_addpar_bo (struct nn_xmsg *m, nn_parameterid_t pid, size_t len, bool be); void *nn_xmsg_addpar (struct nn_xmsg *m, nn_parameterid_t pid, size_t len); void nn_xmsg_addpar_keyhash (struct nn_xmsg *m, const struct ddsi_serdata *serdata, bool force_md5); void nn_xmsg_addpar_statusinfo (struct nn_xmsg *m, unsigned statusinfo); void nn_xmsg_addpar_sentinel (struct nn_xmsg *m); +void nn_xmsg_addpar_sentinel_bo (struct nn_xmsg * m, bool be); int nn_xmsg_addpar_sentinel_ifparam (struct nn_xmsg *m); /* XPACK */ diff --git a/src/core/ddsi/src/ddsi_handshake.c b/src/core/ddsi/src/ddsi_handshake.c index 63de1a0..5d1b967 100644 --- a/src/core/ddsi/src/ddsi_handshake.c +++ b/src/core/ddsi/src/ddsi_handshake.c @@ -12,27 +12,76 @@ #include "dds/ddsi/ddsi_handshake.h" + #ifdef DDSI_INCLUDE_SECURITY +#include + +#include "dds/ddsi/q_bswap.h" +#include "dds/ddsi/ddsi_entity_index.h" +#include "dds/ddsi/ddsi_plist.h" +#include "dds/ddsi/q_entity.h" +#include "dds/security/dds_security_api_types.h" #include "dds/security/dds_security_api.h" -#include "dds/ddsrt/hopscotch.h" +#include "dds/ddsi/ddsi_security_omg.h" +#include "dds/security/core/dds_security_fsm.h" +#include "dds/ddsi/ddsi_security_util.h" +#include "dds/ddsi/ddsi_security_exchange.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/avl.h" + +#define HSTRACE(...) DDS_CTRACE (&handshake->gv->logconfig, __VA_ARGS__) +#define HSWARNING(...) DDS_CLOG (DDS_LC_WARNING, &handshake->gv->logconfig, __VA_ARGS__) +#define HSERROR(...) DDS_CLOG (DDS_LC_ERROR, &handshake->gv->logconfig, __VA_ARGS__) + +#define HSEXCEPTION(e, ...) \ + q_omg_log_exception(&handshake->gv->logconfig, DDS_LC_WARNING, e, __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) + + +#define VERBOSE_HANDSHAKE_DEBUG + +#if 1 +#define TRACE_FUNC(ptr) +#else +#undef TRACE +#define TRACE(args) nn_trace args +#define TRACE_FUNC(ptr) printf("[%p] %s\n", ptr, __FUNCTION__); +#endif + +typedef enum { + EVENT_AUTO = DDS_SECURITY_FSM_EVENT_AUTO, + EVENT_TIMEOUT = DDS_SECURITY_FSM_EVENT_TIMEOUT, + EVENT_VALIDATION_OK = DDS_SECURITY_VALIDATION_OK, + EVENT_VALIDATION_FAILED = DDS_SECURITY_VALIDATION_FAILED, + EVENT_VALIDATION_PENDING_RETRY = DDS_SECURITY_VALIDATION_PENDING_RETRY, + EVENT_VALIDATION_PENDING_HANDSHAKE_REQUEST = DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST, + EVENT_VALIDATION_PENDING_HANDSHAKE_MESSAGE = DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE, + EVENT_VALIDATION_OK_FINAL_MESSAGE = DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE, + EVENT_RECEIVED_MESSAGE_REQUEST = 100, + EVENT_RECEIVED_MESSAGE_REPLY = 101, + EVENT_RECEIVED_MESSAGE_FINAL = 102, + EVENT_SEND_CRYPTO_TOKENS = 103, + EVENT_RECV_CRYPTO_TOKENS = 104 +} handshake_event_t; + +struct handshake_entities { + ddsi_guid_t lguid; + ddsi_guid_t rguid; +}; struct ddsi_handshake { + ddsrt_avl_node_t avlnode; enum ddsi_handshake_state state; - - ddsi_guid_t local_pguid; /* the guid of the local participant */ - ddsi_guid_t remote_pguid; /* the guid of the remote participant */ - ddsi_handshake_end_cb_t end_cb; - struct ddsi_domaingv *gv; - ddsrt_mutex_t lock; - ddsrt_cond_t cv; - - ddsrt_atomic_uint32_t refc; - - DDS_Security_IdentityHandle local_identity_handle; - DDS_Security_IdentityHandle remote_identity_handle; + struct handshake_entities participants; DDS_Security_HandshakeHandle handshake_handle; + ddsrt_atomic_uint32_t refc; + ddsrt_atomic_uint32_t deleting; + ddsi_handshake_end_cb_t end_cb; + ddsrt_mutex_t lock; + struct dds_security_fsm *fsm; + const struct ddsi_domaingv *gv; + dds_security_authentication *auth; DDS_Security_HandshakeMessageToken handshake_message_in_token; nn_message_identity_t handshake_message_in_id; @@ -40,58 +89,1121 @@ struct ddsi_handshake DDS_Security_AuthRequestMessageToken local_auth_request_token; DDS_Security_AuthRequestMessageToken *remote_auth_request_token; DDS_Security_OctetSeq pdata; - DDS_Security_SharedSecretHandle shared_secret; + int64_t shared_secret; int handled_handshake_message; }; +struct ddsi_hsadmin { + ddsrt_mutex_t lock; + ddsrt_avl_tree_t handshakes; + struct dds_security_fsm_control *fsm_control; +}; + +static int compare_handshake(const void *va, const void *vb); + +const ddsrt_avl_treedef_t handshake_treedef = + DDSRT_AVL_TREEDEF_INITIALIZER (offsetof (struct ddsi_handshake, avlnode), offsetof (struct ddsi_handshake, participants), compare_handshake, 0); + +static int compare_handshake(const void *va, const void *vb) +{ + const struct handshake_entities *ha = va; + const struct handshake_entities *hb = vb; + int r; + + r = memcmp(&ha->rguid, &hb->rguid, sizeof(ha->rguid)); + if (r == 0) + r = memcmp(&ha->lguid, &hb->lguid, sizeof(ha->lguid)); + return r; +} + +static bool validate_handshake(struct ddsi_handshake *handshake, struct participant **pp, struct proxy_participant **proxypp) +{ + if (ddsrt_atomic_ld32(&handshake->deleting) > 0) + return false; + + if (pp) + { + if ((*pp = entidx_lookup_participant_guid(handshake->gv->entity_index, &handshake->participants.lguid)) == NULL) + return false; + } + + if (proxypp) + { + if ((*proxypp = entidx_lookup_proxy_participant_guid(handshake->gv->entity_index, &handshake->participants.rguid)) == NULL) + return false; + } + return true; +} + + +#define RETRY_TIMEOUT DDS_SECS(1) +#define RESEND_TIMEOUT DDS_SECS(1) +#define SEND_TOKENS_TIMEOUT DDS_MSECS(100) +#define AUTHENTICATION_TIMEOUT DDS_SECS(100) + +static void func_validate_remote_identity (struct dds_security_fsm *fsm, void *arg); +static void func_handshake_init_message_resend(struct dds_security_fsm *fsm, void *arg); +static void func_begin_handshake_reply (struct dds_security_fsm *fsm, void *arg); +static void func_begin_handshake_request (struct dds_security_fsm *fsm, void *arg); +static void func_process_handshake (struct dds_security_fsm *fsm, void *arg); +static void func_handshake_message_resend (struct dds_security_fsm *fsm, void *arg); +static void func_validation_ok (struct dds_security_fsm *fsm, void *arg); +static void func_validation_failed (struct dds_security_fsm *fsm, void *arg); +static void func_send_crypto_tokens_final (struct dds_security_fsm *fsm, void *arg); +static void func_send_crypto_tokens (struct dds_security_fsm *fsm, void *arg); + +static dds_security_fsm_state state_validate_remote_identity = { func_validate_remote_identity, 0 }; +static dds_security_fsm_state state_validate_remote_identity_retry_wait = { NULL, RETRY_TIMEOUT }; +static dds_security_fsm_state state_handshake_init_message_resend = { func_handshake_init_message_resend, 0 }; +static dds_security_fsm_state state_handshake_init_message_wait = { NULL, RESEND_TIMEOUT }; +static dds_security_fsm_state state_begin_handshake_reply = { func_begin_handshake_reply, 0 }; +static dds_security_fsm_state state_begin_handshake_reply_retry_wait = { NULL, RETRY_TIMEOUT }; +static dds_security_fsm_state state_begin_handshake_request = { func_begin_handshake_request, 0 }; +static dds_security_fsm_state state_begin_handshake_request_retry_wait = { NULL, RETRY_TIMEOUT }; +static dds_security_fsm_state state_process_handshake = { func_process_handshake, 0 }; +static dds_security_fsm_state state_process_handshake_retry_wait = { NULL, RETRY_TIMEOUT }; +static dds_security_fsm_state state_handshake_message_resend = { func_handshake_message_resend, 0 }; +static dds_security_fsm_state state_handshake_message_wait = { NULL, RESEND_TIMEOUT }; +static dds_security_fsm_state state_validation_ok = { func_validation_ok, 0 }; +static dds_security_fsm_state state_validation_failed = { func_validation_failed, 0 }; +static dds_security_fsm_state state_send_crypto_tokens_final_wait = { NULL, SEND_TOKENS_TIMEOUT }; +static dds_security_fsm_state state_send_crypto_tokens_wait = { NULL, SEND_TOKENS_TIMEOUT }; +static dds_security_fsm_state state_send_crypto_tokens_final = { func_send_crypto_tokens_final, 0 }; +static dds_security_fsm_state state_send_crypto_tokens = { func_send_crypto_tokens, 0 }; +static dds_security_fsm_state state_wait_crypto_tokens = { NULL, 0 }; +static dds_security_fsm_state state_handshake_final_resend = { func_handshake_message_resend, 0 }; + +#ifdef VERBOSE_HANDSHAKE_DEBUG +static void q_handshake_fsm_debug( + struct dds_security_fsm *fsm, + DDS_SECURITY_FSM_DEBUG_ACT act, + const dds_security_fsm_state *current, + int event_id, + void *arg) +{ + struct ddsi_handshake *handshake = arg; + char *dispatch; + char *state; + char *event; + + assert(handshake); + DDSRT_UNUSED_ARG(fsm); + + + if (current == NULL) state = "NULL"; + else if (current == &state_validate_remote_identity) state = "state_validate_remote_identity"; + else if (current == &state_validate_remote_identity_retry_wait) state = "state_validate_remote_identity_retry_wait"; + else if (current == &state_handshake_init_message_resend) state = "state_handshake_init_message_resend"; + else if (current == &state_handshake_init_message_wait) state = "state_handshake_init_message_wait"; + else if (current == &state_begin_handshake_reply) state = "state_begin_handshake_reply"; + else if (current == &state_begin_handshake_reply_retry_wait) state = "state_begin_handshake_reply_retry_wait"; + else if (current == &state_begin_handshake_request) state = "state_begin_handshake_request"; + else if (current == &state_begin_handshake_request_retry_wait) state = "state_begin_handshake_request_retry_wait"; + else if (current == &state_process_handshake) state = "state_process_handshake"; + else if (current == &state_process_handshake_retry_wait) state = "state_process_handshake_retry_wait"; + else if (current == &state_handshake_message_resend) state = "state_handshake_message_resend"; + else if (current == &state_handshake_message_wait) state = "state_handshake_message_wait"; + else if (current == &state_validation_ok) state = "state_validation_ok"; + else if (current == &state_validation_failed) state = "state_validation_failed"; + else if (current == &state_send_crypto_tokens_final_wait) state = "state_send_crypto_tokens_final_wait"; + else if (current == &state_send_crypto_tokens_wait) state = "state_send_crypto_tokens_wait"; + else if (current == &state_send_crypto_tokens_final) state = "state_send_crypto_tokens_final"; + else if (current == &state_send_crypto_tokens) state = "state_send_crypto_tokens"; + else if (current == &state_wait_crypto_tokens) state = "state_wait_crypto_tokens"; + else if (current == &state_handshake_final_resend) state = "state_handshake_final_resend"; + else state = "else????"; + + if (event_id == EVENT_AUTO) event = "EVENT_AUTO"; + else if (event_id == EVENT_TIMEOUT) event = "EVENT_TIMEOUT"; + else if (event_id == EVENT_VALIDATION_OK) event = "EVENT_VALIDATION_OK"; + else if (event_id == EVENT_VALIDATION_FAILED) event = "EVENT_VALIDATION_FAILED"; + else if (event_id == EVENT_VALIDATION_PENDING_RETRY) event = "EVENT_VALIDATION_PENDING_RETRY"; + else if (event_id == EVENT_VALIDATION_PENDING_HANDSHAKE_REQUEST) event = "EVENT_VALIDATION_PENDING_HANDSHAKE_REQUEST"; + else if (event_id == EVENT_VALIDATION_PENDING_HANDSHAKE_MESSAGE) event = "EVENT_VALIDATION_PENDING_HANDSHAKE_MESSAGE"; + else if (event_id == EVENT_VALIDATION_OK_FINAL_MESSAGE) event = "EVENT_VALIDATION_OK_FINAL_MESSAGE"; + else if (event_id == EVENT_RECEIVED_MESSAGE_REQUEST) event = "EVENT_RECEIVED_MESSAGE_REQUEST"; + else if (event_id == EVENT_RECEIVED_MESSAGE_REPLY) event = "EVENT_RECEIVED_MESSAGE_REPLY"; + else if (event_id == EVENT_RECEIVED_MESSAGE_FINAL) event = "EVENT_RECEIVED_MESSAGE_FINAL"; + else if (event_id == EVENT_SEND_CRYPTO_TOKENS) event = "EVENT_SEND_CRYPTO_TOKENS"; + else if (event_id == EVENT_RECV_CRYPTO_TOKENS) event = "EVENT_RECV_CRYPTO_TOKENS"; + else event = ""; + + if (act == DDS_SECURITY_FSM_DEBUG_ACT_DISPATCH) dispatch = "dispatching"; + else if (act == DDS_SECURITY_FSM_DEBUG_ACT_DISPATCH_DIRECT) dispatch = "direct_dispatching"; + else if (act == DDS_SECURITY_FSM_DEBUG_ACT_HANDLING) dispatch = "handling"; + else dispatch = ""; + + HSTRACE ("FSM: handshake_debug (lguid="PGUIDFMT" rguid="PGUIDFMT") act=%s, state=%s, event=%s\n", + PGUID (handshake->participants.lguid), + PGUID (handshake->participants.rguid), + dispatch, + state, + event); + +} +#endif + + +/************************************************************************************************************ + Inspiration from https://confluence.prismtech.com/display/VC/Authentication?preview=/30379826/34340895/PT_StateMachine_3g.gif + + [START] + | + v + .---------------------------------. + | state_validate_remote_identity | + .------------|---------------------------------|----------.--------------------. + | | func_validate_remote_identity() | | | + | '---------------------------------' | VALIDATION_PENDING_HANDSHAKE_MESSAGE +VALIDATION_FAILED ^ | VALIDATION_PENDING_RETRY | | +VALIDATION_OK | | | | + | TIMEOUT | v | v + | .-------------------------------------------. | .-----------------------------------. + | | state_validate_remote_identity_retry_wait | | | state_handshake_init_message_wait |<---------------. + | |-------------------------------------------| | |-----------------------------------| AUTO | + | | retry_timeout | | | resend_timeout |---------. | + | '-------------------------------------------' | '-----------------------------------' TIMEOUT | | + | | | | | + | .-----------------------------------' | | | + | | VALIDATION_PENDING_HANDSHAKE_REQUEST | v | + | | | .--------------------------------------. + | v RECEIVED_MESSAGE_REQUEST | state_handshake_init_message_resend | + | .--------------------------------. | |--------------------------------------| + | | state_begin_handshake_request | VALIDATION_PENDING_RETRY | | func_handshake_init_message_resend() | + | |--------------------------------|------------. | '--------------------------------------' + | | func_begin_handshake_request() | | | ^ + | '--------------------------------' | | | + | | | ^ | | | + | | | | TIMEOUT v | | + | VALIDATION_FAILED | .------------------------------------------. | | + | VALIDATION_OK | | state_begin_handshake_request_retry_wait | | | + | | | |------------------------------------------| | | + |--------' | | retry_timeout | | | + | | '------------------------------------------' | | + | | v VALIDATION_FAILED + | | .------------------------------. | + | VALIDATION_PENDING_HANDSHAKE_MESSAGE | state_begin_handshake_reply |------------' + | | .-------|------------------------------| + | | | | func_begin_handshake_reply() |------------. + | | | '------------------------------' | + | | | VALIDATION_OK | ^ VALIDATION_PENDING_RETRY + | | | | | | + | | VALIDATION_PENDING_HANDSHAKE_MESSAGE v | TIMEOUT | + | | | goto state_validation_ok | | + | | v | v + | | .------------------------------. .------------------------------------------. + | | | state_handshake_message_wait | | state_begin_handshake_reply_retry_wait | + | .--------------->|------------------------------|-------. |------------------------------------------| + | | | resend_timeout | | | retry_timeout | + | | '------------------------------' | '------------------------------------------' + | | AUTO | ^ | + | | TIMEOUT | | | + | .---------------------------------. | | | RECEIVED_MESSAGE_REPLY + | | state_handshake_message_resend | | VALIDATION_FAILED | RECEIVED_MESSAGE_FINAL + | |---------------------------------|<--------------' | | + | | func_handshake_message_resend() | | v + | '---------------------------------' .--------------------------. + | | state_process_handshake | + | .--------------------------------|--------------------------|--------------------------. + | | .------------------>| func_process_handshake() | | + | | | '--------------------------' | + | | | | | + | VALIDATION_PENDING_RETRY TIMEOUT VALIDATION_OK | | + | v | v | + | .------------------------------------. .-------------------------------. | + | | state_process_handshake_retry_wait | | state_send_crypto_tokens_wait | | + | |------------------------------------| |-------------------------------| | + | | retry_timeout | | send_tokens_timeout | | + | '------------------------------------' '-------------------------------' | + | | | VALIDATION_OK_FINAL_MESSAGE + | .-------------' '---------. | + | | RECV_CRYPTO_TOKENS TIMEOUT | | + | v v | + | .---------------------------------. .---------------------------. | + | | state_send_crypto_tokens_final | | state_send_crypto_tokens | | + | .--------------|---------------------------------| |---------------------------| | + | | | func_send_crypto_tokens_final() | | func_send_crypto_tokens() | | + | | '---------------------------------' '---------------------------' | + | | ^ | | + | VALIDATION_OK | .--------------------. VALIDATION_OK_FINAL_MESSAGE | + | | TIMEOUT | | RECV_CRYPTO_TOKENS | | | + | | | v | v | + | | .-------------------------------------. .--------------------------. | + | | | state_send_crypto_tokens_final_wait | | state_wait_crypto_tokens |<--------' + | | |-------------------------------------| |--------------------------| + | | | send_tokens_timeout | | |---------. + | | '-------------------------------------' '--------------------------' | + | | ^ | ^ | + | | | RECEIVED_MESSAGE_REPLY AUTO VALIDATION_OK + | | RECV_CRYPTO_TOKENS v | | + | | | .---------------------------------. | + | | | | state_handshake_final_resend | | + | | '---------------------|---------------------------------| | + | VALIDATION_OK | | func_handshake_message_resend() | | + |---------------------------------------------------------. '---------------------------------' | + | | | + '---------------. | | +VALIDATION_FAILED | | | + v v | + .--------------------------. .----------------------. | + | state_validation_failed | | state_validation_ok | | + |--------------------------| |----------------------|<----------------------------------------' + | func_validation_failed() | | func_validation_ok() | + '--------------------------' '----------------------' + | | + v v + [END] [END] + + + .----------------------------------------. + | state_begin_handshake_reply_retry_wait | + |----------------------------------------| + | retry_timeout | + '----------------------------------------' + + +*************************************************************************************************************/ +static const dds_security_fsm_transition handshake_transistions [] = +{ /* Start */ + { NULL, EVENT_AUTO, NULL, + &state_validate_remote_identity }, + /* validate remote identity */ + { &state_validate_remote_identity, EVENT_VALIDATION_PENDING_RETRY, NULL, + &state_validate_remote_identity_retry_wait }, + { &state_validate_remote_identity, EVENT_VALIDATION_FAILED, NULL, + &state_validation_failed }, + { &state_validate_remote_identity, EVENT_VALIDATION_PENDING_HANDSHAKE_REQUEST, NULL, + &state_begin_handshake_request }, + { &state_validate_remote_identity, EVENT_VALIDATION_OK, NULL, + &state_validation_ok }, + { &state_validate_remote_identity, EVENT_VALIDATION_PENDING_HANDSHAKE_MESSAGE, NULL, + &state_handshake_init_message_wait }, + /* ValRemIdentityRetryWait */ + { &state_validate_remote_identity_retry_wait, EVENT_TIMEOUT, NULL, + &state_validate_remote_identity }, + /* HandshakeInitMessageWait */ + { &state_handshake_init_message_wait, EVENT_TIMEOUT, NULL, + &state_handshake_init_message_resend }, + { &state_handshake_init_message_wait, EVENT_RECEIVED_MESSAGE_REQUEST, NULL, + &state_begin_handshake_reply }, + /* resend message */ + { &state_handshake_init_message_resend, EVENT_AUTO, NULL, + &state_handshake_init_message_wait }, + /* begin handshake reply */ + { &state_begin_handshake_reply, EVENT_VALIDATION_PENDING_RETRY, NULL, + &state_begin_handshake_reply_retry_wait }, + { &state_begin_handshake_reply, EVENT_VALIDATION_FAILED, NULL, + &state_handshake_init_message_resend }, + { &state_begin_handshake_reply, EVENT_VALIDATION_PENDING_HANDSHAKE_MESSAGE, NULL, + &state_handshake_message_wait }, + { &state_begin_handshake_reply, EVENT_VALIDATION_OK, NULL, + &state_validation_ok }, + /* BeginHsRepRetryWait */ + { &state_begin_handshake_reply_retry_wait, EVENT_TIMEOUT, NULL, + &state_begin_handshake_reply }, + /* begin handshake request */ + { &state_begin_handshake_request, EVENT_VALIDATION_PENDING_RETRY, NULL, + &state_begin_handshake_request_retry_wait }, + { &state_begin_handshake_request, EVENT_VALIDATION_FAILED, NULL, + &state_validation_failed }, + { &state_begin_handshake_request, EVENT_VALIDATION_PENDING_HANDSHAKE_MESSAGE, NULL, + &state_handshake_message_wait }, + { &state_begin_handshake_request, EVENT_VALIDATION_OK, NULL, + &state_validation_ok }, + /* BeginHsReqRetryWait */ + { &state_begin_handshake_request_retry_wait, EVENT_TIMEOUT, NULL, + &state_begin_handshake_request }, + /* HandshakeMessageWait */ + { &state_handshake_message_wait, EVENT_TIMEOUT, NULL, + &state_handshake_message_resend }, + { &state_handshake_message_wait, EVENT_RECEIVED_MESSAGE_REPLY, NULL, + &state_process_handshake }, + { &state_handshake_message_wait, EVENT_RECEIVED_MESSAGE_FINAL, NULL, + &state_process_handshake }, + /* resend message */ + { &state_handshake_message_resend, EVENT_AUTO, NULL, + &state_handshake_message_wait }, + /* process handshake */ + { &state_process_handshake, EVENT_VALIDATION_PENDING_RETRY, NULL, + &state_process_handshake_retry_wait }, + { &state_process_handshake, EVENT_VALIDATION_FAILED, NULL, + &state_handshake_message_wait }, + { &state_process_handshake, EVENT_VALIDATION_OK, NULL, + &state_send_crypto_tokens_wait }, + { &state_process_handshake, EVENT_VALIDATION_OK_FINAL_MESSAGE, NULL, + &state_wait_crypto_tokens }, + /* ProcessHsRetryWait */ + { &state_process_handshake_retry_wait, EVENT_TIMEOUT, NULL, + &state_process_handshake }, + + { &state_send_crypto_tokens_wait, EVENT_TIMEOUT, NULL, + &state_send_crypto_tokens }, + { &state_send_crypto_tokens_wait, EVENT_RECV_CRYPTO_TOKENS, NULL, + &state_send_crypto_tokens_final }, + + { &state_send_crypto_tokens_final_wait, EVENT_TIMEOUT, NULL, + &state_send_crypto_tokens_final }, + + /* Process_handshake returned VALIDATION_OK_FINAL_MESSAGE notify user and wait for tokens */ + { &state_send_crypto_tokens, EVENT_VALIDATION_OK_FINAL_MESSAGE, NULL, + &state_wait_crypto_tokens }, + /* Process_handshake returned VALIDATION_OK notify user and goto ready state */ + { &state_send_crypto_tokens_final, EVENT_VALIDATION_OK, NULL, + &state_validation_ok }, + + { &state_handshake_final_resend, EVENT_AUTO, NULL, + &state_wait_crypto_tokens }, + + { &state_handshake_final_resend, EVENT_RECV_CRYPTO_TOKENS, NULL, + &state_send_crypto_tokens_final_wait }, + + { &state_wait_crypto_tokens, EVENT_RECV_CRYPTO_TOKENS, NULL, + &state_send_crypto_tokens_final_wait }, + + { &state_wait_crypto_tokens, EVENT_VALIDATION_OK, NULL, + &state_validation_ok }, + + { &state_wait_crypto_tokens, EVENT_RECEIVED_MESSAGE_REPLY, NULL, + &state_handshake_final_resend }, + + /* End */ + { &state_validation_ok, EVENT_AUTO, NULL, + NULL }, + { &state_validation_failed, EVENT_AUTO, NULL, + NULL }, +}; + + + +static bool send_handshake_message(const struct ddsi_handshake *handshake, DDS_Security_DataHolder *token, struct participant *pp, struct proxy_participant *proxypp, int request) +{ + bool ret = false; + nn_dataholderseq_t mdata; + DDS_Security_DataHolderSeq tseq; + + tseq._length = tseq._maximum = 1; + tseq._buffer = token; + + q_omg_shallow_copyout_DataHolderSeq(&mdata, &tseq); + + if (!(ret = write_auth_handshake_message(pp, proxypp, &mdata, request, &handshake->handshake_message_in_id))) + { + HSWARNING("Send handshake: failed to send message (lguid="PGUIDFMT" rguid="PGUIDFMT")", PGUID (pp->e.guid), PGUID (proxypp->e.guid)); + } + + q_omg_shallow_free_nn_dataholderseq(&mdata); + + return ret; +} + +static void func_validate_remote_identity(struct dds_security_fsm *fsm, void *arg) +{ + DDS_Security_ValidationResult_t ret; + DDS_Security_SecurityException exception = {0}; + struct ddsi_handshake *handshake = (struct ddsi_handshake*)arg; + dds_security_authentication *auth = handshake->auth; + struct participant *pp; + struct proxy_participant *proxypp; + DDS_Security_IdentityToken remote_identity_token; + int64_t remote_identity_handle; + ddsi_guid_t remote_guid; + + if (!validate_handshake(handshake, &pp, &proxypp)) + return; + + TRACE_FUNC(fsm); + + if (!(proxypp->plist->present & PP_IDENTITY_TOKEN)) + { + HSERROR("validate remote identity failed: remote participant ("PGUIDFMT") identity token missing", PGUID (proxypp->e.guid)); + ret = DDS_SECURITY_VALIDATION_FAILED; + goto ident_token_missing; + } + + remote_guid = nn_hton_guid(proxypp->e.guid); + q_omg_security_dataholder_copyout(&remote_identity_token, &proxypp->plist->identity_token); + + ddsrt_mutex_lock(&handshake->lock); + ret = auth->validate_remote_identity( + auth, &remote_identity_handle, &handshake->local_auth_request_token, handshake->remote_auth_request_token, + pp->sec_attr->local_identity_handle, &remote_identity_token, (DDS_Security_GUID_t *)&remote_guid, &exception); + ddsrt_mutex_unlock(&handshake->lock); + + /* Trace a failed handshake. */ + if ((ret != DDS_SECURITY_VALIDATION_OK ) && + (ret != DDS_SECURITY_VALIDATION_PENDING_RETRY ) && + (ret != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST) && + (ret != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE)) + { + HSEXCEPTION(&exception, "Validate remote identity failed"); + ret = DDS_SECURITY_VALIDATION_FAILED; + goto validation_failed; + } + + HSTRACE("FSM: validate_remote_identity (lguid="PGUIDFMT" rguid="PGUIDFMT") ret=%d\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid), ret); + + assert(proxypp->sec_attr->remote_identity_handle == 0 || proxypp->sec_attr->remote_identity_handle == remote_identity_handle); + proxypp->sec_attr->remote_identity_handle = remote_identity_handle; + + DDS_Security_DataHolder_deinit(&remote_identity_token); + + /* When validate_remote_identity returns a local_auth_request_token + * which does not equal TOKEN_NIL then an AUTH_REQUEST message has + * to be send. + */ + if (handshake->local_auth_request_token.class_id && strlen(handshake->local_auth_request_token.class_id) != 0) + (void)send_handshake_message(handshake, &handshake->local_auth_request_token, pp, proxypp, 1); + +validation_failed: +ident_token_missing: + /* Use return value as state machine event. */ + dds_security_fsm_dispatch(fsm, (int32_t)ret, true); +} + +static void func_handshake_init_message_resend(struct dds_security_fsm *fsm, void *arg) +{ + struct ddsi_handshake *handshake = arg; + struct participant *pp; + struct proxy_participant *proxypp; + + DDSRT_UNUSED_ARG(fsm); + + if (!validate_handshake(handshake, &pp, &proxypp)) + return; + + TRACE_FUNC(fsm); + + HSTRACE("FSM: handshake init_message_resend (lguid="PGUIDFMT" rguid="PGUIDFMT")\n", PGUID(pp->e.guid), PGUID(proxypp->e.guid)); + + if (strlen(handshake->local_auth_request_token.class_id) != 0) + (void)send_handshake_message(handshake, &handshake->local_auth_request_token, pp, proxypp, 1); +} + +static void func_begin_handshake_reply(struct dds_security_fsm *fsm, void *arg) +{ + DDS_Security_ValidationResult_t ret; + DDS_Security_SecurityException exception = {0}; + struct ddsi_handshake *handshake = arg; + dds_security_authentication *auth = handshake->auth; + struct participant *pp; + struct proxy_participant *proxypp; + + if (!validate_handshake(handshake, &pp, &proxypp)) + return; + + TRACE_FUNC(fsm); + + ddsrt_mutex_lock(&handshake->lock); + + if (handshake->handshake_message_out) + DDS_Security_DataHolder_free(handshake->handshake_message_out); + handshake->handshake_message_out = DDS_Security_DataHolder_alloc(); + + ret = auth->begin_handshake_reply( + auth, &(handshake->handshake_handle), handshake->handshake_message_out, &handshake->handshake_message_in_token, + proxypp->sec_attr->remote_identity_handle, pp->sec_attr->local_identity_handle, &handshake->pdata, &exception); + + ddsrt_mutex_unlock(&handshake->lock); + + HSTRACE("FSM: begin_handshake_reply (lguid="PGUIDFMT" rguid="PGUIDFMT") ret=%d\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid), ret); + + /* Trace a failed handshake. */ + if ((ret != DDS_SECURITY_VALIDATION_OK ) && + (ret != DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE ) && + (ret != DDS_SECURITY_VALIDATION_PENDING_RETRY ) && + (ret != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE)) + { + HSEXCEPTION(&exception, "Begin handshake reply failed"); + ret = DDS_SECURITY_VALIDATION_FAILED; + goto handshake_failed; + } + + if (ret == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + if (!send_handshake_message(handshake, handshake->handshake_message_out, pp, proxypp, 0)) { + ret = DDS_SECURITY_VALIDATION_FAILED; + goto handshake_failed; + } + } + else if (ret == DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE) + { + if (send_handshake_message(handshake, handshake->handshake_message_out, pp, proxypp, 0)) + ret = DDS_SECURITY_VALIDATION_OK; + else + { + ret = DDS_SECURITY_VALIDATION_FAILED; + goto handshake_failed; + } + } + + if (ret == DDS_SECURITY_VALIDATION_OK) + { + handshake->shared_secret = auth->get_shared_secret(auth, handshake->handshake_handle, &exception); + if (handshake->shared_secret == DDS_SECURITY_HANDLE_NIL) + { + HSEXCEPTION(&exception, "Getting shared secret failed"); + ret = DDS_SECURITY_VALIDATION_FAILED; + goto handshake_failed; + } + } + + dds_security_fsm_dispatch(fsm, (int32_t)ret, true); + return; + +handshake_failed: + DDS_Security_DataHolder_free(handshake->handshake_message_out); + handshake->handshake_message_out = NULL; + /* Use return value as state machine event. */ + dds_security_fsm_dispatch(fsm, (int32_t)ret, true); +} + +static void func_begin_handshake_request(struct dds_security_fsm *fsm, void *arg) +{ + DDS_Security_ValidationResult_t ret; + DDS_Security_SecurityException exception = {0}; + struct ddsi_handshake *handshake = arg; + dds_security_authentication *auth = handshake->auth; + struct participant *pp; + struct proxy_participant *proxypp; + + if (!validate_handshake(handshake, &pp, &proxypp)) + return; + + TRACE_FUNC(fsm); + + ddsrt_mutex_lock(&handshake->lock); + + if (handshake->handshake_message_out) + DDS_Security_DataHolder_free(handshake->handshake_message_out); + handshake->handshake_message_out = DDS_Security_DataHolder_alloc(); + + ret = auth->begin_handshake_request(auth, &(handshake->handshake_handle), handshake->handshake_message_out, pp->sec_attr->local_identity_handle, proxypp->sec_attr->remote_identity_handle, &handshake->pdata, &exception); + ddsrt_mutex_unlock(&handshake->lock); + + HSTRACE("FSM: begin_handshake_request (lguid="PGUIDFMT" rguid="PGUIDFMT") ret=%d\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid), ret); + + /* Trace a failed handshake. */ + if ((ret != DDS_SECURITY_VALIDATION_OK ) && + (ret != DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE ) && + (ret != DDS_SECURITY_VALIDATION_PENDING_RETRY ) && + (ret != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE)) + { + HSEXCEPTION(&exception, "Begin handshake request failed"); + ret = DDS_SECURITY_VALIDATION_FAILED; + goto handshake_failed; + } + + if (ret == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) + { + if (!send_handshake_message(handshake, handshake->handshake_message_out, pp, proxypp, 0)) + { + ret = DDS_SECURITY_VALIDATION_FAILED; + goto handshake_failed; + } + } + else if (ret == DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE) + { + if (send_handshake_message(handshake, handshake->handshake_message_out, pp, proxypp, 0)) + { + ret = DDS_SECURITY_VALIDATION_OK; + } else { + ret = DDS_SECURITY_VALIDATION_FAILED; + goto handshake_failed; + } + } + + if (ret == DDS_SECURITY_VALIDATION_OK) + { + handshake->shared_secret = auth->get_shared_secret(auth, handshake->handshake_handle, &exception); + if (handshake->shared_secret == DDS_SECURITY_HANDLE_NIL) + { + HSEXCEPTION(&exception, "Getting shared secret failed"); + ret = DDS_SECURITY_VALIDATION_FAILED; + goto handshake_failed; + } + } + + dds_security_fsm_dispatch(fsm, (int32_t)ret, true); + return; + +handshake_failed: + DDS_Security_DataHolder_free(handshake->handshake_message_out); + handshake->handshake_message_out = NULL; + /* Use return value as state machine event. */ + dds_security_fsm_dispatch(fsm, (int32_t)ret, true); +} + +static void func_process_handshake(struct dds_security_fsm *fsm, void *arg) +{ + DDS_Security_ValidationResult_t ret; + DDS_Security_SecurityException exception = {0}; + struct ddsi_handshake *handshake = arg; + dds_security_authentication *auth = handshake->auth; + struct participant *pp; + struct proxy_participant *proxypp; + + if (!validate_handshake(handshake, &pp, &proxypp)) + return; + + TRACE_FUNC(fsm); + + ddsrt_mutex_lock(&handshake->lock); + + if (handshake->handshake_message_out) + DDS_Security_DataHolder_free(handshake->handshake_message_out); + handshake->handshake_message_out = DDS_Security_DataHolder_alloc(); + + ret = auth->process_handshake(auth, handshake->handshake_message_out, &handshake->handshake_message_in_token, handshake->handshake_handle, &exception); + ddsrt_mutex_unlock(&handshake->lock); + + HSTRACE("FSM: process_handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") ret=%d\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid), ret); + + /* Trace a failed handshake. */ + if ((ret != DDS_SECURITY_VALIDATION_OK ) && + (ret != DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE ) && + (ret != DDS_SECURITY_VALIDATION_PENDING_RETRY )) + { + HSEXCEPTION(&exception, "Process handshake failed"); + ret = DDS_SECURITY_VALIDATION_FAILED; + goto handshake_failed; + } + + if ((ret == DDS_SECURITY_VALIDATION_OK) || (ret == DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE)) + { + handshake->shared_secret = auth->get_shared_secret(auth, handshake->handshake_handle, &exception); + if (handshake->shared_secret == DDS_SECURITY_HANDLE_NIL) + { + HSEXCEPTION(&exception, "Getting shared secret failed"); + ret = DDS_SECURITY_VALIDATION_FAILED; + goto handshake_failed; + } + handshake->end_cb(handshake, pp, proxypp, STATE_HANDSHAKE_PROCESSED); + } + + if (ret == DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE) + { + if (!send_handshake_message(handshake, handshake->handshake_message_out, pp, proxypp, 0)) + { + ret = DDS_SECURITY_VALIDATION_FAILED; + goto handshake_failed; + } + } + + dds_security_fsm_dispatch(fsm, (int32_t)ret, true); + return; + +handshake_failed: + DDS_Security_DataHolder_free(handshake->handshake_message_out); + handshake->handshake_message_out = NULL; + /* Use return value as state machine event. */ + dds_security_fsm_dispatch(fsm, (int32_t)ret, true); +} + +static void func_send_crypto_tokens(struct dds_security_fsm *fsm, void *arg) +{ + struct ddsi_handshake *handshake = arg; + struct participant *pp; + struct proxy_participant *proxypp; + + if (!validate_handshake(handshake, &pp, &proxypp)) + return; + + TRACE_FUNC(fsm); + + /* The final handshake message has been send to the remote + * participant. Call the callback function to signal that + * the corresponding crypto tokens can be send. Amd start + * waiting for the crypto tokens from the remote participant + */ + + HSTRACE("FSM: handshake send crypto tokens (lguid="PGUIDFMT" rguid="PGUIDFMT")\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid)); + handshake->end_cb(handshake, pp, proxypp, STATE_HANDSHAKE_SEND_TOKENS); + dds_security_fsm_dispatch(fsm, EVENT_VALIDATION_OK_FINAL_MESSAGE, true); +} + +static void func_send_crypto_tokens_final(struct dds_security_fsm *fsm, void *arg) +{ + struct ddsi_handshake *handshake = arg; + struct participant *pp; + struct proxy_participant *proxypp; + + if (!validate_handshake(handshake, &pp, &proxypp)) + return; + + TRACE_FUNC(fsm); + + /* The final handshake message has been send to the remote + * participant. Call the callback function to signal that + * the corresponding crypto tokens can be send. Amd start + * waiting for the crypto tokens from the remote participant + */ + + HSTRACE("FSM: handshake send crypto tokens final (lguid="PGUIDFMT" rguid="PGUIDFMT")\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid)); + handshake->end_cb(handshake, pp, proxypp, STATE_HANDSHAKE_SEND_TOKENS); + dds_security_fsm_dispatch(fsm, EVENT_VALIDATION_OK, true); +} + +static void func_handshake_message_resend(struct dds_security_fsm *fsm, void *arg) +{ + struct ddsi_handshake *handshake = arg; + struct participant *pp; + struct proxy_participant *proxypp; + + DDSRT_UNUSED_ARG(fsm); + DDSRT_UNUSED_ARG(arg); + + if (!validate_handshake(handshake, &pp, &proxypp)) + return; + + TRACE_FUNC(fsm); + + HSTRACE("handshake resend (lguid="PGUIDFMT" rguid="PGUIDFMT")\n", PGUID(pp->e.guid), PGUID(proxypp->e.guid)); + if (handshake->handshake_message_out) { + (void)send_handshake_message(handshake, handshake->handshake_message_out, pp, proxypp, 0); + } +} + +static void func_validation_ok(struct dds_security_fsm *fsm, void *arg) +{ + struct ddsi_handshake *handshake = arg; + struct participant *pp; + struct proxy_participant *proxypp; + + DDSRT_UNUSED_ARG(fsm); + + if (!validate_handshake(handshake, &pp, &proxypp)) + return; + + TRACE_FUNC(fsm); + + HSTRACE("FSM: handshake succeeded (lguid="PGUIDFMT" rguid="PGUIDFMT")\n", PGUID(pp->e.guid), PGUID(proxypp->e.guid)); + handshake->state = STATE_HANDSHAKE_OK; + handshake->end_cb(handshake, pp, proxypp, STATE_HANDSHAKE_OK); +} + +static void func_validation_failed(struct dds_security_fsm *fsm, void *arg) +{ + struct ddsi_handshake *handshake = arg; + struct participant *pp; + struct proxy_participant *proxypp; + + DDSRT_UNUSED_ARG(fsm); + + if (!validate_handshake(handshake, &pp, &proxypp)) + return; + + TRACE_FUNC(fsm); + + HSTRACE("FSM: handshake failed (lguid="PGUIDFMT" rguid="PGUIDFMT")\n", PGUID(pp->e.guid), PGUID(proxypp->e.guid)); + handshake->state = STATE_HANDSHAKE_FAILED; + handshake->end_cb(handshake, pp, proxypp, STATE_HANDSHAKE_FAILED); +} + +static void func_handshake_timeout(struct dds_security_fsm *fsm, void *arg) +{ + struct ddsi_handshake *handshake = arg; + struct participant *pp; + struct proxy_participant *proxypp; + + DDSRT_UNUSED_ARG(fsm); + + if (!validate_handshake(handshake, &pp, &proxypp)) + return; + + TRACE_FUNC(fsm); + + HSTRACE("FSM: handshake timeout (lguid="PGUIDFMT" rguid="PGUIDFMT")\n", PGUID(pp->e.guid), PGUID(proxypp->e.guid)); + handshake->state = STATE_HANDSHAKE_TIMED_OUT; + handshake->end_cb(handshake, pp, proxypp, STATE_HANDSHAKE_TIMED_OUT); +} + + +static struct ddsi_handshake * ddsi_handshake_create(struct participant *pp, struct proxy_participant *proxypp, ddsi_handshake_end_cb_t callback) +{ + const struct ddsi_domaingv * gv = pp->e.gv; + struct ddsi_hsadmin *hsadmin = pp->e.gv->hsadmin; + struct ddsi_handshake *handshake; + dds_return_t rc; + ddsi_octetseq_t pdata; + + TRACE_FUNC(NULL); + + handshake = ddsrt_malloc(sizeof(struct ddsi_handshake)); + memset(handshake, 0, sizeof(struct ddsi_handshake)); + + ddsrt_mutex_init(&handshake->lock); + handshake->auth = q_omg_participant_get_authentication(pp); + ddsrt_atomic_st32(&handshake->refc, 1); + ddsrt_atomic_st32(&handshake->deleting, 0); + handshake->participants.lguid = pp->e.guid; + handshake->participants.rguid = proxypp->e.guid; + handshake->gv = gv; + handshake->handshake_handle = 0; + handshake->shared_secret = 0; + auth_get_serialized_participant_data(pp, &pdata); + + handshake->pdata._length = handshake->pdata._maximum = pdata.length; + handshake->pdata._buffer = pdata.value; + + handshake->end_cb = callback; + + handshake->state = STATE_HANDSHAKE_IN_PROGRESS; + if (!hsadmin->fsm_control) + { + hsadmin->fsm_control = dds_security_fsm_control_create(pp->e.gv); + rc = dds_security_fsm_control_start(hsadmin->fsm_control, NULL); + if (rc < 0) + { + GVERROR("Failed to create FSM control"); + goto fsm_control_failed; + } + } + + handshake->fsm = dds_security_fsm_create(hsadmin->fsm_control, handshake_transistions, sizeof(handshake_transistions)/sizeof(handshake_transistions[0]), handshake); + if (!handshake->fsm) + { + GVERROR("Failed to create FSM"); + goto fsm_failed; + } + dds_security_fsm_set_timeout(handshake->fsm, func_handshake_timeout, AUTHENTICATION_TIMEOUT); + +#ifdef VERBOSE_HANDSHAKE_DEBUG + dds_security_fsm_set_debug(handshake->fsm, q_handshake_fsm_debug); +#endif + dds_security_fsm_start(handshake->fsm); + + return handshake; + +fsm_failed: +fsm_control_failed: + ddsrt_free(handshake); + return NULL; +} + +void ddsi_handshake_release(struct ddsi_handshake *handshake) +{ + if (!handshake) return; + + if (ddsrt_atomic_dec32_nv(&handshake->refc) == 0) + { + HSTRACE("handshake delete (lguid="PGUIDFMT" rguid="PGUIDFMT")\n", PGUID(handshake->participants.lguid), PGUID(handshake->participants.rguid)); + DDS_Security_DataHolder_deinit(&handshake->local_auth_request_token); + DDS_Security_DataHolder_deinit(&handshake->handshake_message_in_token); + DDS_Security_DataHolder_free(handshake->handshake_message_out); + DDS_Security_DataHolder_free(handshake->remote_auth_request_token); + DDS_Security_OctetSeq_deinit(&handshake->pdata); + ddsrt_mutex_destroy(&handshake->lock); + ddsrt_free(handshake); + } +} void ddsi_handshake_handle_message(struct ddsi_handshake *handshake, const struct participant *pp, const struct proxy_participant *proxypp, const struct nn_participant_generic_message *msg) { - DDSRT_UNUSED_ARG(handshake); + handshake_event_t event = EVENT_VALIDATION_FAILED; + DDSRT_UNUSED_ARG(pp); DDSRT_UNUSED_ARG(proxypp); - DDSRT_UNUSED_ARG(msg); + + assert(handshake); + assert(pp); + assert(proxypp); + assert(msg); + + TRACE_FUNC(handshake->fsm); + + if (!validate_handshake(handshake, NULL, NULL)) + return; + + HSTRACE ("FSM: handshake_handle_message (lguid="PGUIDFMT" rguid="PGUIDFMT") class_id=%s\n", + PGUID (pp->e.guid), PGUID (proxypp->e.guid), + msg->message_class_id ? msg->message_class_id: "NULL"); + + if (!msg->message_class_id || msg->message_data.n == 0 || !msg->message_data.tags[0].class_id) + { + HSERROR("received handshake message ("PGUIDFMT" --> "PGUIDFMT") does not contain a handshake message token\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid)); + goto invalid_message; + } + else if (strcmp(msg->message_class_id, DDS_SECURITY_AUTH_REQUEST) == 0) + { + if (strcmp(msg->message_data.tags[0].class_id, DDS_SECURITY_AUTH_REQUEST_TOKEN_CLASS_ID) == 0) + { + /* Note the state machine is started by discovery + * currently and not by the reception of an auth_request message which was send as the + * result of validate_remote_entity at the opposite participant + */ + ddsrt_mutex_lock(&handshake->lock); + if (handshake->remote_auth_request_token) + DDS_Security_DataHolder_free(handshake->remote_auth_request_token); + handshake->remote_auth_request_token = DDS_Security_DataHolder_alloc(); + q_omg_security_dataholder_copyout(handshake->remote_auth_request_token, &msg->message_data.tags[0]); + ddsrt_mutex_unlock(&handshake->lock); + } + else + { + HSERROR("received handshake message ("PGUIDFMT" --> "PGUIDFMT") does not contain a valid handshake message token\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid)); + } + } + else if (strcmp(msg->message_class_id, DDS_SECURITY_AUTH_HANDSHAKE) == 0) + { + if (msg->message_data.tags[0].class_id == NULL) + HSERROR("received handshake message ("PGUIDFMT" --> "PGUIDFMT") does not contain a valid handshake message token\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid)); + else if (strcmp(msg->message_data.tags[0].class_id, DDS_SECURITY_AUTH_HANDSHAKE_REQUEST_TOKEN_ID) == 0) + event = EVENT_RECEIVED_MESSAGE_REQUEST; + else if (strcmp(msg->message_data.tags[0].class_id, DDS_SECURITY_AUTH_HANDSHAKE_REPLY_TOKEN_ID) == 0) + event = EVENT_RECEIVED_MESSAGE_REPLY; + else if (strcmp(msg->message_data.tags[0].class_id, DDS_SECURITY_AUTH_HANDSHAKE_FINAL_TOKEN_ID) == 0) + event = EVENT_RECEIVED_MESSAGE_FINAL; + else + { + HSERROR("received handshake message ("PGUIDFMT" --> "PGUIDFMT") does not contain a valid handshake message token\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid)); + goto invalid_message; + } + + ddsrt_mutex_lock(&handshake->lock); + DDS_Security_DataHolder_deinit(&handshake->handshake_message_in_token); + q_omg_security_dataholder_copyout(&handshake->handshake_message_in_token, &msg->message_data.tags[0]); + memcpy(&handshake->handshake_message_in_id, &msg->message_identity, sizeof(handshake->handshake_message_in_id)); + handshake->handled_handshake_message = 0; + dds_security_fsm_dispatch(handshake->fsm, event, false); + ddsrt_mutex_unlock(&handshake->lock); + } + else + { + HSERROR("received handshake message ("PGUIDFMT" --> "PGUIDFMT") does not contain a valid message_class_id\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid)); + } + +invalid_message: + return; } void ddsi_handshake_crypto_tokens_received(struct ddsi_handshake *handshake) { - DDSRT_UNUSED_ARG(handshake); + struct participant *pp; + struct proxy_participant *proxypp; + + assert(handshake); + assert(handshake->fsm); + + if (!validate_handshake(handshake, &pp, &proxypp)) + return; + + HSTRACE("FSM: tokens received (lguid="PGUIDFMT" rguid="PGUIDFMT")\n", PGUID(pp->e.guid), PGUID(proxypp->e.guid)); + + dds_security_fsm_dispatch(handshake->fsm, EVENT_RECV_CRYPTO_TOKENS, false); } int64_t ddsi_handshake_get_shared_secret(const struct ddsi_handshake *handshake) { - DDSRT_UNUSED_ARG(handshake); - - return 0; + return handshake->shared_secret; } int64_t ddsi_handshake_get_handle(const struct ddsi_handshake *handshake) { - DDSRT_UNUSED_ARG(handshake); - - return 0; + return handshake->handshake_handle; } -void ddsi_handshake_register(const struct participant *pp, const struct proxy_participant *proxypp, ddsi_handshake_end_cb_t callback) +static struct ddsi_hsadmin * ddsi_handshake_admin_create(void) { - DDSRT_UNUSED_ARG(pp); - DDSRT_UNUSED_ARG(proxypp); - DDSRT_UNUSED_ARG(callback); + struct ddsi_hsadmin *admin; + + admin = ddsrt_malloc(sizeof(*admin)); + ddsrt_mutex_init(&admin->lock); + ddsrt_avl_init(&handshake_treedef, &admin->handshakes); + admin->fsm_control = NULL; + + return admin; } -void ddsi_handshake_remove(const struct participant *pp, const struct proxy_participant *proxypp, struct ddsi_handshake *handshake) +static void release_handshake(void *arg) { - DDSRT_UNUSED_ARG(pp); - DDSRT_UNUSED_ARG(proxypp); - DDSRT_UNUSED_ARG(handshake); + ddsi_handshake_release((struct ddsi_handshake *)arg); } -struct ddsi_handshake * ddsi_handshake_find(const struct participant *pp, const struct proxy_participant *proxypp) +static void ddsi_handshake_admin_delete(struct ddsi_hsadmin *hsadmin) { - DDSRT_UNUSED_ARG(pp); - DDSRT_UNUSED_ARG(proxypp); + if (hsadmin) + { + ddsrt_mutex_destroy(&hsadmin->lock); + ddsrt_avl_free(&handshake_treedef, &hsadmin->handshakes, release_handshake); + if (hsadmin->fsm_control) + { + dds_security_fsm_control_stop(hsadmin->fsm_control); + dds_security_fsm_control_free(hsadmin->fsm_control); + } + ddsrt_free(hsadmin); + } +} - return NULL; +static struct ddsi_handshake * ddsi_handshake_find_locked( + struct ddsi_hsadmin *hsadmin, + struct participant *pp, + struct proxy_participant *proxypp) +{ + struct handshake_entities handles; + + handles.lguid = pp->e.guid; + handles.rguid = proxypp->e.guid; + + return ddsrt_avl_lookup(&handshake_treedef, &hsadmin->handshakes, &handles); +} + +void ddsi_handshake_remove(struct participant *pp, struct proxy_participant *proxypp, struct ddsi_handshake *handshake) +{ + struct ddsi_hsadmin *hsadmin = pp->e.gv->hsadmin; + + ddsrt_mutex_lock(&hsadmin->lock); + if (!handshake) + handshake = ddsi_handshake_find_locked(hsadmin, pp, proxypp); + if (handshake) + { + ddsrt_avl_delete(&handshake_treedef, &hsadmin->handshakes, handshake); + ddsrt_atomic_st32(&handshake->deleting, 1); + } + ddsrt_mutex_unlock(&hsadmin->lock); + if (handshake && handshake->fsm) + dds_security_fsm_free(handshake->fsm); + ddsi_handshake_release(handshake); +} + +struct ddsi_handshake * ddsi_handshake_find(struct participant *pp, struct proxy_participant *proxypp) +{ + struct ddsi_hsadmin *hsadmin = pp->e.gv->hsadmin; + struct ddsi_handshake *handshake = NULL; + + ddsrt_mutex_lock(&hsadmin->lock); + handshake = ddsi_handshake_find_locked(hsadmin, pp, proxypp); + if (handshake) + ddsrt_atomic_inc32(&handshake->refc); + ddsrt_mutex_unlock(&hsadmin->lock); + + return handshake; +} + +void ddsi_handshake_register(struct participant *pp, struct proxy_participant *proxypp, ddsi_handshake_end_cb_t callback) +{ + struct ddsi_hsadmin *hsadmin = pp->e.gv->hsadmin; + struct ddsi_handshake *handshake = NULL; + + ddsrt_mutex_lock(&hsadmin->lock); + handshake = ddsi_handshake_find_locked(hsadmin, pp, proxypp); + if (!handshake) + { + handshake = ddsi_handshake_create(pp, proxypp, callback); + if (handshake) + ddsrt_avl_insert(&handshake_treedef, &hsadmin->handshakes, handshake); + } + ddsrt_mutex_unlock(&hsadmin->lock); +} + +void ddsi_handshake_admin_init(struct ddsi_domaingv *gv) +{ + assert(gv); + gv->hsadmin = ddsi_handshake_admin_create(); +} + +void ddsi_handshake_admin_deinit(struct ddsi_domaingv *gv) +{ + assert(gv); + ddsi_handshake_admin_delete(gv->hsadmin); } @@ -101,9 +1213,8 @@ extern inline void ddsi_handshake_release(UNUSED_ARG(struct ddsi_handshake *hand extern inline void ddsi_handshake_crypto_tokens_received(UNUSED_ARG(struct ddsi_handshake *handshake)); extern inline int64_t ddsi_handshake_get_shared_secret(UNUSED_ARG(const struct ddsi_handshake *handshake)); extern inline int64_t ddsi_handshake_get_handle(UNUSED_ARG(const struct ddsi_handshake *handshake)); -extern inline void ddsi_handshake_register(UNUSED_ARG(const struct participant *pp), UNUSED_ARG(const struct proxy_participant *proxypp), UNUSED_ARG(ddsi_handshake_end_cb_t callback)); -extern inline void ddsi_handshake_remove(UNUSED_ARG(const struct participant *pp), UNUSED_ARG(const struct proxy_participant *proxypp), UNUSED_ARG(struct ddsi_handshake *handshake)); -extern inline struct ddsi_handshake * ddsi_handshake_find(UNUSED_ARG(const struct participant *pp), UNUSED_ARG(const struct proxy_participant *proxypp)); - +extern inline void ddsi_handshake_register(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp), UNUSED_ARG(ddsi_handshake_end_cb_t callback)); +extern inline void ddsi_handshake_remove(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp), UNUSED_ARG(struct ddsi_handshake *handshake)); +extern inline struct ddsi_handshake * ddsi_handshake_find(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp)); #endif /* DDSI_INCLUDE_DDS_SECURITY */ diff --git a/src/core/ddsi/src/ddsi_plist.c b/src/core/ddsi/src/ddsi_plist.c index d2243f6..9722e02 100644 --- a/src/core/ddsi/src/ddsi_plist.c +++ b/src/core/ddsi/src/ddsi_plist.c @@ -106,7 +106,7 @@ struct piddesc { const enum pserop desc[12]; struct { dds_return_t (*deser) (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff); - dds_return_t (*ser) (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff); + dds_return_t (*ser) (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff, bool be); dds_return_t (*unalias) (void * __restrict dst, size_t * __restrict dstoff); dds_return_t (*fini) (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag); dds_return_t (*valid) (const void *src, size_t srcoff); @@ -289,17 +289,19 @@ static dds_return_t deser_reliability (void * __restrict dst, size_t * __restric return 0; } -static dds_return_t ser_reliability (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff) +static dds_return_t ser_reliability (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff, bool be) { +#define BO4U(x) ((be) ? ddsrt_toBE4u((x)) : (x)) DDSRT_STATIC_ASSERT (DDS_EXTERNAL_RELIABILITY_BEST_EFFORT == 1 && DDS_EXTERNAL_RELIABILITY_RELIABLE == 2 && DDS_RELIABILITY_BEST_EFFORT == 0 && DDS_RELIABILITY_RELIABLE == 1); dds_reliability_qospolicy_t const * const x = deser_generic_src (src, &srcoff, alignof (dds_reliability_qospolicy_t)); ddsi_duration_t mbt = nn_to_ddsi_duration (x->max_blocking_time); - uint32_t * const p = nn_xmsg_addpar (xmsg, pid, 3 * sizeof (uint32_t)); - p[0] = 1 + (uint32_t) x->kind; - p[1] = (uint32_t) mbt.seconds; - p[2] = mbt.fraction; + uint32_t * const p = nn_xmsg_addpar_bo (xmsg, pid, 3 * sizeof (uint32_t), be); + p[0] = BO4U(1 + (uint32_t) x->kind); + p[1] = BO4U((uint32_t) mbt.seconds); + p[2] = BO4U(mbt.fraction); return 0; +#undef BO4U } static dds_return_t valid_reliability (const void *src, size_t srcoff) @@ -340,10 +342,10 @@ static dds_return_t deser_statusinfo (void * __restrict dst, size_t * __restrict return 0; } -static dds_return_t ser_statusinfo (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff) +static dds_return_t ser_statusinfo (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff, bool be) { uint32_t const * const x = deser_generic_src (src, &srcoff, alignof (uint32_t)); - uint32_t * const p = nn_xmsg_addpar (xmsg, pid, sizeof (uint32_t)); + uint32_t * const p = nn_xmsg_addpar_bo (xmsg, pid, sizeof (uint32_t), be); *p = ddsrt_toBE4u (*x); return 0; } @@ -374,14 +376,16 @@ static dds_return_t deser_locator (void * __restrict dst, size_t * __restrict ds return 0; } -static dds_return_t ser_locator (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff) +static dds_return_t ser_locator (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff, bool be) { nn_locators_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_locators_t)); for (const struct nn_locators_one *l = x->first; l != NULL; l = l->next) { - char * const p = nn_xmsg_addpar (xmsg, pid, 24); - memcpy (p, &l->loc.kind, 4); - memcpy (p + 4, &l->loc.port, 4); + char * const p = nn_xmsg_addpar_bo (xmsg, pid, 24, be); + const int32_t kind = be ? ddsrt_toBE4 (l->loc.kind) : l->loc.kind; + const uint32_t port = be ? ddsrt_toBE4u (l->loc.port) : l->loc.port; + memcpy (p, &kind, 4); + memcpy (p + 4, &port, 4); memcpy (p + 8, l->loc.address, 16); } return 0; @@ -854,8 +858,12 @@ static uint32_t ser_generic_count (const ddsi_octetseq_t *src, size_t elem_size, return count; } -static dds_return_t ser_generic_embeddable (char * const data, size_t *dstoff, const void *src, size_t srcoff, const enum pserop * __restrict desc) +static dds_return_t ser_generic_embeddable (char * const data, size_t *dstoff, const void *src, size_t srcoff, const enum pserop * __restrict desc, bool be) { +#define BO4(x) (be ? ddsrt_toBE4((x)) : (x)) +#define BO4U(x) (be ? ddsrt_toBE4u((x)) : (x)) +#define BO8(x) (be ? ddsrt_toBE8((x)) : (x)) + while (true) { switch (*desc) @@ -865,7 +873,7 @@ static dds_return_t ser_generic_embeddable (char * const data, size_t *dstoff, c case XO: { /* octet sequence */ ddsi_octetseq_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_octetseq_t)); char * const p = ser_generic_align4 (data, dstoff); - *((uint32_t *) p) = x->length; + *((uint32_t *) p) = BO4U(x->length); if (x->length) memcpy (p + 4, x->value, x->length); *dstoff += 4 + x->length; srcoff += sizeof (*x); @@ -875,7 +883,7 @@ static dds_return_t ser_generic_embeddable (char * const data, size_t *dstoff, c char const * const * const x = deser_generic_src (src, &srcoff, alignof (char *)); const uint32_t size = (uint32_t) (strlen (*x) + 1); char * const p = ser_generic_align4 (data, dstoff); - *((uint32_t *) p) = size; + *((uint32_t *) p) = BO4U(size); memcpy (p + 4, *x, size); *dstoff += 4 + size; srcoff += sizeof (*x); @@ -884,7 +892,7 @@ static dds_return_t ser_generic_embeddable (char * const data, size_t *dstoff, c case XE1: case XE2: case XE3: { /* enum */ unsigned const * const x = deser_generic_src (src, &srcoff, alignof (unsigned)); uint32_t * const p = ser_generic_align4 (data, dstoff); - *p = (uint32_t) *x; + *p = BO4U((uint32_t) *x); *dstoff += 4; srcoff += sizeof (*x); break; @@ -894,7 +902,7 @@ static dds_return_t ser_generic_embeddable (char * const data, size_t *dstoff, c const uint32_t cnt = 1 + (uint32_t) (*desc - Xi); int32_t * const p = ser_generic_align4 (data, dstoff); for (uint32_t i = 0; i < cnt; i++) - p[i] = x[i]; + p[i] = BO4(x[i]); *dstoff += cnt * sizeof (*x); srcoff += cnt * sizeof (*x); break; @@ -904,7 +912,7 @@ static dds_return_t ser_generic_embeddable (char * const data, size_t *dstoff, c const uint32_t cnt = 1 + (uint32_t) (*desc - Xu); uint32_t * const p = ser_generic_align4 (data, dstoff); for (uint32_t i = 0; i < cnt; i++) - p[i] = x[i]; + p[i] = BO4U(x[i]); *dstoff += cnt * sizeof (*x); srcoff += cnt * sizeof (*x); break; @@ -912,7 +920,7 @@ static dds_return_t ser_generic_embeddable (char * const data, size_t *dstoff, c case Xl: { /* int64_t */ int64_t const * const x = deser_generic_src (src, &srcoff, alignof (int64_t)); int64_t * const p = ser_generic_align8 (data, dstoff); - *p = *x; + *p = BO8(*x); *dstoff += sizeof (*x); srcoff += sizeof (*x); break; @@ -924,8 +932,8 @@ static dds_return_t ser_generic_embeddable (char * const data, size_t *dstoff, c for (uint32_t i = 0; i < cnt; i++) { ddsi_duration_t tmp = nn_to_ddsi_duration (x[i]); - p[2 * i + 0] = (uint32_t) tmp.seconds; - p[2 * i + 1] = tmp.fraction; + p[2 * i + 0] = BO4U((uint32_t) tmp.seconds); + p[2 * i + 1] = BO4U(tmp.fraction); } *dstoff += 2 * cnt * sizeof (uint32_t); srcoff += cnt * sizeof (*x); @@ -981,9 +989,9 @@ static dds_return_t ser_generic_embeddable (char * const data, size_t *dstoff, c else { const size_t elem_size = ser_generic_srcsize (desc + 1); - *((uint32_t *) p) = ser_generic_count (x, elem_size, desc + 1); + *((uint32_t *) p) = BO4U(ser_generic_count (x, elem_size, desc + 1)); for (uint32_t i = 0; i < x->length; i++) - ser_generic_embeddable (data, dstoff, x->value, i * elem_size, desc + 1); + ser_generic_embeddable (data, dstoff, x->value, i * elem_size, desc + 1, be); } srcoff += sizeof (*x); break; @@ -993,13 +1001,18 @@ static dds_return_t ser_generic_embeddable (char * const data, size_t *dstoff, c } desc = pserop_advance(desc); } +#undef BO4 +#undef BO4U +#undef BO8 } -static dds_return_t ser_generic (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff, const enum pserop * __restrict desc) + + +static dds_return_t ser_generic (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff, const enum pserop * __restrict desc, bool be) { - char * const data = nn_xmsg_addpar (xmsg, pid, ser_generic_size (src, srcoff, desc)); + char * const data = nn_xmsg_addpar_bo (xmsg, pid, ser_generic_size (src, srcoff, desc), be); size_t dstoff = 0; - return ser_generic_embeddable (data, &dstoff, src, srcoff, desc); + return ser_generic_embeddable (data, &dstoff, src, srcoff, desc, be); } dds_return_t plist_ser_generic (void **dst, size_t *dstsize, const void *src, const enum pserop * __restrict desc) @@ -1010,7 +1023,7 @@ dds_return_t plist_ser_generic (void **dst, size_t *dstsize, const void *src, co *dstsize = ser_generic_size (src, srcoff, desc); if ((*dst = ddsrt_malloc (*dstsize == 0 ? 1 : *dstsize)) == NULL) return DDS_RETCODE_OUT_OF_RESOURCES; - ret = ser_generic_embeddable (*dst, &dstoff, src, srcoff, desc); + ret = ser_generic_embeddable (*dst, &dstoff, src, srcoff, desc, false); assert (dstoff == *dstsize); return ret; } @@ -1987,7 +2000,7 @@ static void plist_or_xqos_mergein_missing (void * __restrict dst, const void * _ assert ((*qfs_dst.aliased & ~ aliased_dst_inq) == 0); } -static void plist_or_xqos_addtomsg (struct nn_xmsg *xmsg, const void * __restrict src, size_t shift, uint64_t pwanted, uint64_t qwanted) +static void plist_or_xqos_addtomsg (struct nn_xmsg *xmsg, const void * __restrict src, size_t shift, uint64_t pwanted, uint64_t qwanted, bool be) { /* shift == 0: plist, shift > 0: just qos */ uint64_t pw, qw; @@ -2017,9 +2030,9 @@ static void plist_or_xqos_addtomsg (struct nn_xmsg *xmsg, const void * __restric assert (shift == 0 || entry->plist_offset - shift < sizeof (dds_qos_t)); size_t srcoff = entry->plist_offset - shift; if (!(entry->flags & PDF_FUNCTION)) - ser_generic (xmsg, entry->pid, src, srcoff, entry->op.desc); + ser_generic (xmsg, entry->pid, src, srcoff, entry->op.desc, be); else - entry->op.f.ser (xmsg, entry->pid, src, srcoff); + entry->op.f.ser (xmsg, entry->pid, src, srcoff, be); } } } @@ -3333,12 +3346,17 @@ static int partitions_equal (const void *srca, const void *srcb, size_t off) void ddsi_xqos_addtomsg (struct nn_xmsg *m, const dds_qos_t *xqos, uint64_t wanted) { - plist_or_xqos_addtomsg (m, xqos, offsetof (struct ddsi_plist, qos), 0, wanted); + plist_or_xqos_addtomsg (m, xqos, offsetof (struct ddsi_plist, qos), 0, wanted, false); +} + +void ddsi_plist_addtomsg_bo (struct nn_xmsg *m, const ddsi_plist_t *ps, uint64_t pwanted, uint64_t qwanted, bool be) +{ + plist_or_xqos_addtomsg (m, ps, 0, pwanted, qwanted, be); } void ddsi_plist_addtomsg (struct nn_xmsg *m, const ddsi_plist_t *ps, uint64_t pwanted, uint64_t qwanted) { - plist_or_xqos_addtomsg (m, ps, 0, pwanted, qwanted); + plist_or_xqos_addtomsg (m, ps, 0, pwanted, qwanted, false); } /*************************/ diff --git a/src/core/ddsi/src/ddsi_security_exchange.c b/src/core/ddsi/src/ddsi_security_exchange.c new file mode 100644 index 0000000..c583f71 --- /dev/null +++ b/src/core/ddsi/src/ddsi_security_exchange.c @@ -0,0 +1,428 @@ +/* + * 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_SECURITY + +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/md5.h" + +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/ddsi/ddsi_entity_index.h" +#include "dds/ddsi/ddsi_security_exchange.h" +#include "dds/ddsi/ddsi_serdata_default.h" +#include "dds/ddsi/ddsi_security_omg.h" +#include "dds/ddsi/ddsi_handshake.h" +#include "dds/ddsi/q_ddsi_discovery.h" +#include "dds/ddsi/ddsi_tkmap.h" +#include "dds/ddsi/q_xmsg.h" +#include "dds/ddsi/q_transmit.h" +#include "dds/ddsi/q_log.h" +#include "dds/ddsi/q_bswap.h" + +//#define SECURITY_LOG_MESSAGE_DATA + +#ifdef SECURITY_LOG_MESSAGE_DATA +static void nn_property_seq_log(struct ddsi_domaingv *gv, const dds_propertyseq_t *seq) +{ + uint32_t i; + + GVTRACE("{"); + for (i = 0; i < seq->n; i++) { + GVTRACE("n=%s,v=%s", seq->props[i].name, seq->props[i].value); + } + GVTRACE("}"); +} + +static void nn_binary_property_seq_log(struct ddsi_domaingv *gv, const dds_binarypropertyseq_t *seq) +{ + uint32_t i; + + GVTRACE("{"); + for (i = 0; i < seq->n; i++) { + uint32_t j; + GVTRACE("n=%s,v={", seq->props[i].name); + for (j = 0; j < seq->props[i].value.length; j++) { + GVTRACE("%02x", seq->props[i].value.value[j]); + } + GVTRACE("}"); + } + GVTRACE("}"); +} + +static void nn_dataholder_seq_log(struct ddsi_domaingv *gv, const char *prefix, const nn_dataholderseq_t *dhseq) +{ + uint32_t i; + + GVTRACE("%s={", prefix); + for (i = 0; i < dhseq->n; i++) { + GVTRACE("cid=%s,", dhseq->tags[i].class_id); + nn_property_seq_log(gv, &dhseq->tags[i].properties); + GVTRACE(","); + nn_binary_property_seq_log(gv, &dhseq->tags[i].binary_properties); + } + GVTRACE("}"); +} +#endif + +static void nn_participant_generic_message_log(struct ddsi_domaingv *gv, const struct nn_participant_generic_message *msg, int conv) +{ + ddsi_guid_t spguid = conv ? nn_ntoh_guid(msg->message_identity.source_guid ): msg->message_identity.source_guid; + ddsi_guid_t rmguid = conv ? nn_ntoh_guid(msg->related_message_identity.source_guid) : msg->related_message_identity.source_guid; + ddsi_guid_t dpguid = conv ? nn_ntoh_guid(msg->destination_participant_guid) : msg->destination_participant_guid; + ddsi_guid_t deguid = conv ? nn_ntoh_guid(msg->destination_endpoint_guid) : msg->destination_endpoint_guid; + ddsi_guid_t seguid = conv ? nn_ntoh_guid(msg->source_endpoint_guid) : msg->source_endpoint_guid; + + GVTRACE (" msg="); + GVTRACE("mi=" PGUIDFMT "#%" PRId64 ",", PGUID(spguid), msg->message_identity.sequence_number); + GVTRACE("rmi=" PGUIDFMT "#%" PRId64 ",", PGUID(rmguid), msg->related_message_identity.sequence_number); + GVTRACE("dpg=" PGUIDFMT ",", PGUID(dpguid)); + GVTRACE("deg=" PGUIDFMT ",", PGUID(deguid)); + GVTRACE("seg=" PGUIDFMT ",", PGUID(seguid)); + GVTRACE("cid=%s", msg->message_class_id); +#ifdef SECURITY_LOG_MESSAGE_DATA + nn_dataholder_seq_log(gv, ",mdata", &msg->message_data); +#endif + GVTRACE ("\n"); +} + +bool write_auth_handshake_message(const struct participant *pp, const struct proxy_participant *proxypp, nn_dataholderseq_t *mdata, bool request, const nn_message_identity_t *related_message_id) +{ + struct ddsi_domaingv *gv = pp->e.gv; + struct nn_participant_generic_message pmg; + struct ddsi_serdata *serdata; + unsigned char *blob; + size_t len; + struct writer *wr; + int64_t seq; + struct proxy_reader *prd; + ddsi_guid_t prd_guid; + bool result = false; + + if ((wr = get_builtin_writer (pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER)) == NULL) { + GVTRACE ("write_handshake("PGUIDFMT") - builtin stateless message writer not found", PGUID (pp->e.guid)); + return false; + } + + prd_guid.prefix = proxypp->e.guid.prefix; + prd_guid.entityid.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER; + if ((prd = entidx_lookup_proxy_reader_guid (gv->entity_index, &prd_guid)) == NULL) { + GVTRACE ("write_handshake("PGUIDFMT") - builtin stateless message proxy reader not found", PGUID (prd_guid)); + return false; + } + + ddsrt_mutex_lock (&wr->e.lock); + seq = ++wr->seq; + + if (request) { + nn_participant_generic_message_init(&pmg, &wr->e.guid, seq, &proxypp->e.guid, NULL, NULL, DDS_SECURITY_AUTH_REQUEST, mdata, NULL); + } else { + nn_participant_generic_message_init(&pmg, &wr->e.guid, seq, &proxypp->e.guid, NULL, NULL, DDS_SECURITY_AUTH_HANDSHAKE, mdata, related_message_id); + } + + if (nn_participant_generic_message_serialize(&pmg, &blob, &len) != DDS_RETCODE_OK) + return false; + + GVTRACE("write_handshake("PGUIDFMT" --> "PGUIDFMT")(lguid="PGUIDFMT" rguid="PGUIDFMT") ", + PGUID (wr->e.guid), PGUID (prd_guid), + PGUID (pp->e.guid), PGUID (proxypp->e.guid)); + nn_participant_generic_message_log(gv, &pmg, 1); + + struct ddsi_rawcdr_sample raw = { + .blob = blob, + .size = len, + .key = NULL, + .keysize = 0 + }; + serdata = ddsi_serdata_from_sample (gv->rawcdr_topic, SDK_DATA, &raw); + serdata->timestamp = now (); + + result = enqueue_sample_wrlock_held (wr, seq, NULL, serdata, prd, 1) == 0; + ddsi_serdata_unref (serdata); + dds_free(blob); + + ddsrt_mutex_unlock (&wr->e.lock); + nn_participant_generic_message_deinit(&pmg); + + return result; +} + +void auth_get_serialized_participant_data(struct participant *pp, ddsi_octetseq_t *seq) +{ + struct nn_xmsg *mpayload; + size_t sz; + char *payload; + + mpayload = nn_xmsg_new (pp->e.gv->xmsgpool, &pp->e.guid, pp, 0, NN_XMSG_KIND_DATA); + + get_participant_builtin_topic_data(pp, mpayload, true); + payload = nn_xmsg_payload (&sz, mpayload); + + seq->length = (uint32_t)sz; + seq->value = ddsrt_malloc(sz); + memcpy(seq->value, payload, sz); + nn_xmsg_free (mpayload); +} + +void handle_auth_handshake_message(const struct receiver_state *rst, ddsi_entityid_t wr_entity_id, nn_wctime_t timestamp, unsigned statusinfo, const void *vdata, size_t len) +{ + const struct CDRHeader *hdr = vdata; /* built-ins not deserialized (yet) */ + const bool bswap = (hdr->identifier == CDR_LE) ^ DDSRT_LITTLE_ENDIAN; + const void *data = (void *) (hdr + 1); + size_t size = (len - sizeof(struct CDRHeader)); + struct nn_participant_generic_message msg; + struct participant *pp = NULL; + struct proxy_writer *pwr = NULL; + ddsi_guid_t guid; + ddsi_guid_t *pwr_guid; + struct ddsi_handshake *handshake; + + DDSRT_UNUSED_ARG(wr_entity_id); + DDSRT_UNUSED_ARG(timestamp); + + RSTTRACE ("recv_handshake ST%x", statusinfo); + if ((hdr->identifier != CDR_LE) && (hdr->identifier != PL_CDR_LE) && + (hdr->identifier != CDR_BE) && (hdr->identifier != PL_CDR_BE)) + { + RSTTRACE (" data->identifier %d !?\n", ntohs (hdr->identifier)); + return; + } + + if (nn_participant_generic_message_deseralize(&msg, data, size, bswap) < 0) + { + RSTTRACE ("deserialize failed\n"); + goto err_deser; + } + + nn_participant_generic_message_log(rst->gv, &msg, 0); + + if (msg.message_identity.source_guid.entityid.u == NN_ENTITYID_PARTICIPANT) + { + guid = msg.message_identity.source_guid; + guid.entityid.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER; + pwr_guid= &guid; + } + else if (msg.message_identity.source_guid.entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER) + { + pwr_guid= &msg.message_identity.source_guid; + } + else + { + RSTTRACE ("invalid source entity id\n"); + goto invalid_source; + } + + if ((pp = entidx_lookup_participant_guid(rst->gv->entity_index, &msg.destination_participant_guid)) == NULL) + { + RSTTRACE ("destination participant ("PGUIDFMT") not found\n", PGUID(msg.destination_participant_guid)); + } + else if ((pwr = entidx_lookup_proxy_writer_guid(rst->gv->entity_index, pwr_guid)) == NULL) + { + RSTTRACE ("proxy writer ("PGUIDFMT") not found\n", PGUID(*pwr_guid)); + } + else if ((handshake = ddsi_handshake_find(pp, pwr->c.proxypp)) == NULL) + { + RSTTRACE ("handshake not found ("PGUIDFMT" --> "PGUIDFMT")\n", PGUID (pwr->c.proxypp->e.guid), PGUID(pp->e.guid)); + } + else + { +// RSTTRACE (" ("PGUIDFMT" --> "PGUIDFMT")\n", PGUID (pwr->c.proxypp->e.guid), PGUID (pp->e.guid)); + ddsi_handshake_handle_message(handshake, pp, pwr->c.proxypp, &msg); + ddsi_handshake_release(handshake); + } + +invalid_source: + nn_participant_generic_message_deinit(&msg); +err_deser: + return; +} + +static bool write_crypto_exchange_message(const struct participant *pp, const ddsi_guid_t *dst_pguid, const ddsi_guid_t *src_eguid, const ddsi_guid_t *dst_eguid, const char *classid, const nn_dataholderseq_t *tokens) +{ + struct ddsi_domaingv * const gv = pp->e.gv; + struct nn_participant_generic_message pmg; + struct ddsi_tkmap_instance *tk; + struct ddsi_serdata *serdata; + struct proxy_reader *prd; + ddsi_guid_t prd_guid; + unsigned char *data; + size_t len; + struct writer *wr; + seqno_t seq; + int r; + + if ((wr = get_builtin_writer (pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER)) == NULL) + { + GVLOG (DDS_LC_DISCOVERY, "write_crypto_exchange_message("PGUIDFMT") - builtin volatile secure writer not found\n", PGUID (pp->e.guid)); + return false; + } + + prd_guid.prefix = dst_pguid->prefix; + prd_guid.entityid.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER; + if ((prd = entidx_lookup_proxy_reader_guid (gv->entity_index, &prd_guid)) == NULL) + return false; + + GVLOG (DDS_LC_DISCOVERY, "send crypto tokens("PGUIDFMT" --> "PGUIDFMT")\n", PGUID (wr->e.guid), PGUID (prd_guid)); + + ddsrt_mutex_lock (&wr->e.lock); + seq = ++wr->seq; + + /* Get serialized message. */ + nn_participant_generic_message_init(&pmg, &wr->e.guid, seq, dst_pguid, dst_eguid, src_eguid, classid, tokens, NULL); + nn_participant_generic_message_serialize(&pmg, &data, &len); + + /* Get the key value. */ + ddsrt_md5_state_t md5st; + ddsrt_md5_byte_t digest[16]; + ddsrt_md5_init (&md5st); + ddsrt_md5_append (&md5st, (const ddsrt_md5_byte_t *)data, sizeof (nn_message_identity_t)); + ddsrt_md5_finish (&md5st, digest); + + /* Write the sample. */ + struct ddsi_rawcdr_sample raw = { + .blob = data, + .size = len, + .key = digest, + .keysize = 16 + }; + serdata = ddsi_serdata_from_sample (gv->rawcdr_topic, SDK_DATA, &raw); + tk = ddsi_tkmap_lookup_instance_ref (gv->m_tkmap, serdata); + ddsrt_mutex_unlock (&wr->e.lock); + ddsrt_free(data); + + r = write_sample_p2p_wrlock_held(wr, seq, NULL, serdata, tk, prd); + ddsi_tkmap_instance_unref (gv->m_tkmap, tk); + ddsi_serdata_unref (serdata); + + nn_participant_generic_message_deinit(&pmg); + + return (r < 0 ? false : true); +} + +bool write_crypto_participant_tokens(const struct participant *pp, const struct proxy_participant *proxypp, const nn_dataholderseq_t *tokens) +{ + return write_crypto_exchange_message(pp, &proxypp->e.guid, NULL, NULL, GMCLASSID_SECURITY_PARTICIPANT_CRYPTO_TOKENS, tokens); +} + +bool write_crypto_writer_tokens(const struct writer *wr, const struct proxy_reader *prd, const nn_dataholderseq_t *tokens) +{ + struct participant *pp = wr->c.pp; + struct proxy_participant *proxypp = prd->c.proxypp; + + return write_crypto_exchange_message(pp, &proxypp->e.guid, &wr->e.guid, &prd->e.guid, GMCLASSID_SECURITY_DATAWRITER_CRYPTO_TOKENS, tokens); +} + +bool write_crypto_reader_tokens(const struct reader *rd, const struct proxy_writer *pwr, const nn_dataholderseq_t *tokens) +{ + struct participant *pp = rd->c.pp; + struct proxy_participant *proxypp = pwr->c.proxypp; + + return write_crypto_exchange_message(pp, &proxypp->e.guid, &rd->e.guid, &pwr->e.guid, GMCLASSID_SECURITY_DATAREADER_CRYPTO_TOKENS, tokens); +} + +void handle_crypto_exchange_message(const struct receiver_state *rst, ddsi_entityid_t wr_entity_id, nn_wctime_t timestamp, unsigned statusinfo, const void *vdata, unsigned len) +{ + struct ddsi_domaingv *gv = rst->gv; + const struct CDRHeader *hdr = vdata; /* built-ins not deserialized (yet) */ + const int bswap = (hdr->identifier == CDR_LE) ^ DDSRT_LITTLE_ENDIAN; + const void *data = (void *) (hdr + 1); + unsigned size = (unsigned)(len - sizeof(struct CDRHeader)); + struct nn_participant_generic_message msg; + ddsi_guid_t rd_guid; + ddsi_guid_t pwr_guid; + ddsi_guid_t proxypp_guid; + struct participant *pp; + struct proxy_participant *proxypp; + + DDSRT_UNUSED_ARG(timestamp); + + rd_guid.prefix = rst->dst_guid_prefix; + rd_guid.entityid.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER; + pwr_guid.prefix = rst->src_guid_prefix; + pwr_guid.entityid = wr_entity_id; + + GVTRACE ("recv crypto tokens ("PGUIDFMT" --> "PGUIDFMT") ST%x", PGUID (pwr_guid), PGUID (rd_guid), statusinfo); + + memset(&msg, 0, sizeof(msg)); + if (nn_participant_generic_message_deseralize(&msg, data, size, bswap) < 0) + goto deser_msg_failed; + + nn_participant_generic_message_log(gv, &msg, 0); + + if (!msg.message_class_id) + { + ddsi_guid_t guid; + guid.prefix = rst->dst_guid_prefix; + guid.entityid.u = NN_ENTITYID_PARTICIPANT; + GVWARNING("participant "PGUIDFMT" received a crypto exchange message with empty class_id", PGUID(guid)); + goto invalid_msg; + } + + proxypp_guid.prefix = msg.message_identity.source_guid.prefix; + proxypp_guid.entityid.u = NN_ENTITYID_PARTICIPANT; + + if (strcmp(GMCLASSID_SECURITY_PARTICIPANT_CRYPTO_TOKENS, msg.message_class_id) == 0) + { + pp = entidx_lookup_participant_guid(gv->entity_index, &msg.destination_participant_guid); + if (!pp) + { + GVWARNING("received a crypto exchange message from "PGUIDFMT" with participant unknown "PGUIDFMT, PGUID(proxypp_guid), PGUID(msg.destination_participant_guid)); + goto invalid_msg; + } + proxypp = entidx_lookup_proxy_participant_guid(gv->entity_index, &proxypp_guid); + if (!proxypp) + { + GVWARNING("received a crypto exchange message from "PGUIDFMT" with proxy participant unknown "PGUIDFMT, PGUID(proxypp_guid), PGUID(msg.destination_participant_guid)); + goto invalid_msg; + } + q_omg_security_set_participant_crypto_tokens(pp, proxypp, &msg.message_data); + } + else if (strcmp(GMCLASSID_SECURITY_DATAWRITER_CRYPTO_TOKENS, msg.message_class_id) == 0) + { + struct reader *rd; + + rd = entidx_lookup_reader_guid(gv->entity_index, &msg.destination_endpoint_guid); + if (!rd) + { + GVWARNING("received a crypto exchange message from "PGUIDFMT" with reader unknown "PGUIDFMT, PGUID(proxypp_guid), PGUID(msg.destination_participant_guid)); + goto invalid_msg; + } + q_omg_security_set_remote_writer_crypto_tokens(rd, &msg.source_endpoint_guid, &msg.message_data); + } + else if (strcmp(GMCLASSID_SECURITY_DATAREADER_CRYPTO_TOKENS, msg.message_class_id) == 0) + { + struct writer *wr; + + wr = entidx_lookup_writer_guid(gv->entity_index, &msg.destination_endpoint_guid); + if (!wr) + { + GVWARNING("received a crypto exchange message from "PGUIDFMT" with writer unknown "PGUIDFMT, PGUID(proxypp_guid), PGUID(msg.destination_participant_guid)); + goto invalid_msg; + } + q_omg_security_set_remote_reader_crypto_tokens(wr, &msg.source_endpoint_guid, &msg.message_data); + } + else + { + ddsi_guid_t guid; + guid.prefix = rst->dst_guid_prefix; + guid.entityid.u = NN_ENTITYID_PARTICIPANT; + GVWARNING("participant "PGUIDFMT" received a crypto exchange message with unknown class_id", PGUID(guid)); + } + +invalid_msg: + nn_participant_generic_message_deinit(&msg); +deser_msg_failed: + return; +} + + +#endif /* DDSI_INCLUDE_SECURITY */ diff --git a/src/core/ddsi/src/ddsi_security_msg.c b/src/core/ddsi/src/ddsi_security_msg.c index a0bbe77..8838327 100644 --- a/src/core/ddsi/src/ddsi_security_msg.c +++ b/src/core/ddsi/src/ddsi_security_msg.c @@ -14,7 +14,6 @@ #include "dds/ddsrt/md5.h" #include "dds/ddsrt/heap.h" #include "dds/ddsrt/string.h" -#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_transmit.h" @@ -23,6 +22,9 @@ #include "dds/ddsi/ddsi_entity_index.h" #include "dds/ddsi/ddsi_security_msg.h" #include "dds/ddsi/ddsi_plist_generic.h" +#include "dds/ddsi/ddsi_plist.h" +#include "dds/security/core/dds_security_utils.h" + const enum pserop pserop_participant_generic_message[] = { @@ -56,6 +58,8 @@ alias_simple_sequence(ddsi_octetseq_t *dst, const ddsi_octetseq_t *src, size_t e /* Even when aliased, sequence buffers are not shared. */ dst->value = ddsrt_memdup(src->value, src->length * elem_size); } + else + dst->value = NULL; } static void @@ -83,6 +87,8 @@ alias_dataholderseq(nn_dataholderseq_t *dst, const nn_dataholderseq_t *src) alias_dataholder(&(dst->tags[i]), &(src->tags[i])); } } + else + dst->tags = NULL; } void @@ -155,76 +161,6 @@ nn_participant_generic_message_deseralize( return plist_deser_generic (msg, data, len, bswap, pserop_participant_generic_message); } -int -write_crypto_exchange_message( - const struct participant *pp, - const ddsi_guid_t *dst_pguid, - const ddsi_guid_t *src_eguid, - const ddsi_guid_t *dst_eguid, - const char *classid, - const nn_dataholderseq_t *tokens) -{ - struct ddsi_domaingv * const gv = pp->e.gv; - struct nn_participant_generic_message pmg; - struct ddsi_tkmap_instance *tk; - struct ddsi_serdata *serdata; - struct proxy_reader *prd; - ddsi_guid_t prd_guid; - unsigned char *data; - size_t len; - struct writer *wr; - seqno_t seq; - int r; - - if ((wr = get_builtin_writer (pp, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER)) == NULL) - { - GVLOG (DDS_LC_DISCOVERY, "write_crypto_exchange_message("PGUIDFMT") - builtin volatile secure writer not found\n", PGUID (pp->e.guid)); - return -1; - } - - prd_guid.prefix = dst_pguid->prefix; - prd_guid.entityid.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER; - if ((prd = entidx_lookup_proxy_reader_guid (gv->entity_index, &prd_guid)) == NULL) - { - return -1; - } - - GVLOG (DDS_LC_DISCOVERY, "send crypto tokens("PGUIDFMT" --> "PGUIDFMT")\n", PGUID (wr->e.guid), PGUID (prd_guid)); - - ddsrt_mutex_lock (&wr->e.lock); - seq = ++wr->seq; - - /* Get serialized message. */ - nn_participant_generic_message_init(&pmg, &wr->e.guid, seq, dst_pguid, dst_eguid, src_eguid, classid, tokens, NULL); - nn_participant_generic_message_serialize(&pmg, &data, &len); - - /* Get the key value. */ - ddsrt_md5_state_t md5st; - ddsrt_md5_byte_t digest[16]; - ddsrt_md5_init (&md5st); - ddsrt_md5_append (&md5st, (const ddsrt_md5_byte_t *)data, sizeof (nn_message_identity_t)); - ddsrt_md5_finish (&md5st, digest); - - /* Write the sample. */ - struct ddsi_rawcdr_sample raw = { - .blob = data, - .size = len, - .key = digest, - .keysize = 16 - }; - serdata = ddsi_serdata_from_sample (gv->rawcdr_topic, SDK_DATA, &raw); - tk = ddsi_tkmap_lookup_instance_ref (gv->m_tkmap, serdata); - r = write_sample_p2p_wrlock_held(wr, seq, NULL, serdata, tk, prd); - ddsi_tkmap_instance_unref (gv->m_tkmap, tk); - ddsi_serdata_unref (serdata); - - nn_participant_generic_message_deinit(&pmg); - - ddsrt_mutex_unlock (&wr->e.lock); - - return r; -} - int volatile_secure_data_filter(struct writer *wr, struct proxy_reader *prd, struct ddsi_serdata *serdata) { static const size_t guid_offset = offsetof(nn_participant_generic_message_t, destination_participant_guid); @@ -239,7 +175,8 @@ int volatile_secure_data_filter(struct writer *wr, struct proxy_reader *prd, str assert(prd); assert(serdata); - (void)ddsi_serdata_to_ser_ref(serdata, guid_offset, sizeof(ddsi_guid_t), &guid_ref); + /* guid_offset + 4 because 4 bytes header is at 0 */ + (void)ddsi_serdata_to_ser_ref(serdata, guid_offset + 4, sizeof(ddsi_guid_t), &guid_ref); assert(guid_ref.iov_len == sizeof(ddsi_guid_t)); assert(guid_ref.iov_base); msg_guid = (ddsi_guid_t*)guid_ref.iov_base; diff --git a/src/core/ddsi/src/ddsi_security_omg.c b/src/core/ddsi/src/ddsi_security_omg.c index f118f41..8e3808d 100644 --- a/src/core/ddsi/src/ddsi_security_omg.c +++ b/src/core/ddsi/src/ddsi_security_omg.c @@ -12,17 +12,24 @@ #ifdef DDSI_INCLUDE_SECURITY #include +#include -#include "dds/ddsrt/misc.h" #include "dds/ddsrt/heap.h" -#include "dds/ddsrt/bswap.h" #include "dds/ddsrt/string.h" -#include "dds/ddsrt/process.h" +#include "dds/ddsrt/misc.h" +#include "dds/ddsrt/avl.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_radmin.h" +#include "dds/ddsi/q_misc.h" #include "dds/ddsi/ddsi_entity_index.h" +#include "dds/ddsi/ddsi_security_msg.h" #include "dds/ddsi/ddsi_security_omg.h" +#include "dds/ddsi/ddsi_security_util.h" +#include "dds/ddsi/ddsi_security_exchange.h" +#include "dds/ddsi/ddsi_handshake.h" #include "dds/ddsi/ddsi_sertopic.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_log.h" @@ -35,30 +42,79 @@ #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_xevent.h" #include "dds/ddsi/ddsi_plist.h" +#include "dds/ddsi/sysdeps.h" #define AUTH_NAME "Authentication" #define AC_NAME "Access Control" #define CRYPTO_NAME "Cryptographic" -#define SECURITY_EXCEPTION_INIT {NULL, 0, 0} +#define EXCEPTION_LOG(sc,e,cat, ...) \ + q_omg_log_exception(sc->logcfg, cat, e, __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) -struct dds_security_context { - dds_security_plugin auth_plugin; - dds_security_plugin ac_plugin; - dds_security_plugin crypto_plugin; +#define EXCEPTION_ERROR(s, e, ...) EXCEPTION_LOG(s, e, DDS_LC_ERROR, __VA_ARGS__) +#define EXCEPTION_WARNING(s, e, ...) EXCEPTION_LOG(s, e, DDS_LC_WARNING, __VA_ARGS__) - dds_security_authentication *authentication_context; - dds_security_cryptography *crypto_context; - dds_security_access_control *access_control_context; - ddsrt_mutex_t omg_security_lock; - uint32_t next_plugin_id; - const struct ddsrt_log_cfg *logcfg; -}; +#define SECURITY_ATTR_IS_VALID(attr) \ + ((attr) & NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID) -typedef struct dds_security_context dds_security_context; +/* Security attributes are compatible ... */ +#define SECURITY_ATTR_COMPATIBLE(attr_a, attr_b, is_valid_flag) \ +( \ + /* ... if masks are equal ... */ \ + (attr_a == attr_b) \ + || \ + /* ... or if either of the masks is not valid ... */ \ + (((attr_a & is_valid_flag) == 0) || ((attr_b & is_valid_flag) == 0)) \ +) -static bool q_omg_writer_is_payload_protected (const struct writer *wr); +/* Security information are compatible ... */ +#define SECURITY_INFO_COMPATIBLE(info_a, info_b, is_valid_flag) \ +( \ + /* ... if plugin attributes are compatible ... */ \ + SECURITY_ATTR_COMPATIBLE(info_a.plugin_security_attributes, \ + info_b.plugin_security_attributes, \ + is_valid_flag) \ + && \ + /* ... and spec attributes are compatible ... */ \ + SECURITY_ATTR_COMPATIBLE(info_a.security_attributes, \ + info_b.security_attributes, \ + is_valid_flag) \ +) + +/* Security information indicates clear data ... */ +#define SECURITY_INFO_CLEAR(info, is_valid_flag) \ +( \ + /* ... if no flag was set (ignoring the is_valid flag) ... */ \ + (info.security_attributes & (~is_valid_flag)) == 0 \ +) + +#define SECURITY_INFO_IS_RTPS_PROTECTED(info) \ +( \ + (info.security_attributes & NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_VALID ) && \ + (info.security_attributes & NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_RTPS_PROTECTED) \ +) + +#define SECURITY_INFO_IS_WRITE_PROTECTED(info) \ +( \ + (info.security_attributes & NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID ) && \ + (info.security_attributes & NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_WRITE_PROTECTED) \ +) + +#define SECURITY_INFO_IS_READ_PROTECTED(info) \ +( \ + (info.security_attributes & NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID ) && \ + (info.security_attributes & NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_READ_PROTECTED ) \ +) + +#define SECURITY_INFO_IS_RTPS_PROTECTED(info) \ +( \ + (info.security_attributes & NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_VALID ) && \ + (info.security_attributes & NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_RTPS_PROTECTED) \ +) + +#define SECURITY_INFO_USE_RTPS_AUTHENTICATION(info) \ + ((info).plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED) static bool endpoint_is_DCPSParticipantSecure (const ddsi_guid_t *guid) { @@ -92,14 +148,415 @@ static bool endpoint_is_DCPSParticipantMessageSecure (const ddsi_guid_t *guid) static bool endpoint_is_DCPSParticipantVolatileMessageSecure (const ddsi_guid_t *guid) { -#if 1 - /* TODO: volatile endpoint. */ - DDSRT_UNUSED_ARG(guid); - return false; -#else return ((guid->entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER) || (guid->entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER)); -#endif +} + +struct participant_sec_index { + ddsrt_mutex_t lock; + ddsrt_avl_ctree_t participants; +}; + +struct dds_security_context { + dds_security_plugin auth_plugin; + dds_security_plugin ac_plugin; + dds_security_plugin crypto_plugin; + + dds_security_authentication *authentication_context; + dds_security_cryptography *crypto_context; + dds_security_access_control *access_control_context; + ddsrt_mutex_t omg_security_lock; + uint32_t next_plugin_id; + + struct participant_sec_index partiticpant_index; + + const struct ddsrt_log_cfg *logcfg; +}; + +typedef struct dds_security_context dds_security_context; + +static int compare_guid(const void *va, const void *vb); +static int compare_crypto_handle (const void *va, const void *vb); +static int compare_guid_pair(const void *va, const void *vb); + +const ddsrt_avl_ctreedef_t pp_proxypp_treedef = + DDSRT_AVL_CTREEDEF_INITIALIZER (offsetof (struct pp_proxypp_match, avlnode), offsetof (struct pp_proxypp_match, proxypp_guid), compare_guid, 0); +const ddsrt_avl_treedef_t proxypp_pp_treedef = + DDSRT_AVL_TREEDEF_INITIALIZER (offsetof (struct proxypp_pp_match, avlnode), offsetof (struct proxypp_pp_match, pp_crypto_handle), compare_crypto_handle, 0); +const ddsrt_avl_treedef_t entity_match_treedef = + DDSRT_AVL_TREEDEF_INITIALIZER (offsetof (struct security_entity_match, avlnode), offsetof (struct security_entity_match, guids), compare_guid_pair, 0); +const ddsrt_avl_ctreedef_t participant_index_treedef = + DDSRT_AVL_CTREEDEF_INITIALIZER (offsetof (struct participant_sec_attributes, avlnode), offsetof (struct participant_sec_attributes, crypto_handle), compare_crypto_handle, 0); + +static int compare_crypto_handle (const void *va, const void *vb) +{ + const DDS_Security_ParticipantCryptoHandle *ha = va; + const DDS_Security_ParticipantCryptoHandle *hb = vb; + + return ((*ha > *hb) ? 1 : (*ha < *hb) ? -1 : 0); +} + +static int guid_compare (const ddsi_guid_t *guid1, const ddsi_guid_t *guid2) +{ + return memcmp (guid1, guid2, sizeof (ddsi_guid_t)); +} + +static int compare_guid(const void *va, const void *vb) +{ + const ddsi_guid_t *ga = va; + const ddsi_guid_t *gb = vb; + + return guid_compare(ga, gb); +} + +static int compare_guid_pair(const void *va, const void *vb) +{ + const struct guid_pair *na = va; + const struct guid_pair *nb = vb; + int r; + + if ((r = guid_compare(&na->src, &nb->src)) == 0) + r = guid_compare(&na->dst, &nb->dst); + return r; +} + +static struct dds_security_context * q_omg_security_get_secure_context(const struct participant *pp) +{ + if (pp && pp->e.gv->security_context && q_omg_is_security_loaded(pp->e.gv->security_context)) + return pp->e.gv->security_context; + return NULL; +} + +struct dds_security_authentication *q_omg_participant_get_authentication(const struct participant *pp) +{ + if (pp && pp->e.gv->security_context && q_omg_is_security_loaded(pp->e.gv->security_context)) + return pp->e.gv->security_context->authentication_context; + return NULL; +} + +static struct dds_security_context * q_omg_security_get_secure_context_from_proxypp(const struct proxy_participant *proxypp) +{ + if (proxypp && proxypp->e.gv->security_context && q_omg_is_security_loaded(proxypp->e.gv->security_context)) + return proxypp->e.gv->security_context; + return NULL; +} + +void q_omg_log_exception(const struct ddsrt_log_cfg *lc, uint32_t cat, DDS_Security_SecurityException *exception, const char *file, uint32_t line, const char *func, const char *fmt, ...) +{ + char logbuffer[512]; + va_list ap; + int l; + + va_start (ap, fmt); + l = vsnprintf(logbuffer, sizeof(logbuffer), fmt, ap); + va_end (ap); + if ((size_t) l >= sizeof(logbuffer)) + { + logbuffer[sizeof(logbuffer)-1] = '\0'; + } + dds_log_cfg(lc, cat, file, line, func, "%s: %s(code: %d)\n", logbuffer, exception->message ? exception->message : "", exception->code); + DDS_Security_Exception_reset(exception); +} + +static struct security_entity_match * entity_match_new(const ddsi_guid_t *src, const ddsi_guid_t *dst) +{ + struct security_entity_match *match; + + match = ddsrt_malloc(sizeof(*match)); + match->guids.src = *src; + match->guids.dst = *dst; + match->matched = false; + match->crypto_handle = 0; + match->tokens = NULL; + + return match; +} + +static void entity_match_free(struct security_entity_match *match) +{ + if (match) { + if (match->tokens) + DDS_Security_ParticipantCryptoTokenSeq_free(match->tokens); + ddsrt_free(match); + } +} + +static struct security_entity_match * find_entity_match_locked(struct dds_security_match_index *list, const ddsi_guid_t *src, const ddsi_guid_t *dst) +{ + struct guid_pair guids; + + guids.src = *src; + guids.dst = *dst; + + return ddsrt_avl_lookup(&entity_match_treedef, &list->matches, &guids); +} + +static struct security_entity_match * find_or_create_entity_match(struct dds_security_match_index *list, const ddsi_guid_t *src, const ddsi_guid_t *dst) +{ + struct security_entity_match *match; + + ddsrt_mutex_lock(&list->lock); + match = find_entity_match_locked(list, src, dst); + if (!match) + { + match = entity_match_new(src, dst); + ddsrt_avl_insert(&entity_match_treedef, &list->matches, match); + } + ddsrt_mutex_unlock(&list->lock); + + return match; +} + +static struct security_entity_match * remove_entity_match(struct dds_security_match_index *list, const ddsi_guid_t *src, const ddsi_guid_t *dst) +{ + struct security_entity_match *match; + struct guid_pair guids; + ddsrt_avl_dpath_t path; + + guids.src = *src; + guids.dst = *dst; + + ddsrt_mutex_lock(&list->lock); + match = ddsrt_avl_lookup_dpath(&entity_match_treedef, &list->matches, &guids, &path); + if (match) + ddsrt_avl_delete_dpath(&entity_match_treedef, &list->matches, match, &path); + ddsrt_mutex_unlock(&list->lock); + + return match; +} + +static struct dds_security_match_index * security_match_index_new(void) +{ + struct dds_security_match_index *list; + + list = ddsrt_malloc (sizeof(*list)); + ddsrt_mutex_init (&list->lock); + ddsrt_avl_init (&entity_match_treedef, &list->matches); + return list; +} + +static void entity_match_free_wrapper(void *arg) +{ + struct security_entity_match *match = arg; + entity_match_free(match); +} + +static void security_match_index_free(struct dds_security_match_index *list) +{ + if (list) + { + ddsrt_avl_free (&entity_match_treedef, &list->matches, entity_match_free_wrapper); + ddsrt_mutex_destroy(&list->lock); + ddsrt_free(list); + } +} + +static struct pp_proxypp_match * pp_proxypp_match_new(struct proxy_participant *proxypp, DDS_Security_ParticipantCryptoHandle proxypp_crypto_handle) +{ + struct pp_proxypp_match *pm; + + pm = ddsrt_malloc(sizeof(*pm)); + pm->proxypp_guid = proxypp->e.guid; + pm->proxypp_crypto_handle = proxypp_crypto_handle; + + return pm; +} + +static void pp_proxypp_match_free(struct dds_security_context *sc, struct pp_proxypp_match *pm) +{ + DDSRT_UNUSED_ARG(sc); + + ddsrt_free(pm); +} + +static struct proxypp_pp_match * proxypp_pp_match_new(struct participant *pp, DDS_Security_PermissionsHandle permissions_hdl, DDS_Security_SharedSecretHandle shared_secret) +{ + struct proxypp_pp_match *pm; + + pm = ddsrt_malloc(sizeof(*pm)); + pm->pp_guid = pp->e.guid; + pm->pp_crypto_handle = pp->sec_attr->crypto_handle; + pm->permissions_handle = permissions_hdl; + pm->shared_secret = shared_secret; + + return pm; +} + +static void proxypp_pp_match_free(struct dds_security_context *sc, struct proxypp_pp_match *pm) +{ + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + + if (pm->permissions_handle != DDS_SECURITY_HANDLE_NIL) + { + if (!sc->access_control_context->return_permissions_handle(sc->access_control_context, pm->permissions_handle, &exception)) + EXCEPTION_ERROR(sc, &exception, "Failed to return remote permissions handle"); + } + ddsrt_free(pm); +} + +static void pp_proxypp_unrelate(struct dds_security_context *sc, struct participant *pp, const ddsi_guid_t *proxypp_guid) +{ + struct pp_proxypp_match *pm; + ddsrt_avl_dpath_t dpath; + + ddsrt_mutex_lock(&pp->sec_attr->lock); + if ((pm = ddsrt_avl_clookup_dpath(&pp_proxypp_treedef, &pp->sec_attr->proxy_participants, proxypp_guid, &dpath)) != NULL) + { + ddsrt_avl_cdelete_dpath(&pp_proxypp_treedef, &pp->sec_attr->proxy_participants, pm, &dpath); + pp_proxypp_match_free(sc, pm); + } + ddsrt_mutex_unlock(&pp->sec_attr->lock); +} + +static void proxypp_pp_unrelate(struct dds_security_context *sc, struct proxy_participant *proxypp, const ddsi_guid_t *pp_guid, int64_t pp_crypto_handle) +{ + if (proxypp->sec_attr) + { + struct proxypp_pp_match *pm; + struct security_entity_match *match; + ddsrt_avl_dpath_t dpath; + + match = remove_entity_match(proxypp->e.gv->security_matches, &proxypp->e.guid, pp_guid); + if (match) + entity_match_free(match); + + ddsrt_mutex_lock(&proxypp->sec_attr->lock); + if ((pm = ddsrt_avl_lookup_dpath(&proxypp_pp_treedef, &proxypp->sec_attr->participants, &pp_crypto_handle, &dpath)) != NULL) + { + ddsrt_avl_delete_dpath(&proxypp_pp_treedef, &proxypp->sec_attr->participants, pm, &dpath); + proxypp_pp_match_free(sc, pm); + } + ddsrt_mutex_unlock(&proxypp->sec_attr->lock); + } +} + +static struct participant_sec_attributes * participant_sec_attributes_new(ddsi_guid_t *guid) +{ + struct participant_sec_attributes *attr; + + attr = ddsrt_malloc(sizeof(*attr)); + ddsrt_mutex_init(&attr->lock); + ddsrt_avl_cinit(&pp_proxypp_treedef, &attr->proxy_participants); + attr->pp_guid = *guid; + attr->crypto_handle = DDS_SECURITY_HANDLE_NIL; + attr->plugin_attr = false; + attr->initialized = false; + return attr; +} + +static void participant_sec_attributes_free(struct participant_sec_attributes *attr) +{ + if (attr) + { + ddsrt_avl_cfree(&pp_proxypp_treedef, &attr->proxy_participants, 0); + ddsrt_mutex_destroy(&attr->lock); + ddsrt_free(attr); + } +} + +static struct writer_sec_attributes * writer_sec_attributes_new(void) +{ + struct writer_sec_attributes *attr; + + attr = ddsrt_malloc(sizeof(*attr)); + memset(attr, 0, sizeof(*attr)); + attr->crypto_handle = DDS_SECURITY_HANDLE_NIL; + attr->plugin_attr = false; + return attr; +} + +static void writer_sec_attributes_free(struct writer_sec_attributes *attr) +{ + ddsrt_free(attr); +} + +static struct reader_sec_attributes * reader_sec_attributes_new(void) +{ + struct reader_sec_attributes *attr; + + attr = ddsrt_malloc(sizeof(*attr)); + memset(attr, 0, sizeof(*attr)); + attr->crypto_handle = DDS_SECURITY_HANDLE_NIL; + attr->plugin_attr = false; + + return attr; +} + +static void reader_sec_attributes_free(struct reader_sec_attributes *attr) +{ + ddsrt_free(attr); +} + +static void +participant_index_add(dds_security_context *sc, struct participant_sec_attributes *attr) +{ + ddsrt_mutex_lock(&sc->partiticpant_index.lock); + ddsrt_avl_cinsert(&participant_index_treedef, &sc->partiticpant_index.participants, attr); + ddsrt_mutex_unlock(&sc->partiticpant_index.lock); +} + +static struct participant_sec_attributes * +participant_index_find(dds_security_context *sc, int64_t crypto_handle) +{ + struct participant_sec_attributes *attr; + + ddsrt_mutex_lock(&sc->partiticpant_index.lock); + attr = ddsrt_avl_clookup(&participant_index_treedef, &sc->partiticpant_index.participants, &crypto_handle); + ddsrt_mutex_unlock(&sc->partiticpant_index.lock); + + return attr; +} + +static struct participant_sec_attributes * +participant_index_remove(dds_security_context *sc, int64_t crypto_handle) +{ + struct participant_sec_attributes *attr; + ddsrt_avl_dpath_t dpath; + + ddsrt_mutex_lock(&sc->partiticpant_index.lock); + attr = ddsrt_avl_clookup_dpath(&participant_index_treedef, &sc->partiticpant_index.participants, &crypto_handle, &dpath); + if (attr) + ddsrt_avl_cdelete_dpath(&participant_index_treedef, &sc->partiticpant_index.participants, attr, &dpath); + ddsrt_mutex_unlock(&sc->partiticpant_index.lock); + + return attr; +} + +static uint32_t +get_matched_proxypp_crypto_handles(struct participant_sec_attributes *attr, DDS_Security_ParticipantCryptoHandleSeq *hdls) +{ + uint32_t i; + struct pp_proxypp_match *pm; + ddsrt_avl_citer_t it; + + ddsrt_mutex_lock(&attr->lock); + hdls->_length = hdls->_maximum = (uint32_t)ddsrt_avl_ccount(&attr->proxy_participants); + hdls->_buffer = NULL; + if (hdls->_length == 0) + { + ddsrt_mutex_unlock(&attr->lock); + return 0; + } + hdls->_buffer = ddsrt_malloc(hdls->_length * sizeof(int64_t)); + for (pm = ddsrt_avl_citer_first(&pp_proxypp_treedef, &attr->proxy_participants, &it), i = 0; pm; pm = ddsrt_avl_citer_next(&it), i++) + hdls->_buffer[i] = pm->proxypp_crypto_handle; + ddsrt_mutex_unlock(&attr->lock); + return hdls->_length; +} + +static int64_t +get_first_matched_proxypp_crypto_handle(struct participant_sec_attributes *attr) +{ + int64_t handle = 0; + struct pp_proxypp_match *pm; + + ddsrt_mutex_lock(&attr->lock); + pm = ddsrt_avl_croot(&pp_proxypp_treedef, &attr->proxy_participants); + if (pm) + handle = pm->proxypp_crypto_handle; + ddsrt_mutex_unlock(&attr->lock); + + return handle; } bool q_omg_is_security_loaded (dds_security_context *sc) @@ -107,22 +564,27 @@ bool q_omg_is_security_loaded (dds_security_context *sc) return (sc->crypto_context != NULL || sc->authentication_context != NULL || sc->access_control_context != NULL); } -void q_omg_security_init (dds_security_context **sc, const struct ddsrt_log_cfg *logcfg) +void q_omg_security_init (struct ddsi_domaingv *gv) { - *sc = ddsrt_malloc (sizeof (dds_security_context)); - memset (*sc, 0, sizeof (dds_security_context)); + dds_security_context *sc; - (*sc)->auth_plugin.name = AUTH_NAME; - (*sc)->ac_plugin.name = AC_NAME; - (*sc)->crypto_plugin.name = CRYPTO_NAME; + sc = ddsrt_malloc (sizeof (dds_security_context)); + memset (sc, 0, sizeof (dds_security_context)); - ddsrt_mutex_init (&(*sc)->omg_security_lock); - (*sc)->logcfg = logcfg; + sc->auth_plugin.name = AUTH_NAME; + sc->ac_plugin.name = AC_NAME; + sc->crypto_plugin.name = CRYPTO_NAME; - //DDS_CTRACE ((*sc)->logcfg, "DDS Security init\n"); -#if HANDSHAKE_IMPLEMENTED - //remote_participant_crypto_handle_list_init(); -#endif + ddsrt_mutex_init(&sc->partiticpant_index.lock); + ddsrt_avl_cinit(&participant_index_treedef, &sc->partiticpant_index.participants); + + ddsrt_mutex_init (&sc->omg_security_lock); + sc->logcfg = &gv->logconfig; + + gv->security_context = sc; + gv->security_matches = security_match_index_new(); + + ddsi_handshake_admin_init(gv); } /** @@ -130,42 +592,42 @@ void q_omg_security_init (dds_security_context **sc, const struct ddsrt_log_cfg */ static void release_plugins (dds_security_context *sc) { -#if HANDSHAKE_IMPLEMENTED - q_handshake_terminate (); -#endif - if (dds_security_plugin_release (&sc->auth_plugin, sc->authentication_context)) - DDS_CERROR (sc->logcfg, "Error occured releasing %s plugin", sc->auth_plugin.name); + DDS_CERROR (sc->logcfg, "Error occurred releasing %s plugin", sc->auth_plugin.name); if (dds_security_plugin_release (&sc->crypto_plugin, sc->crypto_context)) - DDS_CERROR (sc->logcfg, "Error occured releasing %s plugin", sc->crypto_plugin.name); + DDS_CERROR (sc->logcfg, "Error occurred releasing %s plugin", sc->crypto_plugin.name); if (dds_security_plugin_release (&sc->ac_plugin, sc->access_control_context)) - DDS_CERROR (sc->logcfg, "Error occured releasing %s plugin", sc->ac_plugin.name); + DDS_CERROR (sc->logcfg, "Error occurred releasing %s plugin", sc->ac_plugin.name); sc->authentication_context = NULL; sc->access_control_context = NULL; sc->crypto_context = NULL; } -void q_omg_security_deinit (struct dds_security_context **sc) +void q_omg_security_deinit (struct ddsi_domaingv *gv) { - assert (sc != NULL); - assert (*sc != NULL); + dds_security_context *sc = gv->security_context; -#if HANDSHAKE_IMPLEMENTED - //remote_participant_crypto_handle_list_deinit(); -#endif + assert (gv->security_context != NULL); - if ((*sc)->authentication_context != NULL && (*sc)->access_control_context != NULL && (*sc)->crypto_context != NULL){ - release_plugins (*sc); + ddsrt_avl_cfree(&participant_index_treedef, &sc->partiticpant_index.participants, 0); + ddsrt_mutex_destroy(&sc->partiticpant_index.lock); + + if (gv->security_context->authentication_context != NULL && gv->security_context->access_control_context != NULL && gv->security_context->crypto_context != NULL){ + release_plugins (gv->security_context); } - ddsrt_mutex_destroy (&(*sc)->omg_security_lock); + ddsi_handshake_admin_deinit(gv); - //DDS_CTRACE ((*sc)->logcfg, "DDS Security deinit\n"); - ddsrt_free (*sc); - *sc = NULL; + security_match_index_free(gv->security_matches); + gv->security_matches = NULL; + + ddsrt_mutex_destroy (&gv->security_context->omg_security_lock); + + ddsrt_free(gv->security_context); + gv->security_context = NULL; } static void dds_qos_to_security_plugin_configuration (const dds_qos_t *qos, dds_security_plugin_suite_config *suite_config) @@ -278,99 +740,738 @@ error: return DDS_RETCODE_ERROR; } -bool q_omg_participant_is_secure (const struct participant *pp) +static const char * get_builtin_topic_name(ddsi_entityid_t id) { - /* TODO: Register local participant. */ - DDSRT_UNUSED_ARG (pp); - return false; + switch (id.u) { + case NN_ENTITYID_SEDP_BUILTIN_TOPIC_WRITER: + case NN_ENTITYID_SEDP_BUILTIN_TOPIC_READER: + return "DCPSTopic"; + break; + case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER: + case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER: + return "DCPSPublication"; + break; + case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER: + case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_READER: + return "DCPSSubscription"; + break; + case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER: + case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER: + return "DCPSParticipant"; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER: + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER: + return "DCPSParticipantMessage"; + break; + case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER: + case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_READER: + return "DCPSPublicationsSecure"; + break; + case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER: + case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER: + return "DCPSSubscriptionsSecure"; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER: + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER: + return "DCPSParticipantStatelessMessage"; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER: + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER: + return "DCPSParticipantMessageSecure"; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER: + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER: + return "DCPSParticipantVolatileMessageSecure"; + break; + case NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER: + case NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_READER: + return "DCPSParticipantsSecure"; + break; + default: + return "(null)"; + break; + } + + return NULL; +} + +static void notify_handshake_recv_token(struct participant *pp, struct proxy_participant *proxypp) +{ + struct ddsi_handshake *handshake; + + handshake = ddsi_handshake_find(pp, proxypp); + if (handshake) { + ddsi_handshake_crypto_tokens_received(handshake); + ddsi_handshake_release(handshake); + } +} + +static const char * get_reader_topic_name(struct reader *rd) +{ + if (rd->topic) { + return rd->topic->name; + } + return get_builtin_topic_name(rd->e.guid.entityid); +} + +static const char * get_writer_topic_name(struct writer *wr) +{ + if (wr->topic) { + return wr->topic->name; + } + return get_builtin_topic_name(wr->e.guid.entityid); +} + +bool q_omg_participant_is_secure(const struct participant *pp) +{ + return ((pp->sec_attr != NULL) && (pp->sec_attr->crypto_handle != DDS_SECURITY_HANDLE_NIL)); } bool q_omg_proxy_participant_is_secure (const struct proxy_participant *proxypp) { - /* TODO: Register remote participant */ - DDSRT_UNUSED_ARG (proxypp); - return false; + return (proxypp->sec_attr != NULL); } -static bool q_omg_writer_is_discovery_protected (const struct writer *wr) +bool q_omg_participant_allow_unauthenticated(struct participant *pp) { - /* TODO: Register local writer. */ - DDSRT_UNUSED_ARG (wr); - return false; + return ((pp->sec_attr != NULL) && pp->sec_attr->attr.allow_unauthenticated_participants); } -static bool q_omg_reader_is_discovery_protected (const struct reader *rd) +bool q_omg_security_check_create_participant(struct participant *pp, uint32_t domain_id) { - /* TODO: Register local reader. */ - DDSRT_UNUSED_ARG (rd); - return false; + bool allowed = false; + struct dds_security_context *sc = q_omg_security_get_secure_context(pp); + DDS_Security_IdentityHandle identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + DDS_Security_ValidationResult_t result = 0; + DDS_Security_IdentityToken identity_token; + DDS_Security_PermissionsToken permissions_token = DDS_SECURITY_TOKEN_INIT; + DDS_Security_PermissionsCredentialToken credential_token = DDS_SECURITY_TOKEN_INIT; + struct participant_sec_attributes *sec_attr = NULL; + DDS_Security_Qos par_qos; + ddsi_guid_t candidate_guid; + ddsi_guid_t adjusted_guid; + + if (!sc) + return true; + + /* Validate local identity */ + ETRACE (pp, "validate_local_identity: candidate_guid: "PGUIDFMT" ", PGUID (pp->e.guid)); + + candidate_guid = nn_hton_guid(pp->e.guid); + q_omg_shallow_copy_security_qos(&par_qos, &(pp->plist->qos)); + + result = sc->authentication_context->validate_local_identity( + sc->authentication_context, &identity_handle, + (DDS_Security_GUID_t *) &adjusted_guid, (DDS_Security_DomainId) domain_id, &par_qos, + (DDS_Security_GUID_t *) &candidate_guid, &exception); + if (result != DDS_SECURITY_VALIDATION_OK) + { + EXCEPTION_ERROR(sc, &exception, "Error occurred while validating local permission"); + goto validation_failed; + } + pp->e.guid = nn_ntoh_guid(adjusted_guid); + + sec_attr = participant_sec_attributes_new(&pp->e.guid); + sec_attr->local_identity_handle = identity_handle; + + ETRACE (pp, "adjusted_guid: "PGUIDFMT" ", PGUID (pp->e.guid)); + + /* Get the identity token and add this to the plist of the participant */ + if (!sc->authentication_context->get_identity_token(sc->authentication_context, &identity_token, identity_handle, &exception)) + { + EXCEPTION_ERROR(sc, &exception, "Error occurred while retrieving the identity token"); + goto validation_failed; + } + assert(exception.code == 0); + + q_omg_security_dataholder_copyin(&pp->plist->identity_token, &identity_token); + DDS_Security_DataHolder_deinit(&identity_token); + pp->plist->present |= PP_IDENTITY_TOKEN; + + sec_attr->permissions_handle = sc->access_control_context->validate_local_permissions( + sc->access_control_context, sc->authentication_context, identity_handle, + (DDS_Security_DomainId)domain_id, &par_qos, &exception); + if (sec_attr->permissions_handle == DDS_SECURITY_HANDLE_NIL) + { + EXCEPTION_ERROR(sc, &exception, "Error occurred while validating local permissions"); + goto not_allowed; + } + + /* ask to access control security plugin for create participant permissions related to this identity*/ + if (!sc->access_control_context->check_create_participant(sc->access_control_context, sec_attr->permissions_handle, (DDS_Security_DomainId) domain_id, &par_qos, &exception)) + { + EXCEPTION_ERROR(sc, &exception, "It is not allowed to create participant"); + goto not_allowed; + } + + /* Get the identity token and add this to the plist of the participant */ + if (!sc->access_control_context->get_permissions_token(sc->access_control_context, &permissions_token, sec_attr->permissions_handle, &exception)) + { + EXCEPTION_ERROR(sc, &exception, "Error occurred while retrieving the permissions token"); + goto not_allowed; + } + + q_omg_security_dataholder_copyin(&pp->plist->permissions_token, &permissions_token); + pp->plist->present |= PP_PERMISSIONS_TOKEN; + + if (!sc->access_control_context->get_permissions_credential_token(sc->access_control_context, &credential_token, sec_attr->permissions_handle, &exception)) + { + EXCEPTION_ERROR(sc, &exception, "Error occurred while retrieving the permissions credential token"); + goto no_credentials; + } + + if (!sc->authentication_context->set_permissions_credential_and_token(sc->authentication_context, sec_attr->local_identity_handle, &credential_token, &permissions_token, &exception)) + { + EXCEPTION_ERROR(sc, &exception, "Error occurred while setting the permissions credential token"); + goto no_credentials; + } + + if (!sc->access_control_context->get_participant_sec_attributes(sc->access_control_context, sec_attr->permissions_handle, &sec_attr->attr, &exception)) + { + EXCEPTION_ERROR(sc, &exception, "Failed to get participant security attributes"); + goto no_sec_attr; + } + + sec_attr->plugin_attr = true; + sec_attr->crypto_handle = sc->crypto_context->crypto_key_factory->register_local_participant( + sc->crypto_context->crypto_key_factory, sec_attr->local_identity_handle, sec_attr->permissions_handle, NULL, &sec_attr->attr, &exception); + if (!sec_attr->crypto_handle) { + EXCEPTION_ERROR(sc, &exception, "Failed to register participant with crypto key factory"); + goto no_crypto; + } + + participant_index_add(sc, sec_attr); + pp->sec_attr = sec_attr; + + ETRACE (pp, "\n"); + + allowed = true; + +no_crypto: +no_sec_attr: +no_credentials: + if (permissions_token.class_id) + (void)sc->access_control_context->return_permissions_token(sc->access_control_context, &permissions_token, NULL); + if (credential_token.class_id) + (void)sc->access_control_context->return_permissions_credential_token(sc->access_control_context, &credential_token, NULL); +not_allowed: + if (!allowed) + participant_sec_attributes_free(sec_attr); +validation_failed: + q_omg_shallow_free_security_qos(&par_qos); + return allowed; } -bool q_omg_get_writer_security_info (const struct writer *wr, nn_security_info_t *info) +void q_omg_security_participant_set_initialized(struct participant *pp) { - assert (wr); - assert (info); - /* TODO: Register local writer. */ - DDSRT_UNUSED_ARG (wr); + if (pp->sec_attr) + { + ddsrt_mutex_lock(&pp->sec_attr->lock); + pp->sec_attr->initialized = true; + ddsrt_mutex_unlock(&pp->sec_attr->lock); + } +} +bool q_omg_security_participant_is_initialized(struct participant *pp) +{ + bool initialized = false; + + if (pp->sec_attr) + { + ddsrt_mutex_lock(&pp->sec_attr->lock); + initialized = pp->sec_attr->initialized; + ddsrt_mutex_unlock(&pp->sec_attr->lock); + } + return initialized; +} + +struct cleanup_participant_sec_attributes_arg { + struct ddsi_domaingv *gv; + int64_t crypto_handle; +}; + +static void cleanup_participant_sec_attributes(void *arg) +{ + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + struct cleanup_participant_sec_attributes_arg *info = arg; + struct ddsi_domaingv * gv = info->gv; + dds_security_context *sc = gv->security_context; + struct participant_sec_attributes *attr; + + struct pp_proxypp_match *pm; + + if ((attr = participant_index_remove(sc, info->crypto_handle)) == NULL) + return; + + pm = ddsrt_avl_cfind_min(&pp_proxypp_treedef, &attr->proxy_participants); + while (pm) + { + struct pp_proxypp_match *next = ddsrt_avl_cfind_succ(&pp_proxypp_treedef, &attr->proxy_participants, pm); + ddsrt_mutex_lock(&gv->lock); + struct proxy_participant *proxypp = entidx_lookup_proxy_participant_guid(gv->entity_index, &pm->proxypp_guid); + if (proxypp) + proxypp_pp_unrelate(sc, proxypp, &attr->pp_guid, attr->crypto_handle); + ddsrt_mutex_unlock(&gv->lock); + ddsrt_avl_cdelete(&pp_proxypp_treedef, &attr->proxy_participants, pm); + ddsrt_free(pm); + pm = next; + } + + if (attr->permissions_handle != DDS_SECURITY_HANDLE_NIL) + { + if (!sc->access_control_context->return_permissions_handle(sc->access_control_context, attr->permissions_handle, &exception)) + EXCEPTION_ERROR(sc, &exception, "Failed to return local permissions handle"); + } + if (attr->local_identity_handle != DDS_SECURITY_HANDLE_NIL) + { + if (!sc->authentication_context->return_identity_handle(sc->authentication_context, attr->local_identity_handle, &exception)) + EXCEPTION_ERROR(sc, &exception, "Failed to return local identity handle"); + } + if (attr->plugin_attr) + { + if (!sc->access_control_context->return_participant_sec_attributes(sc->access_control_context, &attr->attr, &exception)) + EXCEPTION_ERROR(sc, &exception, "Failed to return participant security attributes"); + } + + (void)sc->crypto_context->crypto_key_factory->unregister_participant(sc->crypto_context->crypto_key_factory, attr->crypto_handle, NULL); + + ddsrt_avl_cfree(&pp_proxypp_treedef, &attr->proxy_participants, NULL); + ddsrt_mutex_unlock(&attr->lock); + ddsrt_free(attr); + ddsrt_free(arg); +} + +void q_omg_security_deregister_participant(struct participant *pp) +{ +// DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + struct dds_security_context *sc = q_omg_security_get_secure_context(pp); + + if (!sc) + return; + + /* When the participant is deleted the timed event queue may still contain + * messages from this participant. Therefore the crypto handle should still + * be available to ensure that the rtps message can be encoded. + * For this purpose the cleanup of the associated crypto handle is delayed. + * A callback is scheduled to be called after some delay to cleanup this + * crypto handle. + */ + if (pp->sec_attr->crypto_handle != DDS_SECURITY_HANDLE_NIL) { + struct cleanup_participant_sec_attributes_arg *arg = ddsrt_malloc (sizeof (*arg)); + arg->crypto_handle = pp->sec_attr->crypto_handle; + arg->gv = pp->e.gv; + qxev_nt_callback(pp->e.gv->xevents, cleanup_participant_sec_attributes, arg); + } + + pp->sec_attr = NULL; +} + +int64_t q_omg_security_get_local_participant_handle(const struct participant *pp) +{ + if (pp->sec_attr) + return pp->sec_attr->crypto_handle; + return 0; +} + +bool q_omg_participant_is_access_protected(const struct participant *pp) +{ + return ((pp->sec_attr != NULL) && pp->sec_attr->attr.is_access_protected); +} + +bool q_omg_participant_is_rtps_protected(const struct participant *pp) +{ + return ((pp->sec_attr != NULL) && pp->sec_attr->attr.is_rtps_protected); +} + +bool q_omg_participant_is_liveliness_protected(const struct participant *pp) +{ + return ((pp->sec_attr != NULL) && pp->sec_attr->attr.is_liveliness_protected); +} + + +static bool maybe_rtps_protected(ddsi_entityid_t entityid) +{ + if (!is_builtin_entityid(entityid, NN_VENDORID_ECLIPSE)) + return true; + + switch (entityid.u) + { + case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER: + case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_READER: + case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER: + case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER: + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER: + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER: + case NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER: + case NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_READER: + return true; + default: + return false; + } +} + +static bool proxypp_is_rtps_protected(const struct proxy_participant *proxypp) +{ + return (proxypp->sec_attr != NULL && SECURITY_INFO_IS_RTPS_PROTECTED(proxypp->security_info)); +} + +bool q_omg_security_is_remote_rtps_protected(const struct proxy_participant *proxypp, ddsi_entityid_t entityid) +{ + return q_omg_proxy_participant_is_secure(proxypp) && + SECURITY_INFO_IS_RTPS_PROTECTED(proxypp->security_info) && + maybe_rtps_protected(entityid); +} + +bool q_omg_security_is_local_rtps_protected(const struct participant *pp, ddsi_entityid_t entityid) +{ + return q_omg_participant_is_rtps_protected(pp) && maybe_rtps_protected(entityid); +} + +bool q_omg_get_participant_security_info(const struct participant *pp, nn_security_info_t *info) +{ + assert(pp); + assert(info); + + if (q_omg_participant_is_secure(pp)) { + const DDS_Security_ParticipantSecurityAttributes *attr = &(pp->sec_attr->attr); + + info->security_attributes = NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID; + info->plugin_security_attributes = attr->plugin_participant_attributes; + + if (attr->is_discovery_protected) + info->security_attributes |= NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_DISCOVERY_PROTECTED; + + if (attr->is_liveliness_protected) + info->security_attributes |= NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_LIVELINESS_PROTECTED; + + if (attr->is_rtps_protected) + info->security_attributes |= NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_RTPS_PROTECTED; + + return true; + } + + info->security_attributes = 0; info->plugin_security_attributes = 0; - if (q_omg_writer_is_payload_protected (wr)) - { - info->security_attributes = - NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID | - NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_PAYLOAD_PROTECTED; - } - else - { - info->security_attributes = 0; - } - return true; + + return false; } -bool q_omg_get_reader_security_info (const struct reader *rd, nn_security_info_t *info) +static void q_omg_get_endpoint_security_info(DDS_Security_EndpointSecurityAttributes *attr, nn_security_info_t *info) { - assert (rd); - assert (info); - /* TODO: Register local reader. */ - DDSRT_UNUSED_ARG (rd); + info->security_attributes = NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID; + info->plugin_security_attributes = attr->plugin_endpoint_attributes; + + if (attr->is_read_protected) + info->security_attributes |= NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_READ_PROTECTED; + + if (attr->is_write_protected) + info->security_attributes |= NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_WRITE_PROTECTED; + + if (attr->is_discovery_protected) + info->security_attributes |= NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_DISCOVERY_PROTECTED; + + if (attr->is_liveliness_protected) + info->security_attributes |= NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_LIVELINESS_PROTECTED; + + if (attr->is_submessage_protected) + info->security_attributes |= NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_PROTECTED; + + if (attr->is_payload_protected) + info->security_attributes |= NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_PAYLOAD_PROTECTED; + + if (attr->is_key_protected) + info->security_attributes |= NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_KEY_PROTECTED; +} + +static bool is_topic_discovery_protected(DDS_Security_PermissionsHandle permission_handle, dds_security_access_control *access_control, const char *topic_name) +{ + DDS_Security_TopicSecurityAttributes attributes = {0,0,0,0}; + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + + if (access_control->get_topic_sec_attributes(access_control, permission_handle, topic_name, &attributes, &exception)) + return attributes.is_discovery_protected; + else + DDS_Security_Exception_reset(&exception); + return false; +} + +bool q_omg_security_check_create_topic(const struct ddsi_domaingv *gv, const ddsi_guid_t *pp_guid, const char *topic_name, const struct dds_qos *qos) +{ + bool result = true; + struct participant *pp; + struct dds_security_context *sc; + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + DDS_Security_Qos topic_qos; + + thread_state_awake (lookup_thread_state (), gv); + pp = entidx_lookup_participant_guid (gv->entity_index, pp_guid); + + if ((sc = q_omg_security_get_secure_context(pp)) != NULL) + { + q_omg_shallow_copy_security_qos(&topic_qos, qos); + result = sc->access_control_context->check_create_topic(sc->access_control_context, pp->sec_attr->permissions_handle, (DDS_Security_DomainId)gv->config.domainId, topic_name, &topic_qos, &exception); + if (!result) + { + /*log if the topic discovery is not protected*/ + if (!is_topic_discovery_protected(pp->sec_attr->permissions_handle, sc->access_control_context, topic_name)) + EXCEPTION_ERROR(sc, &exception, "Local topic permission denied"); + else + DDS_Security_Exception_reset(&exception); + } + q_omg_shallow_free_security_qos(&topic_qos); + } + thread_state_asleep (lookup_thread_state ()); + + return result; +} + +bool q_omg_security_check_create_writer(struct participant *pp, uint32_t domain_id, const char *topic_name, const struct dds_qos *writer_qos) +{ + struct dds_security_context *sc = q_omg_security_get_secure_context(pp) ; + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + DDS_Security_PartitionQosPolicy partitions; + DDS_Security_Qos security_qos; + bool result; + + if (!sc) + return true; + + if (writer_qos->present & QP_PARTITION) + g_omg_shallow_copy_StringSeq(&partitions.name, &(writer_qos->partition)); + else + memset(&(partitions), 0, sizeof(DDS_Security_PartitionQosPolicy)); + + q_omg_shallow_copy_security_qos(&security_qos, writer_qos); + + result = sc->access_control_context->check_create_datawriter(sc->access_control_context, pp->sec_attr->permissions_handle, (DDS_Security_DomainId)domain_id, topic_name, &security_qos, &partitions, NULL, &exception); + if (!result) + { + /*log if the topic discovery is not protected*/ + if (!is_topic_discovery_protected( pp->sec_attr->permissions_handle, sc->access_control_context, topic_name)) + EXCEPTION_ERROR(sc, &exception, "Local topic permission denied"); + else + DDS_Security_Exception_reset(&exception); + } + + q_omg_shallow_free_security_qos(&security_qos); + g_omg_shallow_free_StringSeq(&partitions.name); + + return result; +} + +void q_omg_security_register_writer(struct writer *wr) +{ + struct participant *pp = wr->c.pp; + struct dds_security_context *sc = q_omg_security_get_secure_context(pp); + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + DDS_Security_PartitionQosPolicy partitions; + DDS_Security_PropertySeq properties; + const char *topic_name; + + if (!sc) + return; + + if (wr->xqos->present & QP_PARTITION) + g_omg_shallow_copy_StringSeq(&partitions.name, &(wr->xqos->partition)); + else + memset(&(partitions), 0, sizeof(DDS_Security_PartitionQosPolicy)); + + wr->sec_attr = writer_sec_attributes_new(); + topic_name = get_writer_topic_name(wr); + if (!sc->access_control_context->get_datawriter_sec_attributes(sc->access_control_context, pp->sec_attr->permissions_handle, topic_name, &partitions, NULL, &wr->sec_attr->attr, &exception)) + { + EXCEPTION_ERROR(sc, &exception, "Failed to retrieve writer security attributes"); + goto no_attr; + } + wr->sec_attr->plugin_attr = true; + + if (wr->sec_attr->attr.is_payload_protected || wr->sec_attr->attr.is_submessage_protected) + { + if (wr->xqos->present & QP_PROPERTY_LIST) + q_omg_copy_PropertySeq(&properties, &wr->xqos->property.value); + else + memset(&properties, 0, sizeof(DDS_Security_PropertySeq)); + + wr->sec_attr->crypto_handle = sc->crypto_context->crypto_key_factory->register_local_datawriter( + sc->crypto_context->crypto_key_factory, pp->sec_attr->crypto_handle, &properties, &wr->sec_attr->attr, &exception); + DDS_Security_PropertySeq_freebuf(&properties); + if (wr->sec_attr->crypto_handle == DDS_SECURITY_HANDLE_NIL) + { + EXCEPTION_ERROR(sc, &exception, "Failed to register writer with crypto"); + goto not_registered; + } + } + + if (wr->sec_attr->attr.is_key_protected) + wr->include_keyhash = 1; + +not_registered: +no_attr: + g_omg_shallow_free_StringSeq(&partitions.name); +} + +void q_omg_security_deregister_writer(struct writer *wr) +{ + struct dds_security_context *sc = q_omg_security_get_secure_context(wr->c.pp); + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + + if (wr->sec_attr) + { + if (wr->sec_attr->crypto_handle != DDS_SECURITY_HANDLE_NIL) + { + if (!sc->crypto_context->crypto_key_factory->unregister_datawriter(sc->crypto_context->crypto_key_factory, wr->sec_attr->crypto_handle, &exception)) + EXCEPTION_ERROR(sc, &exception, "Failed to unregister writer with crypto"); + } + if (wr->sec_attr->plugin_attr) + { + if (!sc->access_control_context->return_datawriter_sec_attributes(sc->access_control_context, &wr->sec_attr->attr, &exception)) + EXCEPTION_ERROR(sc, &exception, "Failed to return writer security attributes"); + } + writer_sec_attributes_free(wr->sec_attr); + wr->sec_attr = NULL; + } +} + +bool q_omg_get_writer_security_info(const struct writer *wr, nn_security_info_t *info) +{ + assert(wr); + assert(info); + + if (wr->sec_attr) { + q_omg_get_endpoint_security_info(&wr->sec_attr->attr, info); + return true; + } info->plugin_security_attributes = 0; info->security_attributes = 0; return false; } -void q_omg_security_init_remote_participant (struct proxy_participant *proxypp) +bool q_omg_security_check_create_reader(struct participant *pp, uint32_t domain_id, const char *topic_name, const struct dds_qos *reader_qos) { - DDSRT_UNUSED_ARG (proxypp); + struct dds_security_context *sc = q_omg_security_get_secure_context(pp); + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + DDS_Security_PartitionQosPolicy partitions; + DDS_Security_Qos security_qos; + bool result; + + if (!sc) + return true; + + if (reader_qos->present & QP_PARTITION) + g_omg_shallow_copy_StringSeq(&partitions.name, &(reader_qos->partition)); + else + memset(&(partitions), 0, sizeof(DDS_Security_PartitionQosPolicy)); + + q_omg_shallow_copy_security_qos(&security_qos, reader_qos); + + result = sc->access_control_context->check_create_datareader(sc->access_control_context, pp->sec_attr->permissions_handle, (DDS_Security_DomainId)domain_id, topic_name, &security_qos, &partitions, NULL, &exception); + if (!result) + { + /*log if the topic discovery is not protected*/ + if (!is_topic_discovery_protected( pp->sec_attr->permissions_handle, sc->access_control_context, topic_name)) + EXCEPTION_ERROR(sc, &exception, "Reader is not permitted"); + else + DDS_Security_Exception_reset(&exception); + } + + q_omg_shallow_free_security_qos(&security_qos); + g_omg_shallow_free_StringSeq(&partitions.name); + + return result; } -static bool q_omg_proxyparticipant_is_authenticated (const struct proxy_participant *proxy_pp) +void q_omg_security_register_reader(struct reader *rd) { - /* TODO: Handshake */ - DDSRT_UNUSED_ARG (proxy_pp); + struct participant *pp = rd->c.pp; + struct dds_security_context *sc = q_omg_security_get_secure_context(pp); + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + DDS_Security_PartitionQosPolicy partitions; + DDS_Security_PropertySeq properties; + const char *topic_name; + + if (!sc) + return; + + if (rd->xqos->present & QP_PARTITION) + g_omg_shallow_copy_StringSeq(&partitions.name, &(rd->xqos->partition)); + else + memset(&(partitions), 0, sizeof(DDS_Security_PartitionQosPolicy)); + + rd->sec_attr = reader_sec_attributes_new(); + + topic_name = get_reader_topic_name(rd); + if (!sc->access_control_context->get_datareader_sec_attributes(sc->access_control_context, pp->sec_attr->permissions_handle, topic_name, &partitions, NULL, &rd->sec_attr->attr, &exception)) + { + EXCEPTION_ERROR(sc, &exception, "Failed to retrieve reader security attributes"); + goto no_attr; + } + rd->sec_attr->plugin_attr = true; + + if (rd->sec_attr->attr.is_payload_protected || rd->sec_attr->attr.is_submessage_protected) + { + if (rd->xqos->present & QP_PROPERTY_LIST) + q_omg_copy_PropertySeq(&properties, &rd->xqos->property.value); + else + memset(&properties, 0, sizeof(DDS_Security_PropertySeq)); + + rd->sec_attr->crypto_handle = sc->crypto_context->crypto_key_factory->register_local_datareader( + sc->crypto_context->crypto_key_factory, pp->sec_attr->crypto_handle, &properties, &rd->sec_attr->attr, &exception); + DDS_Security_PropertySeq_freebuf(&properties); + if (rd->sec_attr->crypto_handle == DDS_SECURITY_HANDLE_NIL) + { + EXCEPTION_ERROR(sc, &exception, "Failed to register reader with crypto"); + goto not_registered; + } + } + +not_registered: +no_attr: + g_omg_shallow_free_StringSeq(&partitions.name); +} + +void q_omg_security_deregister_reader(struct reader *rd) +{ + struct dds_security_context *sc = q_omg_security_get_secure_context(rd->c.pp); + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + + if (rd->sec_attr) + { + assert(sc); + if (rd->sec_attr->crypto_handle != DDS_SECURITY_HANDLE_NIL) + { + if (!sc->crypto_context->crypto_key_factory->unregister_datareader(sc->crypto_context->crypto_key_factory, rd->sec_attr->crypto_handle, &exception)) + { + EXCEPTION_ERROR(sc, &exception, "Failed to unregister reader with crypto"); + } + } + if (rd->sec_attr->plugin_attr) + { + if (!sc->access_control_context->return_datareader_sec_attributes(sc->access_control_context, &rd->sec_attr->attr, &exception)) + { + EXCEPTION_ERROR(sc, &exception, "Failed to return reader security attributes"); + } + } + reader_sec_attributes_free(rd->sec_attr); + rd->sec_attr = NULL; + } +} + +bool q_omg_get_reader_security_info(const struct reader *rd, nn_security_info_t *info) +{ + assert(rd); + assert(info); + + if (rd->sec_attr) { + q_omg_get_endpoint_security_info(&rd->sec_attr->attr, info); + return true; + } + info->plugin_security_attributes = 0; + info->security_attributes = 0; return false; } -int64_t q_omg_security_get_local_participant_handle (struct participant *pp) -{ - /* TODO: Local registration */ - DDSRT_UNUSED_ARG (pp); - return 0; -} - -int64_t q_omg_security_get_remote_participant_handle (struct proxy_participant *proxypp) -{ - /* TODO: Handshake */ - DDSRT_UNUSED_ARG(proxypp); - return 0; -} - -bool q_omg_participant_allow_unauthenticated (struct participant *pp) -{ - DDSRT_UNUSED_ARG (pp); - return true; -} - -unsigned determine_subscription_writer (const struct reader *rd) +unsigned determine_subscription_writer(const struct reader *rd) { if (q_omg_reader_is_discovery_protected (rd)) return NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER; @@ -386,17 +1487,292 @@ unsigned determine_publication_writer (const struct writer *wr) return NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER; } -void q_omg_security_register_remote_participant (struct participant *pp, struct proxy_participant *proxypp, int64_t shared_secret, int64_t proxy_permissions) +static int64_t check_remote_participant_permissions(uint32_t domain_id, struct participant *pp, struct proxy_participant *proxypp, int64_t remote_identity_handle) { - DDSRT_UNUSED_ARG (pp); - DDSRT_UNUSED_ARG (proxypp); - DDSRT_UNUSED_ARG (shared_secret); - DDSRT_UNUSED_ARG (proxy_permissions); + struct dds_security_context *sc = q_omg_security_get_secure_context(pp); + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + struct ddsi_handshake *handshake; + DDS_Security_PermissionsToken permissions_token = DDS_SECURITY_TOKEN_INIT; + DDS_Security_AuthenticatedPeerCredentialToken peer_credential_token = DDS_SECURITY_TOKEN_INIT; + int64_t permissions_hdl = DDS_SECURITY_HANDLE_NIL; + + if (proxypp->plist->present & PP_PERMISSIONS_TOKEN) + q_omg_shallow_copyin_DataHolder(&permissions_token, &proxypp->plist->permissions_token); + else + memset(&permissions_token, 0, sizeof(DDS_Security_PermissionsToken)); + + handshake = ddsi_handshake_find(pp, proxypp); + if (!handshake) + { + ELOG(DDS_LC_ERROR, pp, "Could not find handshake local participant "PGUIDFMT" and remote participant "PGUIDFMT, + PGUID(pp->e.guid), PGUID(proxypp->e.guid)); + goto no_handshake; + } + + if (!sc->authentication_context->get_authenticated_peer_credential_token(sc->authentication_context, &peer_credential_token, ddsi_handshake_get_handle(handshake), &exception)) + { + if (q_omg_participant_is_access_protected(pp)) + { + EXCEPTION_ERROR(sc, &exception, "Could not authenticate_peer_credential_token for local participan1152t "PGUIDFMT" and remote participant "PGUIDFMT, + PGUID(pp->e.guid), PGUID(proxypp->e.guid)); + goto no_credentials; + } + /* Failing is allowed due to the non-protection of access. */ + EXCEPTION_WARNING(sc, &exception, "Could not authenticate_peer_credential_token for local participant "PGUIDFMT" and remote participant "PGUIDFMT , + PGUID(pp->e.guid), PGUID(proxypp->e.guid)); + } + + permissions_hdl = sc->access_control_context->validate_remote_permissions( + sc->access_control_context, sc->authentication_context, pp->sec_attr->local_identity_handle, remote_identity_handle, &permissions_token, &peer_credential_token, &exception); + if (permissions_hdl == DDS_SECURITY_HANDLE_NIL) + { + if (q_omg_participant_is_access_protected(pp)) + { + EXCEPTION_ERROR(sc, &exception, "Could not get remote participant "PGUIDFMT" permissions from plugin", PGUID(proxypp->e.guid)); + goto no_permissions; + } + /* Failing is allowed due to the non-protection of access. */ + EXCEPTION_WARNING(sc, &exception, "Could not get remote participant "PGUIDFMT" permissions from plugin", PGUID(proxypp->e.guid)); + } + + /* Only check remote participant if joining access is protected. */ + if (q_omg_participant_is_access_protected(pp)) + { + DDS_Security_ParticipantBuiltinTopicDataSecure participant_data; + + q_omg_shallow_copy_ParticipantBuiltinTopicDataSecure(&participant_data, &(proxypp->e.guid), proxypp->plist); + if (!sc->access_control_context->check_remote_participant(sc->access_control_context, permissions_hdl, (DDS_Security_DomainId)domain_id, &participant_data, &exception)) + { + EXCEPTION_WARNING(sc, &exception, "Plugin does not allow remote participant "PGUIDFMT, PGUID(proxypp->e.guid)); + if (!sc->access_control_context->return_permissions_handle(sc->access_control_context, permissions_hdl, &exception)) + { + EXCEPTION_ERROR(sc, &exception, "Failed to return remote permissions handle"); + } + permissions_hdl = DDS_SECURITY_HANDLE_NIL; + } + q_omg_shallow_free_ParticipantBuiltinTopicDataSecure(&participant_data); + } + +no_permissions: + if (!sc->authentication_context->return_authenticated_peer_credential_token(sc->authentication_context, &peer_credential_token, &exception)) + { + EXCEPTION_ERROR(sc, &exception, "Failed to return peer credential token"); + } +no_credentials: + ddsi_handshake_release(handshake); +no_handshake: + q_omg_shallow_free_DataHolder(&permissions_token); + return permissions_hdl; } -void q_omg_security_deregister_remote_participant (struct proxy_participant *proxypp) +static void send_participant_crypto_tokens(struct participant *pp, struct proxy_participant *proxypp, DDS_Security_ParticipantCryptoHandle local_crypto, DDS_Security_ParticipantCryptoHandle remote_crypto) { - DDSRT_UNUSED_ARG (proxypp); + struct dds_security_context *sc = q_omg_security_get_secure_context(pp); + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + DDS_Security_ParticipantCryptoTokenSeq tokens = DDS_SECURITY_SEQUENCE_INIT; + bool r; + + r = sc->crypto_context->crypto_key_exchange->create_local_participant_crypto_tokens(sc->crypto_context->crypto_key_exchange, &tokens, local_crypto, remote_crypto, &exception); + if (!r) + EXCEPTION_ERROR(sc, &exception, "Failed to create local participant crypto tokens "PGUIDFMT" for remote participant "PGUIDFMT, PGUID(pp->e.guid), PGUID(proxypp->e.guid)); + else if (tokens._length > 0) + { + nn_dataholderseq_t tholder; + + q_omg_shallow_copyout_DataHolderSeq(&tholder, &tokens); + write_crypto_participant_tokens(pp, proxypp, &tholder); + q_omg_shallow_free_nn_dataholderseq(&tholder); + + if (!sc->crypto_context->crypto_key_exchange->return_crypto_tokens(sc->crypto_context->crypto_key_exchange, &tokens, &exception)) + EXCEPTION_ERROR(sc, &exception, "Failed to return local participant crypto tokens "PGUIDFMT" for remote participant "PGUIDFMT, PGUID(pp->e.guid), PGUID(proxypp->e.guid)); + } +} + +static int64_t get_permissions_handle(struct participant *pp, struct proxy_participant *proxypp) +{ + int64_t hdl = 0; + struct proxypp_pp_match *pm; + + ddsrt_mutex_lock(&proxypp->sec_attr->lock); + pm = ddsrt_avl_lookup(&proxypp_pp_treedef, &proxypp->sec_attr->participants, &pp->sec_attr->crypto_handle); + if (pm) + hdl = pm->permissions_handle; + ddsrt_mutex_unlock(&proxypp->sec_attr->lock); + + return hdl; +} + +void q_omg_security_init_remote_participant(struct proxy_participant *proxypp) +{ + proxypp->sec_attr = ddsrt_malloc(sizeof(*proxypp->sec_attr)); + ddsrt_mutex_init(&proxypp->sec_attr->lock); + ddsrt_avl_init (&proxypp_pp_treedef, &proxypp->sec_attr->participants); + proxypp->sec_attr->sc = proxypp->e.gv->security_context; + proxypp->sec_attr->remote_identity_handle = 0; + proxypp->sec_attr->crypto_handle = 0; + proxypp->sec_attr->initialized = false; +} + +void q_omg_security_remote_participant_set_initialized(struct proxy_participant *proxypp) +{ + if (proxypp->sec_attr) + { + ddsrt_mutex_lock(&proxypp->sec_attr->lock); + proxypp->sec_attr->initialized = true; + ddsrt_mutex_unlock(&proxypp->sec_attr->lock); + } +} + +bool q_omg_security_remote_participant_is_initialized(struct proxy_participant *proxypp) +{ + bool initialized = false; + + if (proxypp->sec_attr) + { + ddsrt_mutex_lock(&proxypp->sec_attr->lock); + initialized = proxypp->sec_attr->initialized; + ddsrt_mutex_unlock(&proxypp->sec_attr->lock); + } + return initialized; +} + +static bool proxypp_is_authenticated(const struct proxy_participant *proxypp) +{ + bool authenticated = false; + + if (proxypp->sec_attr) + { + ddsrt_mutex_lock(&proxypp->sec_attr->lock); + authenticated = !ddsrt_avl_is_empty(&proxypp->sec_attr->participants); + ddsrt_mutex_unlock(&proxypp->sec_attr->lock); + } + return authenticated; +} + +static void match_proxypp_pp(struct participant *pp, struct proxy_participant *proxypp, DDS_Security_PermissionsHandle permissions_handle, DDS_Security_SharedSecretHandle shared_secret_handle) +{ + struct proxypp_pp_match *pm; + struct pp_proxypp_match *pc; + + pm = proxypp_pp_match_new(pp, permissions_handle, shared_secret_handle); + ddsrt_mutex_lock(&proxypp->sec_attr->lock); + ddsrt_avl_insert(&proxypp_pp_treedef, &proxypp->sec_attr->participants, pm); + ddsrt_mutex_unlock(&proxypp->sec_attr->lock); + + pc = pp_proxypp_match_new(proxypp, proxypp->sec_attr->crypto_handle); + + ddsrt_mutex_lock(&pp->sec_attr->lock); + ddsrt_avl_cinsert(&pp_proxypp_treedef, &pp->sec_attr->proxy_participants, pc); + ddsrt_mutex_unlock(&pp->sec_attr->lock); +} + +bool q_omg_security_register_remote_participant(struct participant *pp, struct proxy_participant *proxypp, int64_t shared_secret) +{ + bool ret = true; + struct ddsi_domaingv *gv = pp->e.gv; + struct dds_security_context *sc = q_omg_security_get_secure_context(pp); + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + DDS_Security_ParticipantCryptoHandle crypto_handle; + int64_t permissions_handle; + bool notify_handshake = false; + + permissions_handle = check_remote_participant_permissions(gv->config.domainId, pp, proxypp, proxypp->sec_attr->remote_identity_handle); + if (permissions_handle == 0) + return false; + + GVTRACE("register remote participant "PGUIDFMT" with "PGUIDFMT"\n", PGUID(proxypp->e.guid), PGUID(pp->e.guid)); + + crypto_handle = sc->crypto_context->crypto_key_factory->register_matched_remote_participant( + sc->crypto_context->crypto_key_factory, pp->sec_attr->crypto_handle, proxypp->sec_attr->remote_identity_handle, permissions_handle, shared_secret, &exception); + if (crypto_handle == DDS_SECURITY_HANDLE_NIL) + { + EXCEPTION_ERROR(sc, &exception, "Failed to register matched remote participant "PGUIDFMT" with participant "PGUIDFMT, PGUID(proxypp->e.guid), PGUID(pp->e.guid)); + ret = false; + goto register_failed; + } + + ddsrt_mutex_lock(&pp->e.lock); + + proxypp->sec_attr->crypto_handle = crypto_handle; + + GVTRACE("match pp->crypto=%"PRId64" proxypp->crypto=%"PRId64"\n", pp->sec_attr->crypto_handle, crypto_handle); + match_proxypp_pp(pp, proxypp, permissions_handle, shared_secret); + + GVTRACE("create proxypp-pp match pp="PGUIDFMT" proxypp="PGUIDFMT" lidh=%"PRId64, PGUID(pp->e.guid), PGUID(proxypp->e.guid), pp->sec_attr->local_identity_handle); + + if (proxypp_is_rtps_protected(proxypp)) + { + struct security_entity_match *m = find_or_create_entity_match(gv->security_matches, &proxypp->e.guid, &pp->e.guid); + m->crypto_handle = crypto_handle; + if (m->tokens) + { + ret = sc->crypto_context->crypto_key_exchange->set_remote_participant_crypto_tokens(sc->crypto_context->crypto_key_exchange, pp->sec_attr->crypto_handle, crypto_handle, m->tokens, &exception); + if (ret) + { + struct security_entity_match *mx; + mx = remove_entity_match(proxypp->e.gv->security_matches, &proxypp->e.guid, &pp->e.guid); + assert(mx == m); + (void)mx; + entity_match_free(m); + GVTRACE("set participant tokens src("PGUIDFMT") to dst("PGUIDFMT") (by registering remote)\n", PGUID(proxypp->e.guid), PGUID(pp->e.guid)); + } + else + { + EXCEPTION_ERROR(sc, &exception, "Failed to set remote participant crypto tokens "PGUIDFMT" --> "PGUIDFMT, PGUID(proxypp->e.guid), PGUID(pp->e.guid)); + ret = false; + } + } + else + notify_handshake = true; + } + ddsrt_mutex_unlock(&pp->e.lock); + + if (notify_handshake) + notify_handshake_recv_token(pp, proxypp); + +register_failed: + return ret; +} + +void q_omg_security_deregister_remote_participant(struct proxy_participant *proxypp) +{ + struct ddsi_domaingv *gv = proxypp->e.gv; + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + + if (proxypp->sec_attr) { + dds_security_context *sc = proxypp->sec_attr->sc; + struct proxypp_pp_match *pm; + struct participant *pp; + + pm = ddsrt_avl_find_min(&proxypp_pp_treedef, &proxypp->sec_attr->participants); + while (pm) + { + struct proxypp_pp_match *next = ddsrt_avl_find_succ(&proxypp_pp_treedef, &proxypp->sec_attr->participants, pm); + + ddsrt_avl_delete(&proxypp_pp_treedef, &proxypp->sec_attr->participants, pm); + pp = entidx_lookup_participant_guid(gv->entity_index, &pm->pp_guid); + if (pp) + pp_proxypp_unrelate(sc, pp, &proxypp->e.guid); + proxypp_pp_match_free(sc, pm); + pm = next; + } + + if (proxypp->sec_attr->crypto_handle != DDS_SECURITY_HANDLE_NIL) + { + if (!sc->crypto_context->crypto_key_factory->unregister_participant(sc->crypto_context->crypto_key_factory, proxypp->sec_attr->crypto_handle, &exception)) + EXCEPTION_ERROR(sc, &exception, "2:Failed to return remote crypto handle"); + } + + if (proxypp->sec_attr->remote_identity_handle != DDS_SECURITY_HANDLE_NIL) + { + if (!sc->authentication_context->return_identity_handle(sc->authentication_context, proxypp->sec_attr->remote_identity_handle, &exception)) + EXCEPTION_ERROR(sc, &exception, "Failed to return remote identity handle"); + } + + ddsrt_mutex_destroy(&proxypp->sec_attr->lock); + ddsrt_free(proxypp->sec_attr); + proxypp->sec_attr = NULL; + } } bool is_proxy_participant_deletion_allowed (struct ddsi_domaingv * const gv, const struct ddsi_guid *guid, const ddsi_entityid_t pwr_entityid) @@ -421,98 +1797,103 @@ bool is_proxy_participant_deletion_allowed (struct ddsi_domaingv * const gv, con GVLOGDISC (" unknown"); return false; } - return (!q_omg_proxyparticipant_is_authenticated (proxypp)); + + return (!proxypp_is_authenticated(proxypp)); } -/* ask to access control security plugin for the remote participant permissions */ -int64_t q_omg_security_check_remote_participant_permissions (uint32_t domain_id, struct participant *pp, struct proxy_participant *proxypp) +bool q_omg_is_similar_participant_security_info(struct participant *pp, struct proxy_participant *proxypp) { - DDSRT_UNUSED_ARG (domain_id); - DDSRT_UNUSED_ARG (pp); - DDSRT_UNUSED_ARG (proxypp); + bool matching; + nn_security_info_t pp_security_info; + + if (!q_omg_get_participant_security_info(pp, &pp_security_info)) + return false; + + matching = SECURITY_INFO_COMPATIBLE(pp_security_info, proxypp->security_info, NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_VALID); + if (!matching) { + DDS_CLOG (DDS_LC_WARNING, &pp->e.gv->logconfig, "match remote_participant "PGUIDFMT" with participant "PGUIDFMT" security_attributes mismatch: 0x%08x.0x%08x - 0x%08x.0x%08x\n", + PGUID(proxypp->e.guid), PGUID(pp->e.guid), + proxypp->security_info.security_attributes, proxypp->security_info.plugin_security_attributes, + pp_security_info.security_attributes, pp_security_info.plugin_security_attributes); + } else { + /* We previously checked for attribute compatibility. That doesn't + * mean equal, because compatibility depends on the valid flag. + * Some products don't properly send the attributes, in which case + * the valid flag is 0. To be able to support these product, assume + * that the attributes are the same. If there is actually a mismatch, + * communication will fail at a later moment anyway. */ + if (!SECURITY_ATTR_IS_VALID(proxypp->security_info.security_attributes)) { + proxypp->security_info.security_attributes = pp_security_info.security_attributes; + } + if (!SECURITY_ATTR_IS_VALID(proxypp->security_info.plugin_security_attributes)) { + proxypp->security_info.plugin_security_attributes = pp_security_info.plugin_security_attributes; + } + } + assert(matching); + return matching; +} + +void q_omg_security_set_participant_crypto_tokens(struct participant *pp, struct proxy_participant *proxypp, const nn_dataholderseq_t *tokens) +{ + struct ddsi_domaingv *gv = pp->e.gv; + struct dds_security_context *sc = q_omg_security_get_secure_context(pp); + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + struct proxypp_pp_match *pm; + DDS_Security_DatawriterCryptoTokenSeq *tseq; + struct security_entity_match *m; + + if (!sc) + return; + + ddsrt_mutex_lock(&proxypp->sec_attr->lock); + pm = ddsrt_avl_lookup (&proxypp_pp_treedef, &proxypp->sec_attr->participants, &pp->sec_attr->crypto_handle); + ddsrt_mutex_unlock(&proxypp->sec_attr->lock); + + ddsrt_mutex_lock(&pp->e.lock); + m = find_or_create_entity_match(gv->security_matches, &proxypp->e.guid, &pp->e.guid); + + tseq = DDS_Security_DataHolderSeq_alloc(); + q_omg_copyin_DataHolderSeq(tseq, tokens); + + if (!pm) + { + GVTRACE("remember participant tokens src("PGUIDFMT") dst("PGUIDFMT")\n", PGUID(proxypp->e.guid), PGUID(pp->e.guid)); + m->tokens = tseq; + } + else + { + if (sc->crypto_context->crypto_key_exchange->set_remote_participant_crypto_tokens(sc->crypto_context->crypto_key_exchange, pp->sec_attr->crypto_handle, proxypp->sec_attr->crypto_handle, tseq, &exception)) + { + m->matched= true; + GVTRACE("set participant tokens src("PGUIDFMT") dst("PGUIDFMT")\n", PGUID(proxypp->e.guid), PGUID(pp->e.guid)); + DDS_Security_DataHolderSeq_free(tseq); + } + else + EXCEPTION_ERROR(sc, &exception, "Failed to set remote participant crypto tokens "PGUIDFMT" for participant "PGUIDFMT, PGUID(proxypp->e.guid), PGUID(pp->e.guid)); + } + ddsrt_mutex_unlock(&pp->e.lock); + + notify_handshake_recv_token(pp, proxypp); +} + +void q_omg_security_participant_send_tokens(struct participant *pp, struct proxy_participant *proxypp) +{ + if (proxypp->sec_attr->crypto_handle != 0) + send_participant_crypto_tokens(pp, proxypp, pp->sec_attr->crypto_handle, proxypp->sec_attr->crypto_handle); +} + +int64_t q_omg_security_get_remote_participant_handle(struct proxy_participant *proxypp) +{ + if (proxypp->sec_attr) + return proxypp->sec_attr->crypto_handle; + return 0; } -bool q_omg_is_similar_participant_security_info (struct participant *pp, struct proxy_participant *proxypp) +void set_proxy_participant_security_info(struct proxy_participant *proxypp, const ddsi_plist_t *plist) { - DDSRT_UNUSED_ARG (pp); - DDSRT_UNUSED_ARG (proxypp); - return true; -} - -bool q_omg_security_check_create_participant (struct participant *pp, uint32_t domain_id) -{ - DDSRT_UNUSED_ARG (pp); - DDSRT_UNUSED_ARG (domain_id); - return true; -} - -void q_omg_security_participant_send_tokens (struct participant *pp, struct proxy_participant *proxypp) -{ - DDSRT_UNUSED_ARG (pp); - DDSRT_UNUSED_ARG (proxypp); -} - -bool q_omg_security_match_remote_writer_enabled (struct reader *rd, struct proxy_writer *pwr) -{ - DDSRT_UNUSED_ARG (rd); - DDSRT_UNUSED_ARG (pwr); - assert (rd); - assert (pwr); - return true; -} - -bool q_omg_security_match_remote_reader_enabled (struct writer *wr, struct proxy_reader *prd) -{ - DDSRT_UNUSED_ARG (wr); - DDSRT_UNUSED_ARG (prd); - assert (wr); - assert (prd); - return true; -} - -bool q_omg_security_check_remote_writer_permissions (const struct proxy_writer *pwr, uint32_t domain_id, struct participant *pp) -{ - DDSRT_UNUSED_ARG (pwr); - DDSRT_UNUSED_ARG (domain_id); - DDSRT_UNUSED_ARG (pp); - assert (pwr); - assert (pp); - assert (pwr->c.proxypp); - return true; -} - -bool q_omg_security_check_remote_reader_permissions (const struct proxy_reader *prd, uint32_t domain_id, struct participant *pp) -{ - DDSRT_UNUSED_ARG (prd); - DDSRT_UNUSED_ARG (domain_id); - DDSRT_UNUSED_ARG (pp); - assert (prd); - assert (pp); - assert (prd->c.proxypp); - return true; -} - -bool q_omg_security_is_remote_rtps_protected (const struct proxy_participant *proxy_pp, ddsi_entityid_t entityid) -{ - /* TODO: Handshake */ - DDSRT_UNUSED_ARG (proxy_pp); - DDSRT_UNUSED_ARG (entityid); - return false; -} - -bool q_omg_security_is_local_rtps_protected (const struct participant *pp, ddsi_entityid_t entityid) -{ - /* TODO: Handshake */ - DDSRT_UNUSED_ARG (pp); - DDSRT_UNUSED_ARG (entityid); - return false; -} - -void set_proxy_participant_security_info (struct proxy_participant *proxypp, const ddsi_plist_t *plist) -{ - assert (proxypp); - assert (plist); + assert(proxypp); + assert(plist); if (plist->present & PP_PARTICIPANT_SECURITY_INFO) { proxypp->security_info.security_attributes = plist->participant_security_info.security_attributes; proxypp->security_info.plugin_security_attributes = plist->participant_security_info.plugin_security_attributes; @@ -522,7 +1903,300 @@ void set_proxy_participant_security_info (struct proxy_participant *proxypp, con } } -static void q_omg_get_proxy_endpoint_security_info (const struct entity_common *entity, nn_security_info_t *proxypp_sec_info, const ddsi_plist_t *plist, nn_security_info_t *info) +bool q_omg_writer_is_discovery_protected(const struct writer *wr) +{ + assert (wr != NULL); + return wr->sec_attr != NULL && wr->sec_attr->attr.is_discovery_protected; +} + +bool q_omg_writer_is_submessage_protected(const struct writer *wr) +{ + assert (wr != NULL); + return wr->sec_attr != NULL && wr->sec_attr->attr.is_submessage_protected; +} + +bool q_omg_writer_is_payload_protected(const struct writer *wr) +{ + assert (wr != NULL); + return wr->sec_attr != NULL && wr->sec_attr->attr.is_payload_protected; +} + +bool q_omg_security_check_remote_writer_permissions(const struct proxy_writer *pwr, uint32_t domain_id, struct participant *pp) +{ + struct ddsi_domaingv *gv = pp->e.gv; + struct dds_security_context *sc = q_omg_security_get_secure_context(pp); + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + DDS_Security_PublicationBuiltinTopicDataSecure publication_data; + bool ok = true; + + if (!sc) + return true; + + if (!q_omg_proxy_participant_is_secure(pwr->c.proxypp)) + { + if (q_omg_participant_allow_unauthenticated(pp)) + { + GVTRACE (" allow non-secure remote writer "PGUIDFMT, PGUID (pwr->e.guid)); + return true; + } + else + { + GVWARNING("Non secure remote writer "PGUIDFMT" is not allowed.", PGUID(pwr->e.guid)); + return false; + } + } + + if (SECURITY_INFO_IS_WRITE_PROTECTED(pwr->security_info)) + { + DDS_Security_PermissionsHandle permissions_handle; + + if ((permissions_handle = get_permissions_handle(pp, pwr->c.proxypp)) != 0) + { + GVTRACE("Secure remote writer "PGUIDFMT" proxypp does not have permissions handle yet\n", PGUID(pwr->e.guid)); + return false; + } + else + { + q_omg_shallow_copy_PublicationBuiltinTopicDataSecure(&publication_data, &pwr->e.guid, pwr->c.xqos, &pwr->security_info); + ok = sc->access_control_context->check_remote_datawriter(sc->access_control_context, permissions_handle, (int)domain_id, &publication_data, &exception); + q_omg_shallow_free_PublicationBuiltinTopicDataSecure(&publication_data); + if (!ok) + { + if (!is_topic_discovery_protected(pp->sec_attr->permissions_handle, sc->access_control_context, publication_data.topic_name)) + EXCEPTION_ERROR(sc, &exception, "Access control does not allow remote writer "PGUIDFMT": %s", PGUID(pwr->e.guid)); + else + DDS_Security_Exception_reset(&exception); + } + } + } + + return ok; +} + +static void send_reader_crypto_tokens(struct reader *rd, struct proxy_writer *pwr, DDS_Security_DatareaderCryptoHandle local_crypto, DDS_Security_DatawriterCryptoHandle remote_crypto) +{ + struct dds_security_context *sc = q_omg_security_get_secure_context(rd->c.pp); + struct ddsi_domaingv *gv = rd->e.gv; + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + DDS_Security_DatawriterCryptoTokenSeq tokens = {0, 0, NULL}; + bool r; + + GVTRACE("send reader tokens "PGUIDFMT" to writer "PGUIDFMT"\n", PGUID(rd->e.guid), PGUID(pwr->e.guid)); + + r = sc->crypto_context->crypto_key_exchange->create_local_datareader_crypto_tokens(sc->crypto_context->crypto_key_exchange, &tokens, local_crypto, remote_crypto, &exception); + if (!r) + EXCEPTION_ERROR(sc, &exception,"Failed to create local reader crypto tokens "PGUIDFMT" for remote writer "PGUIDFMT, PGUID(rd->e.guid), PGUID(pwr->e.guid)); + else if (tokens._length > 0) + { + nn_dataholderseq_t tholder; + + q_omg_shallow_copyout_DataHolderSeq(&tholder, &tokens); + write_crypto_reader_tokens(rd, pwr, &tholder); + q_omg_shallow_free_nn_dataholderseq(&tholder); + + if (!sc->crypto_context->crypto_key_exchange->return_crypto_tokens(sc->crypto_context->crypto_key_exchange, &tokens, &exception)) + EXCEPTION_ERROR(sc, &exception, "Failed to return local reader crypto tokens "PGUIDFMT" for remote writer "PGUIDFMT, PGUID(rd->e.guid), PGUID(pwr->e.guid)); + } +} + +static bool q_omg_security_register_remote_writer_match(struct proxy_writer *pwr, struct reader *rd, int64_t *crypto_handle) +{ + struct participant *pp = rd->c.pp; + struct proxy_participant *proxypp = pwr->c.proxypp; + struct ddsi_domaingv *gv = pp->e.gv; + struct dds_security_context *sc = q_omg_security_get_secure_context(pp); + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + struct proxypp_pp_match *pm; + struct security_entity_match *match; + bool send_tokens = false; + + ddsrt_mutex_lock(&proxypp->sec_attr->lock); + pm = ddsrt_avl_lookup(&proxypp_pp_treedef, &proxypp->sec_attr->participants, &pp->sec_attr->crypto_handle); + ddsrt_mutex_unlock(&proxypp->sec_attr->lock); + + if (!pm) + return false; + + /* TODO: the security_entity_match should be removed after the the received tokens are stored in the plugin. + * Currently the security_entity_match is also used to detect if a match between a reader and writer has + * already been completed. + */ + ddsrt_mutex_lock(&rd->e.lock); + match = find_or_create_entity_match(gv->security_matches, &pwr->e.guid, &rd->e.guid); + if (match->matched) + *crypto_handle = match->crypto_handle; + else + { + /* Generate writer crypto info. */ + match->crypto_handle = sc->crypto_context->crypto_key_factory->register_matched_remote_datawriter( + sc->crypto_context->crypto_key_factory, rd->sec_attr->crypto_handle, proxypp->sec_attr->crypto_handle, pm->shared_secret, &exception); + + *crypto_handle = match->crypto_handle; + + if (match->crypto_handle == 0) + EXCEPTION_ERROR(sc, &exception, "Failed to register remote writer "PGUIDFMT" with reader "PGUIDFMT, PGUID(pwr->e.guid), PGUID(rd->e.guid)); + else if (rd->e.guid.entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER) + { + /* The builtin ParticipantVolatileSecure endpoints do not exchange tokens. + * Simulate that we already got them. */ + match->matched = true; + GVTRACE(" volatile secure reader: proxypp_crypto=%"PRId64" rd_crypto=%"PRId64" pwr_crypto=%"PRId64"\n", proxypp->sec_attr->crypto_handle, rd->sec_attr->crypto_handle, match->crypto_handle); + } + else + { + send_tokens = true; + if (match->tokens) + { + if (sc->crypto_context->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + sc->crypto_context->crypto_key_exchange, rd->sec_attr->crypto_handle, match->crypto_handle, match->tokens, &exception)) + { + match->matched = true; + DDS_Security_DataHolderSeq_free(match->tokens); + match->tokens = NULL; + GVTRACE("match_remote_writer "PGUIDFMT" with reader "PGUIDFMT": tokens available\n", PGUID(pwr->e.guid), PGUID(rd->e.guid)); + } + else + EXCEPTION_ERROR(sc, &exception, "Failed to set remote writer crypto tokens "PGUIDFMT" --> "PGUIDFMT, PGUID(pwr->e.guid), PGUID(rd->e.guid)); + } + } + } + ddsrt_mutex_unlock(&rd->e.lock); + + if (send_tokens) + (void)send_reader_crypto_tokens(rd, pwr, rd->sec_attr->crypto_handle, match->crypto_handle); + + return match->matched; +} + +bool q_omg_security_match_remote_writer_enabled(struct reader *rd, struct proxy_writer *pwr, int64_t *crypto_handle) +{ + struct ddsi_domaingv *gv = rd->e.gv; + nn_security_info_t info; + + if (!rd->sec_attr) + return true; + + /* + * Check if the security settings match by checking the attributes. + * + * The attributes will be 0 when security is not enabled for the related + * federation or the security configuration told that this endpoint should + * not be protected. + * + * This can mean that an unprotected endpoint of a secure federation can + * connect to an endpoint of a non-secure federation. However, that will + * be blocked by q_omg_security_check_remote_writer_permissions() if + * q_omg_participant_allow_unauthenticated() returns FALSE there. + */ + (void)q_omg_get_reader_security_info(rd, &info); + if (!SECURITY_INFO_COMPATIBLE(pwr->security_info, info, NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID)) + { + GVWARNING("match_remote_writer "PGUIDFMT" with reader "PGUIDFMT" security_attributes mismatch: 0x%08x.0x%08x - 0x%08x.0x%08x\n", + PGUID(pwr->e.guid), PGUID(rd->e.guid), + pwr->security_info.security_attributes, pwr->security_info.plugin_security_attributes, + info.security_attributes, info.plugin_security_attributes); + return false; + } + + if ((!rd->sec_attr->attr.is_payload_protected ) && (!rd->sec_attr->attr.is_submessage_protected)) + return true; + + if (!q_omg_proxy_participant_is_secure(pwr->c.proxypp)) + { + /* Remote proxy was downgraded to a non-secure participant, + * but the local endpoint is protected. */ + return false; + } + + /* We previously checked for attribute compatibility. That doesn't + * mean equal, because compatibility depends on the valid flag. + * Some products don't properly send the attributes, in which case + * the valid flag is 0. To be able to support these product, assume + * that the attributes are the same. If there is actually a mismatch, + * communication will fail at a later moment anyway. */ + if (!SECURITY_ATTR_IS_VALID(pwr->security_info.security_attributes)) { + pwr->security_info.security_attributes = info.security_attributes; + } + if (!SECURITY_ATTR_IS_VALID(pwr->security_info.plugin_security_attributes)) { + pwr->security_info.plugin_security_attributes = info.plugin_security_attributes; + } + + return q_omg_security_register_remote_writer_match(pwr, rd, crypto_handle); +} + +void q_omg_security_deregister_remote_writer_match(const struct ddsi_domaingv *gv, const ddsi_guid_t *rd_guid, struct rd_pwr_match *m) +{ + struct dds_security_context *sc = gv->security_context; + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + struct security_entity_match *match = NULL; + + if (m->crypto_handle != 0) + { + match = remove_entity_match(gv->security_matches, &m->pwr_guid, rd_guid); + if (match) + { + assert(match->crypto_handle == m->crypto_handle); + if (!sc->crypto_context->crypto_key_factory->unregister_datawriter(sc->crypto_context->crypto_key_factory, match->crypto_handle, &exception)) + EXCEPTION_ERROR(sc, &exception, "Failed to unregster remote writer "PGUIDFMT" for reader "PGUIDFMT, PGUID(m->pwr_guid), PGUID(*rd_guid)); + entity_match_free(match); + } + } +} + +bool q_omg_security_check_remote_reader_permissions(const struct proxy_reader *prd, uint32_t domain_id, struct participant *pp) +{ + struct ddsi_domaingv *gv = pp->e.gv; + struct dds_security_context *sc = q_omg_security_get_secure_context(pp); + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + bool ok = true; + + if (!sc) + return true; + + if (!q_omg_proxy_participant_is_secure(prd->c.proxypp)) + { + if (q_omg_participant_allow_unauthenticated(pp)) + { + GVTRACE (" allow non-secure remote reader "PGUIDFMT, PGUID (prd->e.guid)); + return true; + } + else + { + GVWARNING("Non secure remote reader "PGUIDFMT" is not allowed.", PGUID(prd->e.guid)); + return false; + } + } + + if (SECURITY_INFO_IS_READ_PROTECTED(prd->security_info)) + { + DDS_Security_PermissionsHandle permissions_handle; + + if ((permissions_handle = get_permissions_handle(pp, prd->c.proxypp)) != 0) + { + GVTRACE("Secure remote reader "PGUIDFMT" proxypp does not have permissions handle yet\n", PGUID(prd->e.guid)); + return false; + } + else + { + DDS_Security_SubscriptionBuiltinTopicDataSecure subscription_data; + + q_omg_shallow_copy_SubscriptionBuiltinTopicDataSecure(&subscription_data, &prd->e.guid, prd->c.xqos, &prd->security_info); + ok = sc->access_control_context->check_remote_datareader(sc->access_control_context, permissions_handle, (int)domain_id, &subscription_data, false, &exception); + q_omg_shallow_free_SubscriptionBuiltinTopicDataSecure(&subscription_data); + if (!ok) + { + if (!is_topic_discovery_protected(pp->sec_attr->permissions_handle, sc->access_control_context, subscription_data.topic_name)) + EXCEPTION_ERROR(sc, &exception, "Access control does not allow remote reader "PGUIDFMT": %s", PGUID(prd->e.guid)); + else + DDS_Security_Exception_reset(&exception); + } + } + } + + return ok; +} + +static void q_omg_get_proxy_endpoint_security_info(const struct entity_common *entity, nn_security_info_t *proxypp_sec_info, const ddsi_plist_t *plist, nn_security_info_t *info) { const bool proxypp_info_available = (proxypp_sec_info->security_attributes != 0 || proxypp_sec_info->plugin_security_attributes != 0); @@ -600,120 +2274,821 @@ static void q_omg_get_proxy_endpoint_security_info (const struct entity_common * } } -void set_proxy_reader_security_info (struct proxy_reader *prd, const ddsi_plist_t *plist) +void q_omg_get_proxy_reader_security_info(struct proxy_reader *prd, const ddsi_plist_t *plist, nn_security_info_t *info) +{ + q_omg_get_proxy_endpoint_security_info(&(prd->e), &(prd->c.proxypp->security_info), plist, info); +} + +void set_proxy_reader_security_info(struct proxy_reader *prd, const ddsi_plist_t *plist) { assert (prd); q_omg_get_proxy_endpoint_security_info (&prd->e, &prd->c.proxypp->security_info, plist, &prd->c.security_info); } -void set_proxy_writer_security_info (struct proxy_writer *pwr, const ddsi_plist_t *plist) + +void q_omg_get_proxy_writer_security_info(struct proxy_writer *pwr, const ddsi_plist_t *plist, nn_security_info_t *info) +{ + q_omg_get_proxy_endpoint_security_info(&(pwr->e), &(pwr->c.proxypp->security_info), plist, info); +} + +void set_proxy_writer_security_info(struct proxy_writer *pwr, const ddsi_plist_t *plist) { assert (pwr); q_omg_get_proxy_endpoint_security_info (&pwr->e, &pwr->c.proxypp->security_info, plist, &pwr->c.security_info); } - -static bool q_omg_security_encode_datareader_submessage (struct reader *rd, const ddsi_guid_prefix_t *dst_prefix, const unsigned char *src_buf, size_t src_len, unsigned char **dst_buf, size_t *dst_len) +void q_omg_security_deregister_remote_reader_match(const struct ddsi_domaingv *gv, const ddsi_guid_t *wr_guid, struct wr_prd_match *m) { - /* TODO: Use proper keys to actually encode (need key-exchange). */ - DDSRT_UNUSED_ARG (rd); - DDSRT_UNUSED_ARG (dst_prefix); - DDSRT_UNUSED_ARG (src_buf); - DDSRT_UNUSED_ARG (src_len); - DDSRT_UNUSED_ARG (dst_buf); - DDSRT_UNUSED_ARG (dst_len); - return false; + struct dds_security_context *sc = gv->security_context; + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + struct security_entity_match *match = NULL; + + if (m->crypto_handle) + { + match = remove_entity_match(gv->security_matches, &m->prd_guid, wr_guid); + if (match) + { + assert(match->crypto_handle == m->crypto_handle); + + if (!sc->crypto_context->crypto_key_factory->unregister_datareader(sc->crypto_context->crypto_key_factory, match->crypto_handle, &exception)) + EXCEPTION_ERROR(sc, &exception, "Failed to unregister remote reader "PGUIDFMT" for writer "PGUIDFMT, PGUID(m->prd_guid), PGUID(*wr_guid)); + entity_match_free(match); + } + } +} + +static void send_writer_crypto_tokens(struct writer *wr, struct proxy_reader *prd, DDS_Security_DatawriterCryptoHandle local_crypto, DDS_Security_DatareaderCryptoHandle remote_crypto) +{ + struct dds_security_context *sc = q_omg_security_get_secure_context(wr->c.pp); + struct ddsi_domaingv *gv = wr->e.gv; + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + DDS_Security_DatawriterCryptoTokenSeq tokens = {0, 0, NULL}; + bool r; + + GVTRACE("send writer tokens "PGUIDFMT" to reader "PGUIDFMT"\n", PGUID(wr->e.guid), PGUID(prd->e.guid)); + + r = sc->crypto_context->crypto_key_exchange->create_local_datawriter_crypto_tokens(sc->crypto_context->crypto_key_exchange, &tokens, local_crypto, remote_crypto, &exception); + if (!r) + EXCEPTION_ERROR(sc, &exception,"Failed to create local writer crypto tokens "PGUIDFMT" for remote reader "PGUIDFMT, PGUID(wr->e.guid), PGUID(prd->e.guid)); + else if (tokens._length > 0) + { + nn_dataholderseq_t tholder; + + q_omg_shallow_copyout_DataHolderSeq(&tholder, &tokens); + write_crypto_writer_tokens(wr, prd, &tholder); + q_omg_shallow_free_nn_dataholderseq(&tholder); + + if (!sc->crypto_context->crypto_key_exchange->return_crypto_tokens(sc->crypto_context->crypto_key_exchange, &tokens, &exception)) + EXCEPTION_ERROR(sc, &exception, "Failed to return local writer crypto tokens "PGUIDFMT" for remote reader "PGUIDFMT, PGUID(wr->e.guid), PGUID(prd->e.guid)); + } +} + +static bool q_omg_security_register_remote_reader_match(struct proxy_reader *prd, struct writer *wr, int64_t *crypto_handle) +{ + struct participant *pp = wr->c.pp; + struct proxy_participant *proxypp = prd->c.proxypp; + struct ddsi_domaingv *gv = pp->e.gv; + struct dds_security_context *sc = q_omg_security_get_secure_context(pp); + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + struct proxypp_pp_match *pm; + struct security_entity_match *match; + bool send_tokens = false; + + *crypto_handle = 0; + + ddsrt_mutex_lock(&proxypp->sec_attr->lock); + pm = ddsrt_avl_lookup(&proxypp_pp_treedef, &proxypp->sec_attr->participants, &pp->sec_attr->crypto_handle); + ddsrt_mutex_unlock(&proxypp->sec_attr->lock); + if (!pm) + return false; + + /* TODO: the security_entity_match should be removed after the the received tokens are stored in the plugin. + * Currently the security_entity_match is also used to detect if a match between a reader and writer has + * already been completed. + */ + ddsrt_mutex_lock(&wr->e.lock); + match = find_or_create_entity_match(gv->security_matches, &prd->e.guid, &wr->e.guid); + if (match->matched) + *crypto_handle = match->crypto_handle; + else + { + /* Generate writer crypto info. */ + match->crypto_handle = sc->crypto_context->crypto_key_factory->register_matched_remote_datareader( + sc->crypto_context->crypto_key_factory, wr->sec_attr->crypto_handle, proxypp->sec_attr->crypto_handle, pm->shared_secret, false, &exception); + + *crypto_handle = match->crypto_handle; + + if (match->crypto_handle == 0) + EXCEPTION_ERROR(sc, &exception, "Failed to register remote reader "PGUIDFMT" with writer "PGUIDFMT, PGUID(prd->e.guid), PGUID(wr->e.guid)); + else if (wr->e.guid.entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER) + { + /* The builtin ParticipantVolatileSecure endpoints do not exchange tokens. + * Simulate that we already got them. */ + match->matched = true; + GVTRACE(" volatile secure writer: proxypp_crypto=%"PRId64" wr_crypto=%"PRId64" prd_crypto=%"PRId64"\n", proxypp->sec_attr->crypto_handle, wr->sec_attr->crypto_handle, match->crypto_handle); + } + else + { + send_tokens = true; + if (match->tokens) + { + if (sc->crypto_context->crypto_key_exchange->set_remote_datareader_crypto_tokens( + sc->crypto_context->crypto_key_exchange, wr->sec_attr->crypto_handle, match->crypto_handle, match->tokens, &exception)) + { + match->matched = true; + DDS_Security_DataHolderSeq_free(match->tokens); + match->tokens = NULL;; + GVTRACE("match_remote_reader "PGUIDFMT" with writer "PGUIDFMT": tokens available\n", PGUID(prd->e.guid), PGUID(wr->e.guid)); + } + else + EXCEPTION_ERROR(sc, &exception, "Failed to set remote reader crypto tokens "PGUIDFMT" --> "PGUIDFMT, PGUID(prd->e.guid), PGUID(wr->e.guid)); + } + else if (!wr->sec_attr->attr.is_submessage_protected) + match->matched = true; + } + } + ddsrt_mutex_unlock(&wr->e.lock); + + if (send_tokens) + (void)send_writer_crypto_tokens(wr, prd, wr->sec_attr->crypto_handle, match->crypto_handle); + + return match->matched; +} + +bool q_omg_security_match_remote_reader_enabled(struct writer *wr, struct proxy_reader *prd, int64_t *crypto_handle) +{ + struct ddsi_domaingv *gv = wr->e.gv; + nn_security_info_t info; + + if (!wr->sec_attr) + return true; + + /* + * Check if the security settings match by checking the attributes. + * + * The attributes will be 0 when security is not enabled for the related + * federation or the security configuration told that this endpoint should + * not be protected. + * + * This can mean that an unprotected endpoint of a secure federation can + * connect to an endpoint of a non-secure federation. However, that will + * be blocked by q_omg_security_check_remote_reader_permissions() if + * q_omg_participant_allow_unauthenticated() returns FALSE there. + */ + (void)q_omg_get_writer_security_info(wr, &info); + if (!SECURITY_INFO_COMPATIBLE(prd->security_info, info, NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID)) + { + GVWARNING("match_remote_reader "PGUIDFMT" with writer "PGUIDFMT" security_attributes mismatch: 0x%08x.0x%08x - 0x%08x.0x%08x\n", + PGUID(prd->e.guid), PGUID(wr->e.guid), + prd->security_info.security_attributes, prd->security_info.plugin_security_attributes, + info.security_attributes, info.plugin_security_attributes); + return false; + } + + if (!wr->sec_attr->attr.is_submessage_protected && !wr->sec_attr->attr.is_payload_protected) + return true; + + if (!q_omg_proxy_participant_is_secure(prd->c.proxypp)) + { + /* Remote proxy was downgraded to a non-secure participant, + * but the local endpoint is protected. */ + return false; + } + + /* We previously checked for attribute compatibility. That doesn't + * mean equal, because compatibility depends on the valid flag. + * Some products don't properly send the attributes, in which case + * the valid flag is 0. To be able to support these product, assume + * that the attributes are the same. If there is actually a mismatch, + * communication will fail at a later moment anyway. */ + if (!SECURITY_ATTR_IS_VALID(prd->security_info.security_attributes)) { + prd->security_info.security_attributes = info.security_attributes; + } + if (!SECURITY_ATTR_IS_VALID(prd->security_info.plugin_security_attributes)) { + prd->security_info.plugin_security_attributes = info.plugin_security_attributes; + } + + return q_omg_security_register_remote_reader_match(prd, wr, crypto_handle); +} + +void q_omg_security_set_remote_writer_crypto_tokens(struct reader *rd, const ddsi_guid_t *pwr_guid, const nn_dataholderseq_t *tokens) +{ + struct dds_security_context *sc = q_omg_security_get_secure_context(rd->c.pp); + struct ddsi_domaingv *gv = rd->e.gv; + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + struct security_entity_match *match; + struct proxy_writer *pwr = NULL; + + if (!sc) + return; + + ddsrt_mutex_lock(&rd->e.lock); + match = find_or_create_entity_match(gv->security_matches, pwr_guid, &rd->e.guid); + if (match->matched) + { + ddsrt_mutex_unlock(&rd->e.lock); + return; + } + + DDS_Security_DatawriterCryptoTokenSeq * tseq = DDS_Security_DataHolderSeq_alloc(); + q_omg_copyin_DataHolderSeq(tseq, tokens); + + if ((pwr = entidx_lookup_proxy_writer_guid(gv->entity_index, pwr_guid)) == NULL || match->crypto_handle == 0 ) + { + GVTRACE("remember writer tokens src("PGUIDFMT") dst("PGUIDFMT")\n", PGUID(*pwr_guid), PGUID(rd->e.guid)); + match->tokens = tseq; + } + else + { + if (sc->crypto_context->crypto_key_exchange->set_remote_datawriter_crypto_tokens(sc->crypto_context->crypto_key_exchange, rd->sec_attr->crypto_handle, match->crypto_handle, tseq, &exception)) + { + GVTRACE("set_remote_writer_crypto_tokens "PGUIDFMT" with reader "PGUIDFMT"\n", PGUID(pwr->e.guid), PGUID(rd->e.guid)); + match->matched = true; + DDS_Security_DataHolderSeq_free(tseq); + } + else + EXCEPTION_ERROR(sc, &exception, "Failed to set remote writer crypto tokens "PGUIDFMT" for reader "PGUIDFMT, PGUID(pwr->e.guid), PGUID(rd->e.guid)); + } + ddsrt_mutex_unlock(&rd->e.lock); + + if (match->matched) + connect_reader_with_proxy_writer_secure(rd, pwr, now_mt (), match->crypto_handle); + + if (pwr) + notify_handshake_recv_token(rd->c.pp, pwr->c.proxypp); +} + +void q_omg_security_set_remote_reader_crypto_tokens(struct writer *wr, const ddsi_guid_t *prd_guid, const nn_dataholderseq_t *tokens) +{ + struct dds_security_context *sc = q_omg_security_get_secure_context(wr->c.pp); + struct ddsi_domaingv *gv = wr->e.gv; + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + struct security_entity_match *match; + struct proxy_reader *prd = NULL; + + if (!sc) + return; + + ddsrt_mutex_lock(&wr->e.lock); + match = find_or_create_entity_match(gv->security_matches, prd_guid, &wr->e.guid); + if (match->matched) + { + ddsrt_mutex_unlock(&wr->e.lock); + return; + } + + DDS_Security_DatawriterCryptoTokenSeq *tseq = DDS_Security_DataHolderSeq_alloc(); + q_omg_copyin_DataHolderSeq(tseq, tokens); + + if (((prd = entidx_lookup_proxy_reader_guid(gv->entity_index, prd_guid)) == NULL) || (match->crypto_handle == 0)) + { + GVTRACE("remember reader tokens src("PGUIDFMT") dst("PGUIDFMT")\n", PGUID(*prd_guid), PGUID(wr->e.guid)); + match->tokens = tseq; + } + else + { + if (sc->crypto_context->crypto_key_exchange->set_remote_datareader_crypto_tokens(sc->crypto_context->crypto_key_exchange, wr->sec_attr->crypto_handle, match->crypto_handle, tseq, &exception)) + { + GVTRACE("set_remote_reader_crypto_tokens "PGUIDFMT" with writer "PGUIDFMT"\n", PGUID(prd->e.guid), PGUID(wr->e.guid)); + match->matched = true; + DDS_Security_DataHolderSeq_free(tseq); + } + else + EXCEPTION_ERROR(sc, &exception, "Failed to set remote reader crypto tokens "PGUIDFMT" for writer "PGUIDFMT, PGUID(prd->e.guid), PGUID(wr->e.guid)); + } + ddsrt_mutex_unlock(&wr->e.lock); + + if (match->matched) + connect_writer_with_proxy_reader_secure(wr, prd, now_mt (), match->crypto_handle); + + if (prd) + notify_handshake_recv_token(wr->c.pp, prd->c.proxypp); +} + +bool q_omg_reader_is_discovery_protected(const struct reader *rd) +{ + assert (rd != NULL); + return rd->sec_attr != NULL && rd->sec_attr->attr.is_discovery_protected; +} + +static bool q_omg_security_encode_datareader_submessage(struct reader *rd, const ddsi_guid_prefix_t *dst_prefix, const unsigned char *src_buf, size_t src_len, unsigned char **dst_buf, size_t *dst_len) +{ + DDS_Security_SecurityException ex = DDS_SECURITY_EXCEPTION_INIT; + struct rd_pwr_match *m; + ddsrt_avl_iter_t it; + DDS_Security_DatareaderCryptoHandleSeq hdls = { 0, 0, NULL }; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq plain_buffer; + bool result = false; + int32_t idx = 0; + + assert (rd); + assert (src_len <= UINT32_MAX); + assert (src_buf); + assert (dst_len); + assert (dst_buf); + assert (rd->sec_attr); + assert (q_omg_reader_is_submessage_protected (rd)); + + const struct ddsi_domaingv *gv = rd->e.gv; + const struct dds_security_context *sc = q_omg_security_get_secure_context (rd->c.pp); + assert (sc); + + GVTRACE (" encode_datareader_submessage "PGUIDFMT" %s/%s", PGUID (rd->e.guid), get_reader_topic_name (rd), rd->topic ? rd->topic->type_name : "(null)"); + // FIXME: print_buf(src_buf, src_len, "q_omg_security_encode_datareader_submessage(SOURCE)"); + + ddsrt_mutex_lock (&rd->e.lock); + hdls._buffer = DDS_Security_DatawriterCryptoHandleSeq_allocbuf (rd->num_writers); + hdls._maximum = rd->num_writers; + for (m = ddsrt_avl_iter_first (&rd_writers_treedef, &rd->writers, &it); m; m = ddsrt_avl_iter_next (&it)) + { + if (m->crypto_handle && (!dst_prefix || guid_prefix_eq (&m->pwr_guid.prefix, dst_prefix))) + hdls._buffer[idx++] = m->crypto_handle; + } + ddsrt_mutex_unlock (&rd->e.lock); + + if ((hdls._length = (DDS_Security_unsigned_long) idx) == 0) + { + GVTRACE ("Submsg encoding failed for datareader "PGUIDFMT" %s/%s: no matching writers\n", PGUID (rd->e.guid), + get_reader_topic_name (rd), rd->topic ? rd->topic->type_name : "(null)"); + goto err_enc_drd_subm; + } + + memset (&encoded_buffer, 0, sizeof (encoded_buffer)); + plain_buffer._buffer = (DDS_Security_octet*) src_buf; + plain_buffer._length = (uint32_t) src_len; + plain_buffer._maximum = (uint32_t) src_len; + + if (!(result = sc->crypto_context->crypto_transform->encode_datareader_submessage ( + sc->crypto_context->crypto_transform, &encoded_buffer, &plain_buffer, rd->sec_attr->crypto_handle, &hdls, &ex))) + { + GVWARNING ("Submsg encoding failed for datareader "PGUIDFMT" %s/%s: %s", PGUID (rd->e.guid), get_reader_topic_name (rd), + rd->topic ? rd->topic->type_name : "(null)", ex.message ? ex.message : "Unknown error"); + GVTRACE ("\n"); + DDS_Security_Exception_reset (&ex); + goto err_enc_drd_subm; + } + assert (encoded_buffer._buffer); + *dst_buf = encoded_buffer._buffer; + *dst_len = encoded_buffer._length; + // FIXME: print_buf (*dst_buf, *dst_len, "q_omg_security_encode_datareader_submessage(DEST)"); + goto end_enc_drd_subm; + +err_enc_drd_subm: + *dst_buf = NULL; + *dst_len = 0; + +end_enc_drd_subm: + DDS_Security_DatawriterCryptoHandleSeq_freebuf (&hdls); + return result; } static bool q_omg_security_encode_datawriter_submessage (struct writer *wr, const ddsi_guid_prefix_t *dst_prefix, const unsigned char *src_buf, size_t src_len, unsigned char **dst_buf, size_t *dst_len) { - /* TODO: Use proper keys to actually encode (need key-exchange). */ - DDSRT_UNUSED_ARG (wr); - DDSRT_UNUSED_ARG (dst_prefix); - DDSRT_UNUSED_ARG (src_buf); - DDSRT_UNUSED_ARG (src_len); - DDSRT_UNUSED_ARG (dst_buf); - DDSRT_UNUSED_ARG (dst_len); - return false; + DDS_Security_SecurityException ex = DDS_SECURITY_EXCEPTION_INIT; + struct wr_prd_match *m; + ddsrt_avl_iter_t it; + DDS_Security_DatareaderCryptoHandleSeq hdls = { 0, 0, NULL }; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq plain_buffer; + bool result = false; + int32_t idx = 0; + + assert (wr); + assert (src_len <= UINT32_MAX); + assert (src_buf); + assert (dst_len); + assert (dst_buf); + assert (wr->sec_attr); + assert (q_omg_writer_is_submessage_protected (wr)); + ASSERT_MUTEX_HELD (wr->e.lock); + + const struct ddsi_domaingv *gv = wr->e.gv; + const struct dds_security_context *sc = q_omg_security_get_secure_context (wr->c.pp); + assert (sc); + + GVTRACE (" encode_datawriter_submessage "PGUIDFMT" %s/%s", PGUID (wr->e.guid), get_writer_topic_name (wr), wr->topic ? wr->topic->type_name : "(null)"); + + // FIXME: print_buf(src_buf, src_len, "q_omg_security_encode_datawriter_submessage(SOURCE)"); + + hdls._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf (wr->num_readers); + hdls._maximum = wr->num_readers; + for (m = ddsrt_avl_iter_first (&wr_readers_treedef, &wr->readers, &it); m; m = ddsrt_avl_iter_next (&it)) + { + if (m->crypto_handle && (!dst_prefix || guid_prefix_eq (&m->prd_guid.prefix, dst_prefix))) + hdls._buffer[idx++] = m->crypto_handle; + } + + if ((hdls._length = (DDS_Security_unsigned_long) idx) == 0) + { + GVTRACE ("Submsg encoding failed for datawriter "PGUIDFMT" %s/%s: no matching readers\n", PGUID (wr->e.guid), + get_writer_topic_name (wr), wr->topic ? wr->topic->type_name : "(null)"); + goto err_enc_dwr_subm; + } + + memset (&encoded_buffer, 0, sizeof (encoded_buffer)); + plain_buffer._buffer = (DDS_Security_octet*) src_buf; + plain_buffer._length = (uint32_t) src_len; + plain_buffer._maximum = (uint32_t) src_len; + result = true; + idx = 0; + while (result && idx < (int32_t)hdls._length) + { + /* If the plugin thinks a new call is unnecessary, the index will be set to the size of the hdls sequence. */ + result = sc->crypto_context->crypto_transform->encode_datawriter_submessage (sc->crypto_context->crypto_transform, + &encoded_buffer, &plain_buffer, wr->sec_attr->crypto_handle, &hdls, &idx, &ex); + + /* With a possible second call to encode, the plain buffer should be NULL. */ + plain_buffer._buffer = NULL; + plain_buffer._length = 0; + plain_buffer._maximum = 0; + } + + if (!result) + { + GVWARNING ("Submsg encoding failed for datawriter "PGUIDFMT" %s/%s: %s", PGUID (wr->e.guid), get_writer_topic_name (wr), + wr->topic ? wr->topic->type_name : "(null)", ex.message ? ex.message : "Unknown error"); + GVTRACE ("\n"); + DDS_Security_Exception_reset (&ex); + goto err_enc_dwr_subm; + } + + assert (encoded_buffer._buffer); + *dst_buf = encoded_buffer._buffer; + *dst_len = encoded_buffer._length; + // FIXME: print_buf (*dst_buf, *dst_len, "q_omg_security_encode_datawriter_submessage(DEST)"); + goto end_enc_dwr_subm; + +err_enc_dwr_subm: + *dst_buf = NULL; + *dst_len = 0; + +end_enc_dwr_subm: + DDS_Security_DatareaderCryptoHandleSeq_freebuf (&hdls); + return result; } -static bool q_omg_security_decode_submessage (const ddsi_guid_prefix_t * const src_prefix, const ddsi_guid_prefix_t * const dst_prefix, const unsigned char *src_buf, size_t src_len, unsigned char **dst_buf, size_t *dst_len) +static bool q_omg_security_decode_submessage (const struct ddsi_domaingv *gv, const ddsi_guid_prefix_t * const src_prefix, const ddsi_guid_prefix_t * const dst_prefix, const unsigned char *src_buf, size_t src_len, unsigned char **dst_buf, size_t *dst_len) { - /* TODO: Use proper keys to actually decode (need key-exchange). */ - DDSRT_UNUSED_ARG (src_prefix); - DDSRT_UNUSED_ARG (dst_prefix); - DDSRT_UNUSED_ARG (src_buf); - DDSRT_UNUSED_ARG (src_len); - DDSRT_UNUSED_ARG (dst_buf); - DDSRT_UNUSED_ARG (dst_len); - return false; + DDS_Security_SecurityException ex = DDS_SECURITY_EXCEPTION_INIT; + struct dds_security_context *sc = gv->security_context; + DDS_Security_SecureSubmessageCategory_t cat = 0; + DDS_Security_DatawriterCryptoHandle pp_crypto_hdl = DDS_SECURITY_HANDLE_NIL; + DDS_Security_DatawriterCryptoHandle proxypp_crypto_hdl = DDS_SECURITY_HANDLE_NIL; + DDS_Security_DatawriterCryptoHandle wr_crypto_hdl = DDS_SECURITY_HANDLE_NIL; + DDS_Security_DatareaderCryptoHandle rd_crypto_hdl = DDS_SECURITY_HANDLE_NIL; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq plain_buffer; + struct participant *pp = NULL; + struct proxy_participant *proxypp; + ddsi_guid_t proxypp_guid, pp_guid = { .prefix= {.u = {0,0,0} }, .entityid.u = 0 }; + bool result; + + assert (src_len <= UINT32_MAX); + assert (src_buf); + assert (dst_len); + assert (dst_buf); + + // FIXME: print_buf(src_buf, src_len, "q_omg_security_decode_submessage(SOURCE)"); + + proxypp_guid.prefix = *src_prefix; + proxypp_guid.entityid.u = NN_ENTITYID_PARTICIPANT; + if (!(proxypp = entidx_lookup_proxy_participant_guid (gv->entity_index, &proxypp_guid))) + { + GVTRACE (" Unknown remote participant "PGUIDFMT" for decoding submsg\n", PGUID (proxypp_guid)); + return false; + } + if (!proxypp->sec_attr) + { + GVTRACE (" Remote participant "PGUIDFMT" not secure for decoding submsg\n", PGUID (proxypp_guid)); + return false; + } + proxypp_crypto_hdl = proxypp->sec_attr->crypto_handle; + + if (proxypp_crypto_hdl == DDS_SECURITY_HANDLE_NIL) + { + GVTRACE (" Remote participant "PGUIDFMT" not matched yet for decoding submsg\n", PGUID (proxypp_guid)); + return false; + } + + if (dst_prefix && !guid_prefix_zero (dst_prefix)) + { + pp_guid.prefix = *dst_prefix; + pp_guid.entityid.u = NN_ENTITYID_PARTICIPANT; + if (!(pp = entidx_lookup_participant_guid (gv->entity_index, &pp_guid))) + return false; + pp_crypto_hdl = pp->sec_attr->crypto_handle; + } + + GVTRACE(" decode: pp_crypto=%"PRId64" proxypp_crypto=%"PRId64"\n", pp_crypto_hdl, proxypp_crypto_hdl); + /* Prepare buffers. */ + memset (&plain_buffer, 0, sizeof (plain_buffer)); + encoded_buffer._buffer = (DDS_Security_octet*) src_buf; + encoded_buffer._length = (uint32_t) src_len; + encoded_buffer._maximum = (uint32_t) src_len; + + /* Determine how the RTPS sub-message was encoded. */ + assert (sc); + result = sc->crypto_context->crypto_transform->preprocess_secure_submsg (sc->crypto_context->crypto_transform, &wr_crypto_hdl, &rd_crypto_hdl, + &cat, &encoded_buffer, pp_crypto_hdl, proxypp_crypto_hdl, &ex); + GVTRACE ( "decode_submessage: pp("PGUIDFMT") proxypp("PGUIDFMT"), cat(%d)", PGUID (pp_guid), PGUID (proxypp_guid), (int) cat); + if (!result) + { + GVTRACE (" Pre-process submsg failed: %s\n", ex.message ? ex.message : "Unknown error"); + DDS_Security_Exception_reset (&ex); + return false; + } + + switch (cat) + { + case DDS_SECURITY_DATAWRITER_SUBMESSAGE: + result = sc->crypto_context->crypto_transform->decode_datawriter_submessage(sc->crypto_context->crypto_transform, &plain_buffer, &encoded_buffer, rd_crypto_hdl, wr_crypto_hdl, &ex); + break; + case DDS_SECURITY_DATAREADER_SUBMESSAGE: + result = sc->crypto_context->crypto_transform->decode_datareader_submessage(sc->crypto_context->crypto_transform, &plain_buffer, &encoded_buffer, wr_crypto_hdl, rd_crypto_hdl, &ex); + break; + case DDS_SECURITY_INFO_SUBMESSAGE: + /* No decoding needed. + * TODO: Is DDS_SECURITY_INFO_SUBMESSAGE even possible when there's a SMID_SEC_PREFIX? + * + * This function is only called when there is a prefix. If it is possible, + * then I might have a problem because the further parsing expects a new + * buffer (without the security sub-messages). + * + */ + result = true; + break; + default: + result = false; + break; + } + + if (!result) + { + GVTRACE (" Submsg decoding failed: %s\n", ex.message ? ex.message : "Unknown error"); + DDS_Security_Exception_reset (&ex); + *dst_buf = NULL; + *dst_len = 0; + return false; + } + + assert (plain_buffer._buffer); + *dst_buf = plain_buffer._buffer; + *dst_len = plain_buffer._length; + // FIXME: print_buf(*dst_buf, *dst_len, "q_omg_security_decode_submessage(DEST-DATAWRITER)"); + return true; } static bool q_omg_security_encode_serialized_payload (const struct writer *wr, const unsigned char *src_buf, size_t src_len, unsigned char **dst_buf, size_t *dst_len) { - /* TODO: Use proper keys to actually encode (need key-exchange). */ - DDSRT_UNUSED_ARG (wr); - DDSRT_UNUSED_ARG (src_buf); - DDSRT_UNUSED_ARG (src_len); - DDSRT_UNUSED_ARG (dst_buf); - DDSRT_UNUSED_ARG (dst_len); - return false; + DDS_Security_SecurityException ex = DDS_SECURITY_EXCEPTION_INIT; + DDS_Security_OctetSeq extra_inline_qos; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq plain_buffer; + + assert (wr); + assert (src_buf); + assert (src_len <= UINT32_MAX); + assert (dst_buf); + assert (dst_len); + assert (wr->sec_attr); + assert (q_omg_writer_is_payload_protected (wr)); + + const struct ddsi_domaingv *gv = wr->e.gv; + const struct dds_security_context *sc = q_omg_security_get_secure_context (wr->c.pp); + assert (sc); + + // FIXME: print_buf(src_buf, src_len, "q_omg_security_encode_serialized_payload(SOURCE)"); + + GVTRACE (" encode_payload "PGUIDFMT" %s/%s\n", PGUID (wr->e.guid), wr->topic ? wr->topic->name : "(null)", wr->topic ? wr->topic->type_name : "(null)"); + + memset (&extra_inline_qos, 0, sizeof (extra_inline_qos)); + memset (&encoded_buffer, 0, sizeof (encoded_buffer)); + plain_buffer._buffer = (DDS_Security_octet *) src_buf; + plain_buffer._length = (uint32_t) src_len; + plain_buffer._maximum = (uint32_t) src_len; + + if (!sc->crypto_context->crypto_transform->encode_serialized_payload (sc->crypto_context->crypto_transform, + &encoded_buffer, &extra_inline_qos, &plain_buffer, wr->sec_attr->crypto_handle, &ex)) + { + GVERROR ("Payload encoding failed for datawriter "PGUIDFMT": %s\n", PGUID (wr->e.guid), ex.message ? ex.message : "Unknown error"); + DDS_Security_Exception_reset (&ex); + *dst_buf = NULL; + *dst_len = 0; + return false; + } + + *dst_buf = encoded_buffer._buffer; + *dst_len = encoded_buffer._length; + // FIXME: print_buf(*dst_buf, *dst_len, "q_omg_security_encode_serialized_payload(DEST)"); + + return true; } static bool q_omg_security_decode_serialized_payload (struct proxy_writer *pwr, const unsigned char *src_buf, size_t src_len, unsigned char **dst_buf, size_t *dst_len) { - /* TODO: Use proper keys to actually decode (need key-exchange). */ - DDSRT_UNUSED_ARG (pwr); - DDSRT_UNUSED_ARG (src_buf); - DDSRT_UNUSED_ARG (src_len); - DDSRT_UNUSED_ARG (dst_buf); - DDSRT_UNUSED_ARG (dst_len); - return false; + DDS_Security_SecurityException ex = DDS_SECURITY_EXCEPTION_INIT; + DDS_Security_OctetSeq extra_inline_qos; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq plain_buffer; + struct pwr_rd_match *pwr_rd_match; + struct reader *rd; + ddsrt_avl_iter_t it; + + assert (pwr); + assert (src_buf); + assert (src_len <= UINT32_MAX); + assert (dst_buf); + assert (dst_len); + + const struct ddsi_domaingv *gv = pwr->e.gv; + const struct dds_security_context *sc = q_omg_security_get_secure_context_from_proxypp (pwr->c.proxypp); + assert (sc); + + // FIXME: print_buf(src_buf, src_len, "q_omg_security_decode_serialized_payload(SOURCE)"); + + *dst_buf = NULL; + *dst_len = 0; + GVTRACE ("decode_payload "PGUIDFMT"", PGUID (pwr->e.guid)); + + /* Only one reader is enough to decrypt the data, so use only the first match. */ + ddsrt_mutex_lock (&pwr->e.lock); + pwr_rd_match = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); + ddsrt_mutex_unlock (&pwr->e.lock); + if (!pwr_rd_match) + { + GVTRACE (" Payload decoding failed for from remote datawriter "PGUIDFMT": no local reader\n", PGUID (pwr->e.guid)); + return false; + } + if (!pwr_rd_match->crypto_handle) + { + GVTRACE (" Payload decoding from datawriter "PGUIDFMT": no crypto handle\n", PGUID (pwr->e.guid)); + return false; + } + if (!(rd = entidx_lookup_reader_guid (gv->entity_index, &pwr_rd_match->rd_guid))) + { + GVTRACE (" No datareader "PGUIDFMT" for decoding data from datawriter "PGUIDFMT"", PGUID (pwr_rd_match->rd_guid), PGUID (pwr->e.guid)); + return false; + } + + memset (&extra_inline_qos, 0, sizeof (extra_inline_qos)); + memset (&plain_buffer, 0, sizeof (plain_buffer)); + encoded_buffer._buffer = (DDS_Security_octet *) src_buf; + encoded_buffer._length = (uint32_t) src_len; + encoded_buffer._maximum = (uint32_t) src_len; + if (!sc->crypto_context->crypto_transform->decode_serialized_payload (sc->crypto_context->crypto_transform, + &plain_buffer, &encoded_buffer, &extra_inline_qos, rd->sec_attr->crypto_handle, pwr_rd_match->crypto_handle, &ex)) + { + GVTRACE (" Payload decoding failed for datareader "PGUIDFMT" from datawriter "PGUIDFMT": %s\n", PGUID (pwr_rd_match->rd_guid), PGUID (pwr->e.guid), ex.message ? ex.message : "Unknown error"); + DDS_Security_Exception_reset (&ex); + return false; + } + *dst_buf = plain_buffer._buffer; + *dst_len = plain_buffer._length; + // FIXME: print_buf(*dst_buf, *dst_len, "q_omg_security_decode_serialized_payload(DEST)"); + return true; } -bool q_omg_security_encode_rtps_message (int64_t src_handle, ddsi_guid_t *src_guid, const unsigned char *src_buf, size_t src_len, unsigned char **dst_buf, size_t *dst_len, int64_t dst_handle) +bool q_omg_security_encode_rtps_message (const struct ddsi_domaingv *gv, int64_t src_handle, const ddsi_guid_t *src_guid, const unsigned char *src_buf, size_t src_len, unsigned char **dst_buf, size_t *dst_len, int64_t dst_handle) { - /* TODO: Use proper keys to actually encode (need key-exchange). */ - DDSRT_UNUSED_ARG (src_handle); - DDSRT_UNUSED_ARG (src_guid); - DDSRT_UNUSED_ARG (src_buf); - DDSRT_UNUSED_ARG (src_len); - DDSRT_UNUSED_ARG (dst_buf); - DDSRT_UNUSED_ARG (dst_len); - DDSRT_UNUSED_ARG (dst_handle); - return false; + struct dds_security_context *sc = gv->security_context; + DDS_Security_SecurityException ex = DDS_SECURITY_EXCEPTION_INIT; + DDS_Security_ParticipantCryptoHandleSeq hdls = { 0, 0, NULL }; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq plain_buffer; + struct participant_sec_attributes *pp_attr = NULL; + bool result = false; + int32_t idx = 0; + + assert (src_buf); + assert (src_len <= UINT32_MAX); + assert (dst_buf); + assert (dst_len); + + if (dst_handle != 0) + { + hdls._buffer = (DDS_Security_long_long *) &dst_handle; + hdls._length = hdls._maximum = 1; + } + else if ((pp_attr = participant_index_find(sc, src_handle)) != NULL) + { + if (SECURITY_INFO_USE_RTPS_AUTHENTICATION(pp_attr->attr)) + { + if (get_matched_proxypp_crypto_handles(pp_attr, &hdls) == 0) + return false; + } + else + { + if ((dst_handle = get_first_matched_proxypp_crypto_handle(pp_attr)) != DDS_SECURITY_HANDLE_NIL) + { + hdls._buffer = (DDS_Security_long_long *) &dst_handle; + hdls._length = hdls._maximum = 1; + } + } + } + else + return false; + + GVTRACE (" ] encode_rtps_message ["PGUIDFMT, PGUID (*src_guid)); + + if (hdls._length > 0) + { + memset (&encoded_buffer, 0, sizeof (encoded_buffer)); + plain_buffer._buffer = (DDS_Security_octet *) src_buf; + plain_buffer._length = (uint32_t) src_len; + plain_buffer._maximum = (uint32_t) src_len; + + result = true; + idx = 0; + while (result && idx < (int32_t) hdls._length) + { + /* If the plugin thinks a new call is unnecessary, the index will be set to the size of the hdls sequence. */ + result = sc->crypto_context->crypto_transform->encode_rtps_message (sc->crypto_context->crypto_transform, + &encoded_buffer, &plain_buffer, src_handle, &hdls, &idx, &ex); + + /* With a possible second call to encode, the plain buffer should be NULL. */ + plain_buffer._buffer = NULL; + plain_buffer._length = 0; + plain_buffer._maximum = 0; + } + + if (!result) + { + GVTRACE ("]\n"); + GVTRACE ("encoding rtps message for participant "PGUIDFMT" failed: %s", PGUID (*src_guid), ex.message ? ex.message : "Unknown error"); + GVTRACE ("["); + DDS_Security_Exception_reset (&ex); + *dst_buf = NULL; + *dst_len = 0; + } + else + { + assert (encoded_buffer._buffer); + *dst_buf = encoded_buffer._buffer; + *dst_len = encoded_buffer._length; + } + } + + if (dst_handle == DDS_SECURITY_HANDLE_NIL) + ddsrt_free(hdls._buffer); + + return result; } static bool q_omg_security_decode_rtps_message (struct proxy_participant *proxypp, const unsigned char *src_buf, size_t src_len, unsigned char **dst_buf, size_t *dst_len) { - /* TODO: Use proper keys to actually decode (need key-exchange). */ - DDSRT_UNUSED_ARG (proxypp); - DDSRT_UNUSED_ARG (src_buf); - DDSRT_UNUSED_ARG (src_len); - DDSRT_UNUSED_ARG (dst_buf); - DDSRT_UNUSED_ARG (dst_len); - return false; + DDS_Security_SecurityException ex = DDS_SECURITY_EXCEPTION_INIT; + struct dds_security_context *sc; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + ddsrt_avl_iter_t it; + + assert (proxypp); + assert (src_buf); + assert (src_len <= UINT32_MAX); + assert (dst_buf); + assert (dst_len); + + const struct ddsi_domaingv *gv = proxypp->e.gv; + GVTRACE ("decode_rtps_message from "PGUIDFMT"\n", PGUID (proxypp->e.guid)); + + *dst_buf = NULL; + *dst_len = 0; + encoded_buffer._buffer = (DDS_Security_octet *) src_buf; + encoded_buffer._length = (uint32_t) src_len; + encoded_buffer._maximum = (uint32_t) src_len; + + ddsrt_mutex_lock (&proxypp->sec_attr->lock); + for (struct proxypp_pp_match *pm = ddsrt_avl_iter_first (&proxypp_pp_treedef, &proxypp->sec_attr->participants, &it); pm; pm = ddsrt_avl_iter_next (&it)) + { + sc = q_omg_security_get_secure_context_from_proxypp(proxypp); + assert (sc); + if (!sc->crypto_context->crypto_transform->decode_rtps_message (sc->crypto_context->crypto_transform, &plain_buffer, &encoded_buffer, pm->pp_crypto_handle, proxypp->sec_attr->crypto_handle, &ex)) + { + if (ex.code == DDS_SECURITY_ERR_INVALID_CRYPTO_RECEIVER_SIGN_CODE) + continue; /* Could be caused by 'with_origin_authentication' being used, so try next match */ + GVTRACE ("decoding rtps message from remote participant "PGUIDFMT" failed: %s\n", PGUID (proxypp->e.guid), ex.message ? ex.message : "Unknown error"); + DDS_Security_Exception_reset (&ex); + ddsrt_mutex_unlock (&proxypp->sec_attr->lock); + return false; + } + *dst_buf = plain_buffer._buffer; + *dst_len = plain_buffer._length; + } + ddsrt_mutex_unlock (&proxypp->sec_attr->lock); + if (*dst_buf == NULL) + { + GVTRACE ("No match found for remote participant "PGUIDFMT" for decoding rtps message\n", PGUID (proxypp->e.guid)); + return false; + } + + return true; } -static bool q_omg_writer_is_payload_protected (const struct writer *wr) +bool q_omg_reader_is_submessage_protected(const struct reader *rd) { - /* TODO: Local registration. */ - DDSRT_UNUSED_ARG (wr); - return false; -} - -static bool q_omg_writer_is_submessage_protected (struct writer *wr) -{ - /* TODO: Local registration. */ - DDSRT_UNUSED_ARG (wr); - return false; -} - -static bool q_omg_reader_is_submessage_protected (struct reader *rd) -{ - /* TODO: Local registration. */ - DDSRT_UNUSED_ARG (rd); - return false; + assert (rd != NULL); + return rd->sec_attr != NULL && rd->sec_attr->attr.is_submessage_protected; } bool encode_payload (struct writer *wr, ddsrt_iovec_t *vec, unsigned char **buf) @@ -735,7 +3110,6 @@ bool encode_payload (struct writer *wr, ddsrt_iovec_t *vec, unsigned char **buf) return true; } - static bool decode_payload (const struct ddsi_domaingv *gv, struct nn_rsample_info *sampleinfo, unsigned char *payloadp, uint32_t *payloadsz, size_t *submsg_len) { assert (payloadp); @@ -757,8 +3131,8 @@ static bool decode_payload (const struct ddsi_domaingv *gv, struct nn_rsample_in size_t dst_len = 0; if (!q_omg_security_decode_serialized_payload (sampleinfo->pwr, payloadp, *payloadsz, &dst_buf, &dst_len)) { - GVWARNING ("decode_payload: failed to decrypt data from "PGUIDFMT"", PGUID (sampleinfo->pwr->e.guid)); - return false; + GVTRACE ("decode_payload: failed to decrypt data from "PGUIDFMT"\n", PGUID (sampleinfo->pwr->e.guid)); + return true; } /* Expect result to always fit into the original buffer. */ @@ -803,10 +3177,7 @@ void encode_datareader_submsg (struct nn_xmsg *msg, struct nn_xmsg_marker sm_mar struct reader * const rd = entidx_lookup_reader_guid (pwr->e.gv->entity_index, rd_guid); /* surely a reader can only be protected if the participant has security enabled? */ if (rd == NULL || !q_omg_reader_is_submessage_protected (rd)) - { - assert (rd == NULL || !q_omg_participant_is_secure (rd->c.pp)); return; - } assert (q_omg_participant_is_secure (rd->c.pp)); unsigned char *src_buf; @@ -835,11 +3206,12 @@ void encode_datareader_submsg (struct nn_xmsg *msg, struct nn_xmsg_marker sm_mar void encode_datawriter_submsg (struct nn_xmsg *msg, struct nn_xmsg_marker sm_marker, struct writer *wr) { - /* Only encode when needed. Surely a writer can only be protected if the participant has security enabled? */ - assert (!q_omg_writer_is_submessage_protected (wr) || q_omg_participant_is_secure (wr->c.pp)); if (!q_omg_writer_is_submessage_protected (wr)) return; + /* Only encode when needed. Surely a writer can only be protected if the participant has security enabled? */ + assert (q_omg_participant_is_secure (wr->c.pp)); + unsigned char *src_buf; size_t src_len; unsigned char *dst_buf; @@ -974,7 +3346,7 @@ static bool decode_SecPrefix_patched_hdr_flags (const struct receiver_state *rst /* Decode all three submessages. */ unsigned char *dst_buf; size_t dst_len; - const bool decoded = q_omg_security_decode_submessage (src_prefix, dst_prefix, submsg, totalsize, &dst_buf, &dst_len); + const bool decoded = q_omg_security_decode_submessage (rst->gv, src_prefix, dst_prefix, submsg, totalsize, &dst_buf, &dst_len); if (decoded && dst_buf) { /* @@ -1057,7 +3429,7 @@ static nn_rtps_msg_state_t check_rtps_message_is_secure (struct ddsi_domaingv *g GVTRACE ("received encoded rtps message from unknown participant\n"); return NN_RTPS_MSG_STATE_ERROR; } - else if (!q_omg_proxyparticipant_is_authenticated (*proxypp)) + else if (!proxypp_is_authenticated (*proxypp)) { GVTRACE ("received encoded rtps message from unauthenticated participant\n"); return NN_RTPS_MSG_STATE_ERROR; @@ -1147,6 +3519,7 @@ decode_rtps_message ( ssize_t secure_conn_write( + const struct ddsi_domaingv *gv, ddsi_tran_conn_t conn, const nn_locator_t *dst, size_t niov, @@ -1211,7 +3584,7 @@ secure_conn_write( } ssize_t ret = -1; - if (!q_omg_security_encode_rtps_message (sec_info->src_pp_handle, &guid, srcbuf, srclen, &dstbuf, &dstlen, dst_handle)) + if (!q_omg_security_encode_rtps_message (gv, sec_info->src_pp_handle, &guid, srcbuf, srclen, &dstbuf, &dstlen, dst_handle)) ret = -1; else { @@ -1250,33 +3623,66 @@ secure_conn_write( return ret; } +bool q_omg_plist_keyhash_is_protected(const ddsi_plist_t *plist) +{ + assert(plist); + if (plist->present & PP_ENDPOINT_SECURITY_INFO) + { + unsigned attr = plist->endpoint_security_info.security_attributes; + return attr & NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID && + attr & NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_KEY_PROTECTED; + } + return false; +} + +bool q_omg_is_endpoint_protected(const ddsi_plist_t *plist) +{ + assert(plist); + return plist->present & PP_ENDPOINT_SECURITY_INFO && + !SECURITY_INFO_CLEAR(plist->endpoint_security_info, NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID); +} + +void q_omg_log_endpoint_protection(struct ddsi_domaingv * const gv, const ddsi_plist_t *plist) +{ + GVLOGDISC (" p("); + if (plist->present & PP_ENDPOINT_SECURITY_INFO) + GVLOGDISC ("0x%08x.0x%08x", plist->endpoint_security_info.security_attributes, plist->endpoint_security_info.plugin_security_attributes); + else + GVLOGDISC ("open"); + GVLOGDISC (")"); +} + #else /* DDSI_INCLUDE_SECURITY */ #include "dds/ddsi/ddsi_security_omg.h" -extern inline bool q_omg_participant_is_secure(UNUSED_ARG(const struct participant *pp)); -extern inline bool q_omg_proxy_participant_is_secure(const struct proxy_participant *proxypp); extern inline bool q_omg_security_enabled(void); -extern inline bool q_omg_participant_is_secure( - UNUSED_ARG(const struct participant *pp)); +extern inline bool q_omg_participant_is_access_protected(UNUSED_ARG(const struct participant *pp)); +extern inline bool q_omg_participant_is_rtps_protected(UNUSED_ARG(const struct participant *pp)); +extern inline bool q_omg_participant_is_liveliness_protected(UNUSED_ARG(const struct participant *pp)); +extern inline bool q_omg_participant_is_secure(UNUSED_ARG(const struct participant *pp)); +extern inline bool q_omg_proxy_participant_is_secure(UNUSED_ARG(const struct proxy_participant *proxypp)); -extern inline unsigned determine_subscription_writer( - UNUSED_ARG(const struct reader *rd)); +extern inline unsigned determine_subscription_writer(UNUSED_ARG(const struct reader *rd)); -extern inline bool q_omg_security_match_remote_writer_enabled(UNUSED_ARG(struct reader *rd), UNUSED_ARG(struct proxy_writer *pwr)); -extern inline bool q_omg_security_match_remote_reader_enabled(UNUSED_ARG(struct writer *wr), UNUSED_ARG(struct proxy_reader *prd)); +extern inline bool q_omg_security_match_remote_writer_enabled(UNUSED_ARG(struct reader *rd), UNUSED_ARG(struct proxy_writer *pwr), UNUSED_ARG(int64_t *crypto_handle)); +extern inline bool q_omg_security_match_remote_reader_enabled(UNUSED_ARG(struct writer *wr), UNUSED_ARG(struct proxy_reader *prd), UNUSED_ARG(int64_t *crypto_handle)); +extern inline bool q_omg_writer_is_discovery_protected(UNUSED_ARG(const struct writer *wr)); +extern inline bool q_omg_writer_is_submessage_protected(UNUSED_ARG(const struct writer *wr)); +extern inline bool q_omg_writer_is_payload_protected(UNUSED_ARG(const struct writer *wr)); + +extern inline void q_omg_get_proxy_writer_security_info(UNUSED_ARG(struct proxy_writer *pwr), UNUSED_ARG(const ddsi_plist_t *plist), UNUSED_ARG(nn_security_info_t *info)); extern inline bool q_omg_security_check_remote_writer_permissions(UNUSED_ARG(const struct proxy_writer *pwr), UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(struct participant *pp)); +extern inline void q_omg_security_deregister_remote_writer_match(UNUSED_ARG(const struct proxy_writer *pwr), UNUSED_ARG(const struct reader *rd), UNUSED_ARG(struct rd_pwr_match *match)); +extern inline void q_omg_get_proxy_reader_security_info(UNUSED_ARG(struct proxy_reader *prd), UNUSED_ARG(const ddsi_plist_t *plist), UNUSED_ARG(nn_security_info_t *info)); extern inline bool q_omg_security_check_remote_reader_permissions(UNUSED_ARG(const struct proxy_reader *prd), UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(struct participant *par)); +extern inline void q_omg_security_deregister_remote_reader_match(UNUSED_ARG(const struct proxy_reader *prd), UNUSED_ARG(const struct writer *wr), UNUSED_ARG(struct wr_prd_match *match)); -extern inline unsigned determine_publication_writer( - UNUSED_ARG(const struct writer *wr)); +extern inline unsigned determine_publication_writer(UNUSED_ARG(const struct writer *wr)); -extern inline bool is_proxy_participant_deletion_allowed( - UNUSED_ARG(struct ddsi_domaingv * const gv), - UNUSED_ARG(const struct ddsi_guid *guid), - UNUSED_ARG(const ddsi_entityid_t pwr_entityid)); +extern inline bool is_proxy_participant_deletion_allowed(UNUSED_ARG(struct ddsi_domaingv * const gv), UNUSED_ARG(const struct ddsi_guid *guid), UNUSED_ARG(const ddsi_entityid_t pwr_entityid)); extern inline bool q_omg_is_similar_participant_security_info(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp)); @@ -1284,29 +3690,43 @@ extern inline bool q_omg_participant_allow_unauthenticated(UNUSED_ARG(struct par extern inline bool q_omg_security_check_create_participant(UNUSED_ARG(struct participant *pp), UNUSED_ARG(uint32_t domain_id)); +extern inline void q_omg_security_deregister_participant(UNUSED_ARG(struct participant *pp)); + +extern inline bool q_omg_security_check_create_topic(UNUSED_ARG(const struct ddsi_domaingv *gv), UNUSED_ARG(const ddsi_guid_t *pp_guid), UNUSED_ARG(const char *topic_name), UNUSED_ARG(const struct dds_qos *qos)); + +extern inline int64_t q_omg_security_get_local_participant_handle(UNUSED_ARG(const struct participant *pp)); + +extern inline bool q_omg_security_check_create_writer(UNUSED_ARG(struct participant *pp), UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(const char *topic_name), UNUSED_ARG(const struct dds_qos *writer_qos)); + +extern inline void q_omg_security_register_writer(UNUSED_ARG(struct writer *wr)); + +extern inline void q_omg_security_deregister_writer(UNUSED_ARG(struct writer *wr)); + +extern inline bool q_omg_security_check_create_reader(UNUSED_ARG(struct participant *pp), UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(const char *topic_name), UNUSED_ARG(const struct dds_qos *reader_qos)); + +extern inline void q_omg_security_register_reader(UNUSED_ARG(struct reader *rd)); + +extern inline void q_omg_security_deregister_reader(UNUSED_ARG(struct reader *rd)); + +extern inline bool q_omg_security_is_remote_rtps_protected(UNUSED_ARG(const struct proxy_participant *proxypp), UNUSED_ARG(ddsi_entityid_t entityid)); + /* initialize the proxy participant security attributes */ extern inline void q_omg_security_init_remote_participant(UNUSED_ARG(struct proxy_participant *proxypp)); /* ask to access control security plugin for the remote participant permissions */ extern inline int64_t q_omg_security_check_remote_participant_permissions(UNUSED_ARG(uint32_t domain_id), UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp)); -extern inline void q_omg_security_register_remote_participant(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp), UNUSED_ARG(int64_t shared_secret), UNUSED_ARG(int64_t proxy_permissions)); +extern inline bool q_omg_security_register_remote_participant(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp), UNUSED_ARG(int64_t identity_handle), UNUSED_ARG(int64_t shared_secret)); extern inline void q_omg_security_deregister_remote_participant(UNUSED_ARG(struct proxy_participant *proxypp)); extern inline void q_omg_security_participant_send_tokens(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp)); -extern inline void set_proxy_participant_security_info( - UNUSED_ARG(struct proxy_participant *prd), - UNUSED_ARG(const ddsi_plist_t *plist)); +extern inline void set_proxy_participant_security_info(UNUSED_ARG(struct proxy_participant *prd), UNUSED_ARG(const ddsi_plist_t *plist)); -extern inline void set_proxy_reader_security_info( - UNUSED_ARG(struct proxy_reader *prd), - UNUSED_ARG(const ddsi_plist_t *plist)); +extern inline void set_proxy_reader_security_info(UNUSED_ARG(struct proxy_reader *prd), UNUSED_ARG(const ddsi_plist_t *plist)); -extern inline void set_proxy_writer_security_info( - UNUSED_ARG(struct proxy_writer *pwr), - UNUSED_ARG(const ddsi_plist_t *plist)); +extern inline void set_proxy_writer_security_info(UNUSED_ARG(struct proxy_writer *pwr), UNUSED_ARG(const ddsi_plist_t *plist)); extern inline bool decode_Data( UNUSED_ARG(const struct ddsi_domaingv *gv), @@ -1359,4 +3779,17 @@ extern inline nn_rtps_msg_state_t decode_rtps_message( UNUSED_ARG(struct nn_rbufpool *rbpool), UNUSED_ARG(bool isstream)); +extern inline int64_t q_omg_security_get_remote_participant_handle(UNUSED_ARG(struct proxy_participant *proxypp)); + +extern inline bool q_omg_reader_is_discovery_protected(UNUSED_ARG(const struct reader *rd)); + +extern inline bool q_omg_reader_is_submessage_protected(UNUSED_ARG(const struct reader *rd)); + +extern inline bool q_omg_plist_keyhash_is_protected(UNUSED_ARG(const ddsi_plist_t *plist)); + +extern inline bool q_omg_is_endpoint_protected(UNUSED_ARG(const ddsi_plist_t *plist)); + +extern inline void q_omg_log_endpoint_protection(UNUSED_ARG(struct ddsi_domaingv * const gv), UNUSED_ARG(const ddsi_plist_t *plist)); + + #endif /* DDSI_INCLUDE_SECURITY */ diff --git a/src/core/ddsi/src/ddsi_security_util.c b/src/core/ddsi/src/ddsi_security_util.c new file mode 100644 index 0000000..388fb4e --- /dev/null +++ b/src/core/ddsi/src/ddsi_security_util.c @@ -0,0 +1,708 @@ +/* + * 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_SECURITY + +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/bswap.h" + +#include "dds/ddsi/ddsi_security_util.h" + +void +g_omg_shallow_copy_StringSeq( + DDS_Security_StringSeq *dst, + const ddsi_stringseq_t *src) +{ + unsigned i; + assert(dst); + assert(src); + + dst->_length = src->n; + dst->_maximum = src->n; + dst->_buffer = NULL; + if (src->n > 0) + { + dst->_buffer = ddsrt_malloc(src->n * sizeof(DDS_Security_string)); + for (i = 0; i < src->n; i++) + dst->_buffer[i] = src->strs[i]; + } +} + +void +g_omg_shallow_free_StringSeq( + DDS_Security_StringSeq *obj) +{ + if (obj) + ddsrt_free(obj->_buffer); +} + +void +q_omg_copy_PropertySeq( + DDS_Security_PropertySeq *dst, + const dds_propertyseq_t *src) +{ + uint32_t i; + + if (src) + { + dst->_length = dst->_maximum = src->n; + if (src->n > 0) + dst->_buffer = DDS_Security_PropertySeq_allocbuf(src->n); + else + dst->_buffer = NULL; + + for (i = 0; i < src->n; i++) + { + dst->_buffer[i].name = src->props->name ? ddsrt_strdup(src->props->name) : ddsrt_strdup(""); + dst->_buffer[i].value = src->props->value ? ddsrt_strdup(src->props->value) : ddsrt_strdup(""); + } + } + else + memset(dst, 0, sizeof(*dst)); +} + +void +q_omg_shallow_copyin_PropertySeq( + DDS_Security_PropertySeq *dst, + const dds_propertyseq_t *src) +{ + unsigned i; + assert(dst); + assert(src); + + dst->_length = src->n; + dst->_maximum = src->n; + dst->_buffer = NULL; + + if (src->n > 0) + { + dst->_buffer = ddsrt_malloc(src->n * sizeof(DDS_Security_Property_t)); + for (i = 0; i < src->n; i++) + { + dst->_buffer[i].name = src->props[i].name; + dst->_buffer[i].value = src->props[i].value; + dst->_buffer[i].propagate = src->props[i].propagate; + } + } +} + +void +q_omg_shallow_copyout_PropertySeq( + dds_propertyseq_t *dst, + const DDS_Security_PropertySeq *src) +{ + unsigned i; + assert(dst); + assert(src); + + dst->n = src->_length; + dst->props = NULL; + + if (src->_length > 0) + { + dst->props = ddsrt_malloc(src->_length * sizeof(dds_property_t)); + for (i = 0; i < src->_length; i++) + { + dst->props[i].name = src->_buffer[i].name; + dst->props[i].value = src->_buffer[i].value; +// dst->props[i].propagate = src->_buffer[i].propagate; + dst->props[i].propagate = true; + } + } +} + +void +q_omg_shallow_free_PropertySeq( + DDS_Security_PropertySeq *obj) +{ + assert(obj); + ddsrt_free(obj->_buffer); + obj->_length = 0; + obj->_maximum = 0; + obj->_buffer = NULL; +} + +static void +q_omg_shallow_free_dds_propertyseq( + dds_propertyseq_t *obj) +{ + ddsrt_free(obj->props); + obj->n = 0; + obj->props = NULL; +} + +void +q_omg_shallow_copyin_BinaryPropertySeq( + DDS_Security_BinaryPropertySeq *dst, + const dds_binarypropertyseq_t *src) +{ + unsigned i; + assert(dst); + assert(src); + + dst->_length = src->n; + dst->_maximum = src->n; + dst->_buffer = NULL; + + if (src->n > 0) + { + dst->_buffer = ddsrt_malloc(src->n * sizeof(DDS_Security_BinaryProperty_t)); + for (i = 0; i < src->n; i++) + { + dst->_buffer[i].name = src->props[i].name; + dst->_buffer[i].value._length = src->props[i].value.length; + dst->_buffer[i].value._maximum = src->props[i].value.length; + dst->_buffer[i].value._buffer = src->props[i].value.value; +// dst->_buffer[i].propagate = src->props[i].propagate; + dst->_buffer[i].propagate = true; + } + } +} + +void +q_omg_shallow_copyout_BinaryPropertySeq( + dds_binarypropertyseq_t *dst, + const DDS_Security_BinaryPropertySeq *src) +{ + unsigned i; + assert(dst); + assert(src); + + dst->n = src->_length; + dst->props = NULL; + + if (src->_length > 0) + { + dst->props = ddsrt_malloc(src->_length * sizeof(dds_binaryproperty_t)); + for (i = 0; i < src->_length; i++) + { + dst->props[i].name = src->_buffer[i].name; + dst->props[i].value.length = src->_buffer[i].value._length; + dst->props[i].value.value = src->_buffer[i].value._buffer; + dst->props[i].propagate = src->_buffer[i].propagate; + } + } +} + +void +q_omg_shallow_free_BinaryPropertySeq( + DDS_Security_BinaryPropertySeq *obj) +{ + ddsrt_free(obj->_buffer); + obj->_length = 0; + obj->_maximum = 0; + obj->_buffer = NULL; +} + +static void +q_omg_shallow_free_dds_binarypropertyseq( + dds_binarypropertyseq_t *obj) +{ + ddsrt_free(obj->props); + obj->n = 0; + obj->props = NULL; +} + +void +q_omg_shallow_copy_PropertyQosPolicy( + DDS_Security_PropertyQosPolicy *dst, + const dds_property_qospolicy_t *src) +{ + assert(dst); + assert(src); + q_omg_shallow_copyin_PropertySeq(&(dst->value), &(src->value)); + q_omg_shallow_copyin_BinaryPropertySeq(&(dst->binary_value), &(src->binary_value)); +} + +void +q_omg_shallow_copy_security_qos( + DDS_Security_Qos *dst, + const struct dds_qos *src) +{ + assert(src); + assert(dst); + + /* DataTags not supported yet. */ + memset(&(dst->data_tags), 0, sizeof(DDS_Security_DataTagQosPolicy)); + + if (src->present & QP_PROPERTY_LIST) + q_omg_shallow_copy_PropertyQosPolicy(&(dst->property), &(src->property)); + else + memset(&(dst->property), 0, sizeof(DDS_Security_PropertyQosPolicy)); +} + +void +q_omg_shallow_free_PropertyQosPolicy( + DDS_Security_PropertyQosPolicy *obj) +{ + q_omg_shallow_free_PropertySeq(&(obj->value)); + q_omg_shallow_free_BinaryPropertySeq(&(obj->binary_value)); +} + +void +q_omg_shallow_free_security_qos( + DDS_Security_Qos *obj) +{ + q_omg_shallow_free_PropertyQosPolicy(&(obj->property)); +} + +void +q_omg_security_dataholder_copyin( + nn_dataholder_t *dh, + const DDS_Security_DataHolder *holder) +{ + uint32_t i; + + dh->class_id = holder->class_id ? ddsrt_strdup(holder->class_id) : NULL; + dh->properties.n = holder->properties._length; + dh->properties.props = dh->properties.n ? ddsrt_malloc(dh->properties.n * sizeof(dds_property_t)) : NULL; + for (i = 0; i < dh->properties.n; i++) + { + DDS_Security_Property_t *prop = &(holder->properties._buffer[i]); + dh->properties.props[i].name = prop->name ? ddsrt_strdup(prop->name) : NULL; + dh->properties.props[i].value = prop->value ? ddsrt_strdup(prop->value) : NULL; + dh->properties.props[i].propagate = prop->propagate; + } + dh->binary_properties.n = holder->binary_properties._length; + dh->binary_properties.props = dh->binary_properties.n ? ddsrt_malloc(dh->binary_properties.n * sizeof(dds_binaryproperty_t)) : NULL; + for (i = 0; i < dh->binary_properties.n; i++) + { + DDS_Security_BinaryProperty_t *prop = &(holder->binary_properties._buffer[i]); + dh->binary_properties.props[i].name = prop->name ? ddsrt_strdup(prop->name) : NULL; + dh->binary_properties.props[i].value.length = prop->value._length; + if (dh->binary_properties.props[i].value.length) + { + dh->binary_properties.props[i].value.value = ddsrt_malloc(prop->value._length); + memcpy(dh->binary_properties.props[i].value.value, prop->value._buffer, prop->value._length); + } + else + { + dh->binary_properties.props[i].value.value = NULL; + } + dh->binary_properties.props[i].propagate = prop->propagate; + } +} + +void +q_omg_security_dataholder_copyout( + DDS_Security_DataHolder *holder, + const nn_dataholder_t *dh) +{ + uint32_t i; + + holder->class_id = dh->class_id ? ddsrt_strdup(dh->class_id) : NULL; + holder->properties._length = holder->properties._maximum = dh->properties.n; + holder->properties._buffer = dh->properties.n ? DDS_Security_PropertySeq_allocbuf(dh->properties.n) : NULL; + for (i = 0; i < dh->properties.n; i++) + { + dds_property_t *props = &(dh->properties.props[i]); + holder->properties._buffer[i].name = props->name ? ddsrt_strdup(props->name) : NULL; + holder->properties._buffer[i].value = props->value ? ddsrt_strdup(props->value) : NULL; + holder->properties._buffer[i].propagate = props->propagate; + } + holder->binary_properties._length = holder->binary_properties._maximum = dh->binary_properties.n; + holder->binary_properties._buffer = dh->binary_properties.n ? DDS_Security_BinaryPropertySeq_allocbuf(dh->binary_properties.n) : NULL; + for (i = 0; i < dh->binary_properties.n; i++) + { + dds_binaryproperty_t *props = &(dh->binary_properties.props[i]); + holder->binary_properties._buffer[i].name = props->name ? ddsrt_strdup(props->name) : NULL; + holder->binary_properties._buffer[i].value._length = holder->binary_properties._buffer[i].value._maximum = props->value.length; + if (props->value.length) + { + holder->binary_properties._buffer[i].value._buffer = ddsrt_malloc(props->value.length); + memcpy(holder->binary_properties._buffer[i].value._buffer, props->value.value, props->value.length); + } + else + { + holder->binary_properties._buffer[i].value._buffer= NULL; + } + holder->binary_properties._buffer[i].propagate = props->propagate; + } +} + +void +q_omg_shallow_copyin_DataHolder( + DDS_Security_DataHolder *dst, + const nn_dataholder_t *src) +{ + assert(dst); + assert(src); + dst->class_id = src->class_id; + q_omg_shallow_copyin_PropertySeq(&dst->properties, &src->properties); + q_omg_shallow_copyin_BinaryPropertySeq(&dst->binary_properties, &src->binary_properties); +} + +void +q_omg_shallow_copyout_DataHolder( + nn_dataholder_t *dst, + const DDS_Security_DataHolder *src) +{ + assert(dst); + assert(src); + dst->class_id = src->class_id; + q_omg_shallow_copyout_PropertySeq(&dst->properties, &src->properties); + q_omg_shallow_copyout_BinaryPropertySeq(&dst->binary_properties, &src->binary_properties); +} + +void +q_omg_shallow_free_DataHolder( + DDS_Security_DataHolder *obj) +{ + q_omg_shallow_free_PropertySeq(&obj->properties); + q_omg_shallow_free_BinaryPropertySeq(&obj->binary_properties); +} + +void +q_omg_shallow_free_nn_dataholder( + nn_dataholder_t *holder) +{ + q_omg_shallow_free_dds_propertyseq(&holder->properties); + q_omg_shallow_free_dds_binarypropertyseq(&holder->binary_properties); +} + +void +q_omg_shallow_copyin_DataHolderSeq( + DDS_Security_DataHolderSeq *dst, + const nn_dataholderseq_t *src) +{ + unsigned i; + + dst->_length = src->n; + dst->_maximum = src->n; + dst->_buffer = NULL; + + if (src->n > 0) + { + dst->_buffer = ddsrt_malloc(src->n * sizeof(DDS_Security_DataHolder)); + for (i = 0; i < src->n; i++) + { + q_omg_shallow_copyin_DataHolder(&dst->_buffer[i], &src->tags[i]); + } + } +} + +void +q_omg_copyin_DataHolderSeq( + DDS_Security_DataHolderSeq *dst, + const nn_dataholderseq_t *src) +{ + unsigned i; + + dst->_length = src->n; + dst->_maximum = src->n; + dst->_buffer = NULL; + + if (src->n > 0) + { + dst->_buffer = ddsrt_malloc(src->n * sizeof(DDS_Security_DataHolder)); + for (i = 0; i < src->n; i++) + { + q_omg_security_dataholder_copyout(&dst->_buffer[i], &src->tags[i]); + } + } +} + + + +void +q_omg_shallow_copyout_DataHolderSeq( + nn_dataholderseq_t *dst, + const DDS_Security_DataHolderSeq *src) +{ + unsigned i; + + dst->n = src->_length; + dst->tags = NULL; + + if (src->_length > 0) + { + dst->tags = ddsrt_malloc(src->_length * sizeof(nn_dataholder_t)); + for (i = 0; i < src->_length; i++) + { + q_omg_shallow_copyout_DataHolder(&dst->tags[i], &src->_buffer[i]); + } + } +} + +void +q_omg_shallow_free_DataHolderSeq( + DDS_Security_DataHolderSeq *obj) +{ + unsigned i; + + for (i = 0; i < obj->_length; i++) + { + q_omg_shallow_free_DataHolder(&(obj->_buffer[i])); + } +} + +void +q_omg_shallow_free_nn_dataholderseq( + nn_dataholderseq_t *obj) +{ + unsigned i; + + for (i = 0; i < obj->n; i++) + { + q_omg_shallow_free_nn_dataholder(&(obj->tags[i])); + } + if (obj->n > 0) + ddsrt_free(obj->tags); +} + +static DDS_Security_Duration_t convert_duration(dds_duration_t d) +{ + DDS_Security_Duration_t sd; + + if (d == DDS_INFINITY) + { + sd.sec = INT32_MAX; + sd.nanosec = INT32_MAX; + } + else + { + sd.sec = ((int)(d/DDS_NSECS_IN_SEC)); + sd.nanosec = ((uint32_t)((d)%DDS_NSECS_IN_SEC)); + } + return sd; +} + +static void +g_omg_shallow_copy_octSeq( + DDS_Security_OctetSeq *dst, + const ddsi_octetseq_t *src) +{ + dst->_length = src->length; + dst->_maximum = src->length; + dst->_buffer = src->value; +} + +static void +g_omg_shallow_free_octSeq( + DDS_Security_OctetSeq *obj) +{ + DDSRT_UNUSED_ARG(obj); + /* Nothing to free. */ +} + +void +q_omg_shallow_copy_ParticipantBuiltinTopicDataSecure( + DDS_Security_ParticipantBuiltinTopicDataSecure *dst, + const ddsi_guid_t *guid, + const ddsi_plist_t *plist) +{ + assert(dst); + assert(guid); + assert(plist); + + memset(dst, 0, sizeof(DDS_Security_ParticipantBuiltinTopicDataSecure)); + + /* The participant guid is the key. */ + dst->key[0] = guid->prefix.u[0]; + dst->key[1] = guid->prefix.u[1]; + dst->key[2] = guid->prefix.u[2]; + + /* Copy the DDS_Security_OctetSeq content (length, pointer, etc), not the buffer content. */ + if (plist->qos.present & QP_USER_DATA) + memcpy(&(dst->user_data.value), &(plist->qos.user_data.value), sizeof(DDS_Security_OctetSeq)); + /* Tokens are actually DataHolders. */ + if (plist->present & PP_IDENTITY_TOKEN) + q_omg_shallow_copyin_DataHolder(&(dst->identity_token), &(plist->identity_token)); + if (plist->present & PP_PERMISSIONS_TOKEN) + q_omg_shallow_copyin_DataHolder(&(dst->permissions_token), &(plist->permissions_token)); + if (plist->present & PP_IDENTITY_STATUS_TOKEN) + q_omg_shallow_copyin_DataHolder(&(dst->identity_status_token), &(plist->identity_status_token)); + if (plist->qos.present & QP_PROPERTY_LIST) + q_omg_shallow_copy_PropertyQosPolicy(&(dst->property), &(plist->qos.property)); + if (plist->present & PP_PARTICIPANT_SECURITY_INFO) + { + dst->security_info.participant_security_attributes = plist->participant_security_info.security_attributes; + dst->security_info.plugin_participant_security_attributes = plist->participant_security_info.plugin_security_attributes; + } +} + +void +q_omg_shallow_free_ParticipantBuiltinTopicDataSecure( + DDS_Security_ParticipantBuiltinTopicDataSecure *obj) +{ + assert(obj); + q_omg_shallow_free_DataHolder(&(obj->identity_token)); + q_omg_shallow_free_DataHolder(&(obj->permissions_token)); + q_omg_shallow_free_DataHolder(&(obj->identity_status_token)); + q_omg_shallow_free_PropertyQosPolicy(&(obj->property)); +} + +void +q_omg_shallow_copy_SubscriptionBuiltinTopicDataSecure( + DDS_Security_SubscriptionBuiltinTopicDataSecure *dst, + const ddsi_guid_t *guid, + const struct dds_qos *qos, + const nn_security_info_t *secinfo) +{ + memset(dst, 0, sizeof(DDS_Security_SubscriptionBuiltinTopicDataSecure)); + + /* Keys are inspired by write_builtin_topic_copyin_subscriptionInfo() */ + dst->key[0] = ddsrt_toBE4u(guid->prefix.u[0]); + dst->key[1] = ddsrt_toBE4u(guid->prefix.u[1]); + dst->key[2] = ddsrt_toBE4u(guid->prefix.u[2]); + + dst->participant_key[0] = ddsrt_toBE4u(guid->prefix.u[0]); + dst->participant_key[1] = ddsrt_toBE4u(guid->prefix.u[1]); + dst->participant_key[2] = ddsrt_toBE4u(guid->prefix.u[2]); + + if (qos->present & QP_TOPIC_NAME) + dst->topic_name = (DDS_Security_string)qos->topic_name; + if (qos->present & QP_TYPE_NAME) + dst->type_name = (DDS_Security_string)qos->type_name; + + dst->security_info.endpoint_security_mask = secinfo->security_attributes; + dst->security_info.plugin_endpoint_security_mask = secinfo->plugin_security_attributes; + + if (qos->present & QP_DURABILITY) + dst->durability.kind = (DDS_Security_DurabilityQosPolicyKind)qos->durability.kind; + if (qos->present & QP_DEADLINE) + dst->deadline.period = convert_duration(qos->deadline.deadline); + if (qos->present & QP_LATENCY_BUDGET) + dst->latency_budget.duration = convert_duration(qos->latency_budget.duration); + if (qos->present & QP_LIVELINESS) + { + dst->liveliness.kind = (DDS_Security_LivelinessQosPolicyKind)qos->liveliness.kind; + dst->liveliness.lease_duration = convert_duration(qos->liveliness.lease_duration); + } + if (qos->present & QP_OWNERSHIP) + dst->ownership.kind = qos->ownership.kind == DDS_OWNERSHIP_SHARED ? DDS_SECURITY_SHARED_OWNERSHIP_QOS : DDS_SECURITY_EXCLUSIVE_OWNERSHIP_QOS; + if (qos->present & QP_DESTINATION_ORDER) + dst->destination_order.kind = (DDS_Security_DestinationOrderQosPolicyKind)qos->destination_order.kind; + if (qos->present & QP_PRESENTATION) + { + dst->presentation.access_scope = (DDS_Security_PresentationQosPolicyAccessScopeKind)qos->presentation.access_scope; + dst->presentation.coherent_access = qos->presentation.coherent_access; + dst->presentation.ordered_access = qos->presentation.ordered_access; + } + if (qos->present & QP_TIME_BASED_FILTER) + dst->time_based_filter.minimum_separation = convert_duration(qos->time_based_filter.minimum_separation); + if (qos->present & QP_RELIABILITY) + { + dst->reliability.kind = (DDS_Security_ReliabilityQosPolicyKind)(qos->reliability.kind); + dst->reliability.max_blocking_time = convert_duration(qos->reliability.max_blocking_time); + dst->reliability.synchronous = 0; + } + if (qos->present & QP_PARTITION) + g_omg_shallow_copy_StringSeq(&dst->partition.name, &qos->partition); + if (qos->present & QP_USER_DATA) + g_omg_shallow_copy_octSeq(&dst->user_data.value, &qos->user_data); + if (qos->present & QP_TOPIC_DATA) + g_omg_shallow_copy_octSeq(&dst->topic_data.value, &qos->topic_data); + if (qos->present & QP_GROUP_DATA) + g_omg_shallow_copy_octSeq(&dst->group_data.value, &qos->group_data); + + /* The dst->data_tags is not supported yet. It is memset to 0, so ok. */ +} + +void +q_omg_shallow_free_SubscriptionBuiltinTopicDataSecure( + DDS_Security_SubscriptionBuiltinTopicDataSecure *obj) +{ + g_omg_shallow_free_octSeq(&obj->user_data.value); + g_omg_shallow_free_octSeq(&obj->topic_data.value); + g_omg_shallow_free_octSeq(&obj->group_data.value); + g_omg_shallow_free_StringSeq(&obj->partition.name); +} + +void +q_omg_shallow_copy_PublicationBuiltinTopicDataSecure( + DDS_Security_PublicationBuiltinTopicDataSecure *dst, + const ddsi_guid_t *guid, + const struct dds_qos *qos, + const nn_security_info_t *secinfo) +{ + + memset(dst, 0, sizeof(DDS_Security_PublicationBuiltinTopicDataSecure)); + + /* Keys are inspired by write_builtin_topic_copyin_subscriptionInfo() */ + dst->key[0] = ddsrt_toBE4u(guid->prefix.u[0]); + dst->key[1] = ddsrt_toBE4u(guid->prefix.u[1]); + dst->key[2] = ddsrt_toBE4u(guid->prefix.u[2]); + + dst->participant_key[0] = ddsrt_toBE4u(guid->prefix.u[0]); + dst->participant_key[1] = ddsrt_toBE4u(guid->prefix.u[1]); + dst->participant_key[2] = ddsrt_toBE4u(guid->prefix.u[2]); + + if (qos->present & QP_TOPIC_NAME) + dst->topic_name = (DDS_Security_string)qos->topic_name; + if (qos->present & QP_TYPE_NAME) + dst->type_name = (DDS_Security_string)qos->type_name; + + dst->security_info.endpoint_security_mask = secinfo->security_attributes; + dst->security_info.plugin_endpoint_security_mask = secinfo->plugin_security_attributes; + + if (qos->present & QP_DURABILITY) + dst->durability.kind = (DDS_Security_DurabilityQosPolicyKind)qos->durability.kind; + if (qos->present & QP_DEADLINE) + dst->deadline.period = convert_duration(qos->deadline.deadline); + if (qos->present & QP_LATENCY_BUDGET) + dst->latency_budget.duration = convert_duration(qos->latency_budget.duration); + if (qos->present & QP_LIVELINESS) + { + dst->liveliness.kind = (DDS_Security_LivelinessQosPolicyKind)qos->liveliness.kind; + dst->liveliness.lease_duration = convert_duration(qos->liveliness.lease_duration); + } + if (qos->present & QP_OWNERSHIP) + dst->ownership.kind = qos->ownership.kind == DDS_OWNERSHIP_SHARED ? DDS_SECURITY_SHARED_OWNERSHIP_QOS : DDS_SECURITY_EXCLUSIVE_OWNERSHIP_QOS; + if (qos->present & QP_DESTINATION_ORDER) + dst->destination_order.kind = (DDS_Security_DestinationOrderQosPolicyKind)qos->destination_order.kind; + if (qos->present & QP_PRESENTATION) + { + dst->presentation.access_scope = (DDS_Security_PresentationQosPolicyAccessScopeKind)qos->presentation.access_scope; + dst->presentation.coherent_access = qos->presentation.coherent_access; + dst->presentation.ordered_access = qos->presentation.ordered_access; + } + if (qos->present & QP_OWNERSHIP_STRENGTH) + dst->ownership_strength.value = qos->ownership_strength.value; + if (qos->present & QP_RELIABILITY) + { + dst->reliability.kind = (DDS_Security_ReliabilityQosPolicyKind)(qos->reliability.kind); + dst->reliability.max_blocking_time = convert_duration(qos->reliability.max_blocking_time); + dst->reliability.synchronous = 0; + } + if (qos->present & QP_LIFESPAN) + dst->lifespan.duration = convert_duration(qos->lifespan.duration); + if (qos->present & QP_PARTITION) + g_omg_shallow_copy_StringSeq(&dst->partition.name, &qos->partition); + if (qos->present & QP_USER_DATA) + g_omg_shallow_copy_octSeq(&dst->user_data.value, &qos->user_data); + + if (qos->present & QP_TOPIC_DATA) + g_omg_shallow_copy_octSeq(&dst->topic_data.value, &qos->topic_data); + if (qos->present & QP_GROUP_DATA) + g_omg_shallow_copy_octSeq(&dst->group_data.value, &qos->group_data); + + /* The dst->data_tags is not supported yet. It is memset to 0, so ok. */ +} + +void +q_omg_shallow_free_PublicationBuiltinTopicDataSecure( + DDS_Security_PublicationBuiltinTopicDataSecure *obj) +{ + g_omg_shallow_free_octSeq(&obj->user_data.value); + g_omg_shallow_free_octSeq(&obj->topic_data.value); + g_omg_shallow_free_octSeq(&obj->group_data.value); + g_omg_shallow_free_StringSeq(&obj->partition.name); +} + + + +#endif /* DDSI_INCLUDE_SECURITY */ diff --git a/src/core/ddsi/src/q_ddsi_discovery.c b/src/core/ddsi/src/q_ddsi_discovery.c index 05cdea6..589276a 100644 --- a/src/core/ddsi/src/q_ddsi_discovery.c +++ b/src/core/ddsi/src/q_ddsi_discovery.c @@ -45,6 +45,9 @@ #include "dds/ddsi/q_feature_check.h" #include "dds/ddsi/ddsi_security_omg.h" #include "dds/ddsi/ddsi_pmd.h" +#ifdef DDSI_INCLUDE_SECURITY +#include "dds/ddsi/ddsi_security_exchange.h" +#endif static int get_locator (const struct ddsi_domaingv *gv, nn_locator_t *loc, const nn_locators_t *locs, int uc_same_subnet) { @@ -184,37 +187,13 @@ static int write_mpayload (struct writer *wr, int alive, nn_parameterid_t keypar return write_sample_nogc_notk (ts1, NULL, wr, serdata); } -int spdp_write (struct participant *pp) +void get_participant_builtin_topic_data(const struct participant *pp, struct nn_xmsg *mpayload, bool be) { - struct nn_xmsg *mpayload; struct nn_locators_one def_uni_loc_one, def_multi_loc_one, meta_uni_loc_one, meta_multi_loc_one; ddsi_plist_t ps; - struct writer *wr; size_t size; char node[64]; uint64_t qosdiff; - int ret; - - if (pp->e.onlylocal) { - /* This topic is only locally available. */ - return 0; - } - - ETRACE (pp, "spdp_write("PGUIDFMT")\n", PGUID (pp->e.guid)); - - if ((wr = get_builtin_writer (pp, NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER)) == NULL) - { - ETRACE (pp, "spdp_write("PGUIDFMT") - builtin participant writer not found\n", PGUID (pp->e.guid)); - return 0; - } - - /* First create a fake message for the payload: we can add plists to - xmsgs easily, but not to serdata. But it is rather easy to copy - the payload of an xmsg over to a serdata ... Expected size isn't - terribly important, the msg will grow as needed, address space is - essentially meaningless because we only use the message to - construct the payload. */ - mpayload = nn_xmsg_new (pp->e.gv->xmsgpool, &pp->e.guid, NULL, 0, NN_XMSG_KIND_DATA); ddsi_plist_init_empty (&ps); ps.present |= PP_PARTICIPANT_GUID | PP_BUILTIN_ENDPOINT_SET | @@ -321,6 +300,210 @@ int spdp_write (struct participant *pp) ETRACE (pp, "spdp_write("PGUIDFMT") - internals: %s\n", PGUID (pp->e.guid), ps.prismtech_participant_version_info.internals); } +#ifdef DDSI_INCLUDE_SECURITY + /* Add Security specific information. */ + if (q_omg_get_participant_security_info(pp, &(ps.participant_security_info))) { + ps.present |= PP_PARTICIPANT_SECURITY_INFO; + ps.aliased |= PP_PARTICIPANT_SECURITY_INFO; + } +#endif + + /* Participant QoS's insofar as they are set, different from the default, and mapped to the SPDP data, rather than to the PrismTech-specific CMParticipant endpoint. Currently, that means just USER_DATA. */ + qosdiff = ddsi_xqos_delta (&pp->plist->qos, &pp->e.gv->default_plist_pp.qos, QP_USER_DATA); + if (pp->e.gv->config.explicitly_publish_qos_set_to_default) + qosdiff |= ~QP_UNRECOGNIZED_INCOMPATIBLE_MASK; + + assert (ps.qos.present == 0); + ddsi_plist_addtomsg_bo (mpayload, &ps, ~(uint64_t)0, 0, be); + ddsi_plist_addtomsg_bo (mpayload, pp->plist, 0, qosdiff, be); +#ifdef DDSI_INCLUDE_SECURITY + if (q_omg_participant_is_secure(pp)) + ddsi_plist_addtomsg_bo (mpayload, pp->plist, PP_IDENTITY_TOKEN | PP_PERMISSIONS_TOKEN, 0, be); +#endif + nn_xmsg_addpar_sentinel_bo (mpayload, be); + ddsi_plist_fini (&ps); +} + +int spdp_write (struct participant *pp) +{ + struct nn_xmsg *mpayload; + struct writer *wr; + int ret; + + if (pp->e.onlylocal) { + /* This topic is only locally available. */ + return 0; + } + + ETRACE (pp, "spdp_write("PGUIDFMT")\n", PGUID (pp->e.guid)); + + if ((wr = get_builtin_writer (pp, NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER)) == NULL) + { + ETRACE (pp, "spdp_write("PGUIDFMT") - builtin participant writer not found\n", PGUID (pp->e.guid)); + return 0; + } + + /* First create a fake message for the payload: we can add plists to + xmsgs easily, but not to serdata. But it is rather easy to copy + the payload of an xmsg over to a serdata ... Expected size isn't + terribly important, the msg will grow as needed, address space is + essentially meaningless because we only use the message to + construct the payload. */ + mpayload = nn_xmsg_new (pp->e.gv->xmsgpool, &pp->e.guid, pp, 0, NN_XMSG_KIND_DATA); + get_participant_builtin_topic_data(pp, mpayload, false); + ret = write_mpayload (wr, 1, PID_PARTICIPANT_GUID, mpayload); + nn_xmsg_free (mpayload); + return ret; +} + + + +#if 0 +int spdp_write (struct participant *pp) +{ + struct nn_xmsg *mpayload; + struct nn_locators_one def_uni_loc_one, def_multi_loc_one, meta_uni_loc_one, meta_multi_loc_one; + ddsi_plist_t ps; + struct writer *wr; + size_t size; + char node[64]; + uint64_t qosdiff; + int ret; + + if (pp->e.onlylocal) { + /* This topic is only locally available. */ + return 0; + } + + ETRACE (pp, "spdp_write("PGUIDFMT")\n", PGUID (pp->e.guid)); + + if ((wr = get_builtin_writer (pp, NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER)) == NULL) + { + ETRACE (pp, "spdp_write("PGUIDFMT") - builtin participant writer not found\n", PGUID (pp->e.guid)); + return 0; + } + + /* First create a fake message for the payload: we can add plists to + xmsgs easily, but not to serdata. But it is rather easy to copy + the payload of an xmsg over to a serdata ... Expected size isn't + terribly important, the msg will grow as needed, address space is + essentially meaningless because we only use the message to + construct the payload. */ + mpayload = nn_xmsg_new (pp->e.gv->xmsgpool, &pp->e.guid, pp, 0, NN_XMSG_KIND_DATA); + + ddsi_plist_init_empty (&ps); + ps.present |= PP_PARTICIPANT_GUID | PP_BUILTIN_ENDPOINT_SET | + PP_PROTOCOL_VERSION | PP_VENDORID | PP_PARTICIPANT_LEASE_DURATION | + PP_DOMAIN_ID; + ps.participant_guid = pp->e.guid; + ps.builtin_endpoint_set = pp->bes; + ps.protocol_version.major = RTPS_MAJOR; + ps.protocol_version.minor = RTPS_MINOR; + ps.vendorid = NN_VENDORID_ECLIPSE; + ps.domain_id = pp->e.gv->config.extDomainId.value; + /* Be sure not to send a DOMAIN_TAG when it is the default (an empty) + string: it is an "incompatible-if-unrecognized" parameter, and so + implementations that don't understand the parameter will refuse to + discover us, and so sending the default would break backwards + compatibility. */ + if (strcmp (pp->e.gv->config.domainTag, "") != 0) + { + ps.present |= PP_DOMAIN_TAG; + ps.aliased |= PP_DOMAIN_TAG; + ps.domain_tag = pp->e.gv->config.domainTag; + } + ps.default_unicast_locators.n = 1; + ps.default_unicast_locators.first = + ps.default_unicast_locators.last = &def_uni_loc_one; + ps.metatraffic_unicast_locators.n = 1; + ps.metatraffic_unicast_locators.first = + ps.metatraffic_unicast_locators.last = &meta_uni_loc_one; + def_uni_loc_one.next = NULL; + meta_uni_loc_one.next = NULL; + + if (pp->e.gv->config.many_sockets_mode == MSM_MANY_UNICAST) + { + def_uni_loc_one.loc = pp->m_locator; + meta_uni_loc_one.loc = pp->m_locator; + } + else + { + def_uni_loc_one.loc = pp->e.gv->loc_default_uc; + meta_uni_loc_one.loc = pp->e.gv->loc_meta_uc; + } + + if (pp->e.gv->config.publish_uc_locators) + { + ps.present |= PP_DEFAULT_UNICAST_LOCATOR | PP_METATRAFFIC_UNICAST_LOCATOR; + ps.aliased |= PP_DEFAULT_UNICAST_LOCATOR | PP_METATRAFFIC_UNICAST_LOCATOR; + } + + if (pp->e.gv->config.allowMulticast) + { + int include = 0; +#ifdef DDSI_INCLUDE_SSM + /* Note that if the default multicast address is an SSM address, + we will simply advertise it. The recipients better understand + it means the writers will publish to address and the readers + favour SSM. */ + if (ddsi_is_ssm_mcaddr (pp->e.gv, &pp->e.gv->loc_default_mc)) + include = (pp->e.gv->config.allowMulticast & AMC_SSM) != 0; + else + include = (pp->e.gv->config.allowMulticast & AMC_ASM) != 0; +#else + if (pp->e.gv->config.allowMulticast & AMC_ASM) + include = 1; +#endif + if (include) + { + ps.present |= PP_DEFAULT_MULTICAST_LOCATOR | PP_METATRAFFIC_MULTICAST_LOCATOR; + ps.aliased |= PP_DEFAULT_MULTICAST_LOCATOR | PP_METATRAFFIC_MULTICAST_LOCATOR; + ps.default_multicast_locators.n = 1; + ps.default_multicast_locators.first = + ps.default_multicast_locators.last = &def_multi_loc_one; + ps.metatraffic_multicast_locators.n = 1; + ps.metatraffic_multicast_locators.first = + ps.metatraffic_multicast_locators.last = &meta_multi_loc_one; + def_multi_loc_one.next = NULL; + def_multi_loc_one.loc = pp->e.gv->loc_default_mc; + meta_multi_loc_one.next = NULL; + meta_multi_loc_one.loc = pp->e.gv->loc_meta_mc; + } + } + ps.participant_lease_duration = pp->lease_duration; + + /* Add PrismTech specific version information */ + { + ps.present |= PP_PRISMTECH_PARTICIPANT_VERSION_INFO; + memset (&ps.prismtech_participant_version_info, 0, sizeof (ps.prismtech_participant_version_info)); + ps.prismtech_participant_version_info.version = 0; + ps.prismtech_participant_version_info.flags = + NN_PRISMTECH_FL_DDSI2_PARTICIPANT_FLAG | + NN_PRISMTECH_FL_PTBES_FIXED_0 | + NN_PRISMTECH_FL_SUPPORTS_STATUSINFOX; + if (pp->e.gv->config.besmode == BESMODE_MINIMAL) + ps.prismtech_participant_version_info.flags |= NN_PRISMTECH_FL_MINIMAL_BES_MODE; + ddsrt_mutex_lock (&pp->e.gv->privileged_pp_lock); + if (pp->is_ddsi2_pp) + ps.prismtech_participant_version_info.flags |= NN_PRISMTECH_FL_PARTICIPANT_IS_DDSI2; + ddsrt_mutex_unlock (&pp->e.gv->privileged_pp_lock); + + if (ddsrt_gethostname(node, sizeof(node)-1) < 0) + (void) ddsrt_strlcpy (node, "unknown", sizeof (node)); + size = strlen(node) + strlen(DDS_VERSION) + strlen(DDS_HOST_NAME) + strlen(DDS_TARGET_NAME) + 4; /* + ///'\0' */ + ps.prismtech_participant_version_info.internals = ddsrt_malloc(size); + (void) snprintf(ps.prismtech_participant_version_info.internals, size, "%s/%s/%s/%s", node, DDS_VERSION, DDS_HOST_NAME, DDS_TARGET_NAME); + ETRACE (pp, "spdp_write("PGUIDFMT") - internals: %s\n", PGUID (pp->e.guid), ps.prismtech_participant_version_info.internals); + } + +#ifdef DDSI_INCLUDE_SECURITY + /* Add Security specific information. */ + if (q_omg_get_participant_security_info(pp, &(ps.participant_security_info))) { + ps.present |= PP_PARTICIPANT_SECURITY_INFO; + ps.aliased |= PP_PARTICIPANT_SECURITY_INFO; + } +#endif + /* Participant QoS's insofar as they are set, different from the default, and mapped to the SPDP data, rather than to the PrismTech-specific CMParticipant endpoint. Currently, that means just USER_DATA. */ qosdiff = ddsi_xqos_delta (&pp->plist->qos, &pp->e.gv->default_plist_pp.qos, QP_USER_DATA); if (pp->e.gv->config.explicitly_publish_qos_set_to_default) @@ -329,6 +512,10 @@ int spdp_write (struct participant *pp) assert (ps.qos.present == 0); ddsi_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, 0); ddsi_plist_addtomsg (mpayload, pp->plist, 0, qosdiff); +#ifdef DDSI_INCLUDE_SECURITY + if (q_omg_participant_is_secure(pp)) + ddsi_plist_addtomsg (mpayload, pp->plist, PP_IDENTITY_TOKEN | PP_PERMISSIONS_TOKEN, 0); +#endif nn_xmsg_addpar_sentinel (mpayload); ddsi_plist_fini (&ps); @@ -336,6 +523,7 @@ int spdp_write (struct participant *pp) nn_xmsg_free (mpayload); return ret; } +#endif static int spdp_dispose_unregister_with_wr (struct participant *pp, unsigned entityid) { @@ -352,7 +540,7 @@ static int spdp_dispose_unregister_with_wr (struct participant *pp, unsigned ent return 0; } - mpayload = nn_xmsg_new (pp->e.gv->xmsgpool, &pp->e.guid, NULL, 0, NN_XMSG_KIND_DATA); + mpayload = nn_xmsg_new (pp->e.gv->xmsgpool, &pp->e.guid, pp, 0, NN_XMSG_KIND_DATA); ddsi_plist_init_empty (&ps); ps.present |= PP_PARTICIPANT_GUID; ps.participant_guid = pp->e.guid; @@ -1009,7 +1197,7 @@ static int sedp_write_endpoint the QoS and other settings. So the header fields aren't really important, except that they need to be set to reasonable things or it'll crash */ - mpayload = nn_xmsg_new (gv->xmsgpool, &wr->e.guid, NULL, 0, NN_XMSG_KIND_DATA); + mpayload = nn_xmsg_new (gv->xmsgpool, &wr->e.guid, wr->c.pp, 0, NN_XMSG_KIND_DATA); ddsi_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, ~(uint64_t)0); if (xqos) ddsi_xqos_addtomsg (mpayload, xqos, qosdiff); nn_xmsg_addpar_sentinel (mpayload); @@ -1268,6 +1456,12 @@ static void handle_SEDP_alive (const struct receiver_state *rst, seqno_t seq, dd E ("******* AARGH - it expects inline QoS ********\n", err); } + q_omg_log_endpoint_protection(gv, datap); + if (q_omg_is_endpoint_protected(datap) && !q_omg_proxy_participant_is_secure(pp)) + { + E (" remote endpoint is protected while local federation is not secure\n", err); + } + if (is_writer) { pwr = entidx_lookup_proxy_writer_guid (gv->entity_index, &datap->endpoint_guid); @@ -1472,7 +1666,7 @@ int sedp_write_topic (struct participant *pp, const struct ddsi_plist *datap) sedp_wr = get_sedp_writer (pp, NN_ENTITYID_SEDP_BUILTIN_TOPIC_WRITER); - mpayload = nn_xmsg_new (sedp_wr->e.gv->xmsgpool, &sedp_wr->e.guid, NULL, 0, NN_XMSG_KIND_DATA); + mpayload = nn_xmsg_new (sedp_wr->e.gv->xmsgpool, &sedp_wr->e.guid, pp, 0, NN_XMSG_KIND_DATA); delta = ddsi_xqos_delta (&datap->qos, &sedp_wr->e.gv->default_xqos_tp, ~(uint64_t)0); if (sedp_wr->e.gv->config.explicitly_publish_qos_set_to_default) delta |= ~QP_UNRECOGNIZED_INCOMPATIBLE_MASK; @@ -1718,10 +1912,10 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str break; #ifdef DDSI_INCLUDE_SECURITY case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER: - /* TODO: Handshake */ + handle_auth_handshake_message(sampleinfo->rst, srcguid.entityid, timestamp, statusinfo, datap, datasz); break; case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER: - /* TODO: Key exchange */ + handle_crypto_exchange_message(sampleinfo->rst, srcguid.entityid, timestamp, statusinfo, datap, datasz); break; #endif default: diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c index 72df23f..ab60485 100644 --- a/src/core/ddsi/src/q_entity.c +++ b/src/core/ddsi/src/q_entity.c @@ -109,7 +109,7 @@ static void unref_participant (struct participant *pp, const struct ddsi_guid *g static struct entity_common *entity_common_from_proxy_endpoint_common (const struct proxy_endpoint_common *c); #ifdef DDSI_INCLUDE_SECURITY -static void handshake_end_cb(struct ddsi_domaingv const * const gv, struct ddsi_handshake *handshake, const struct ddsi_guid *lpguid, const struct ddsi_guid *ppguid, enum ddsi_handshake_state result); +static void handshake_end_cb(struct ddsi_handshake *handshake, struct participant *pp, struct proxy_participant *proxypp, enum ddsi_handshake_state result); static void downgrade_to_nonsecure(struct proxy_participant *proxypp); #endif @@ -217,6 +217,13 @@ static int is_builtin_volatile_endpoint (ddsi_entityid_t id) } return 0; } +#else + +static int is_builtin_volatile_endpoint (ddsi_entityid_t id) +{ + DDSRT_UNUSED_ARG(id); + return 0; +} #endif @@ -637,14 +644,14 @@ static void connect_participant_secure(struct ddsi_domaingv *gv, struct particip if (q_omg_participant_is_secure(pp)) { + q_omg_security_participant_set_initialized(pp); + entidx_enum_proxy_participant_init (&it, gv->entity_index); while ((proxypp = entidx_enum_proxy_participant_next (&it)) != NULL) { /* Do not start handshaking when security info doesn't match. */ - if (q_omg_is_similar_participant_security_info(pp, proxypp)) - { + if (q_omg_security_remote_participant_is_initialized(proxypp) && q_omg_is_similar_participant_security_info(pp, proxypp)) ddsi_handshake_register(pp, proxypp, handshake_end_cb); - } } entidx_enum_proxy_participant_fini (&it); } @@ -743,7 +750,7 @@ static void participant_remove_wr_lease_locked (struct participant * pp, struct } } -dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct ddsi_domaingv *gv, unsigned flags, const ddsi_plist_t *plist) +dds_return_t new_participant_guid (ddsi_guid_t *ppguid, struct ddsi_domaingv *gv, unsigned flags, const ddsi_plist_t *plist) { struct participant *pp; ddsi_guid_t subguid, group_guid; @@ -806,6 +813,7 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct ddsi_domain ddsi_plist_mergein_missing (pp->plist, &gv->default_local_plist_pp, ~(uint64_t)0, ~(uint64_t)0); #ifdef DDSI_INCLUDE_SECURITY + pp->sec_attr = NULL; /* * if there there are security properties check them . * if there are no security properties, then merge from security configuration if there is @@ -876,6 +884,7 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct ddsi_domain ret = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; goto not_allowed; } + *ppguid = pp->e.guid; } #endif @@ -1257,6 +1266,9 @@ static void unref_participant (struct participant *pp, const struct ddsi_guid *g while longer for it to wakeup. */ ddsi_conn_free (pp->m_conn); } +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_deregister_participant(pp); +#endif ddsi_plist_fini (pp->plist); ddsrt_free (pp->plist); ddsrt_mutex_destroy (&pp->refc_lock); @@ -1735,19 +1747,30 @@ void rebuild_or_clear_writer_addrsets (struct ddsi_domaingv *gv, int rebuild) GVLOGDISC ("rebuild_or_delete_writer_addrsets(%d) done\n", rebuild); } -static void free_wr_prd_match (struct wr_prd_match *m) +static void free_wr_prd_match (const struct ddsi_domaingv *gv, const ddsi_guid_t *wr_guid, struct wr_prd_match *m) { if (m) { +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_deregister_remote_reader_match (gv, wr_guid, m); +#else + (void) gv; + (void) wr_guid; +#endif nn_lat_estim_fini (&m->hb_to_ack_latency); ddsrt_free (m); } } -static void free_rd_pwr_match (struct ddsi_domaingv *gv, struct rd_pwr_match *m) +static void free_rd_pwr_match (struct ddsi_domaingv *gv, const ddsi_guid_t *rd_guid, struct rd_pwr_match *m) { if (m) { +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_deregister_remote_writer_match (gv, rd_guid, m); +#else + (void) rd_guid; +#endif #ifdef DDSI_INCLUDE_SSM if (!is_unspec_locator (&m->ssm_mc_loc)) { @@ -1756,7 +1779,8 @@ static void free_rd_pwr_match (struct ddsi_domaingv *gv, struct rd_pwr_match *m) if (ddsi_leave_mc (gv, gv->mship, gv->data_conn_mc, &m->ssm_src_loc, &m->ssm_mc_loc) < 0) GVWARNING ("failed to leave network partition ssm group\n"); } -#else +#endif +#if !(defined DDSI_INCLUDE_SECURITY || defined DDSI_INCLUDE_SSM) (void) gv; #endif ddsrt_free (m); @@ -1829,8 +1853,10 @@ static void writer_drop_connection (const struct ddsi_guid *wr_guid, const struc ddsrt_avl_delete (&wr_readers_treedef, &wr->readers, m); rebuild_writer_addrset (wr); remove_acked_messages (wr, &whcst, &deferred_free_list); + wr->num_readers--; wr->num_reliable_readers -= m->is_reliable; } + ddsrt_mutex_unlock (&wr->e.lock); if (m != NULL && wr->status_cb) { @@ -1841,7 +1867,7 @@ static void writer_drop_connection (const struct ddsi_guid *wr_guid, const struc (wr->status_cb) (wr->status_cb_entity, &data); } whc_free_deferred_free_list (wr->whc, deferred_free_list); - free_wr_prd_match (m); + free_wr_prd_match (wr->e.gv, &wr->e.guid, m); } } @@ -1981,7 +2007,11 @@ static void reader_drop_connection (const struct ddsi_guid *rd_guid, const struc struct rd_pwr_match *m; ddsrt_mutex_lock (&rd->e.lock); if ((m = ddsrt_avl_lookup (&rd_writers_treedef, &rd->writers, &pwr->e.guid)) != NULL) + { ddsrt_avl_delete (&rd_writers_treedef, &rd->writers, m); + rd->num_writers--; + } + ddsrt_mutex_unlock (&rd->e.lock); if (m != NULL) { @@ -2005,7 +2035,7 @@ static void reader_drop_connection (const struct ddsi_guid *rd_guid, const struc (rd->status_cb) (rd->status_cb_entity, &data); } } - free_rd_pwr_match (pwr->e.gv, m); + free_rd_pwr_match (pwr->e.gv, &rd->e.guid, m); } } @@ -2122,7 +2152,7 @@ static void proxy_reader_drop_connection (const struct ddsi_guid *prd_guid, stru } } -static void writer_add_connection (struct writer *wr, struct proxy_reader *prd) +static void writer_add_connection (struct writer *wr, struct proxy_reader *prd, int64_t crypto_handle) { struct wr_prd_match *m = ddsrt_malloc (sizeof (*m)); ddsrt_avl_ipath_t path; @@ -2134,6 +2164,11 @@ static void writer_add_connection (struct writer *wr, struct proxy_reader *prd) m->all_have_replied_to_hb = 0; m->non_responsive_count = 0; m->rexmit_requests = 0; +#ifdef DDSI_INCLUDE_SECURITY + m->crypto_handle = crypto_handle; +#else + DDSRT_UNUSED_ARG(crypto_handle); +#endif /* m->demoted: see below */ ddsrt_mutex_lock (&prd->e.lock); if (prd->deleting) @@ -2179,6 +2214,7 @@ static void writer_add_connection (struct writer *wr, struct proxy_reader *prd) PGUID (wr->e.guid), PGUID (prd->e.guid), m->seq); ddsrt_avl_insert_ipath (&wr_readers_treedef, &wr->readers, m, &path); rebuild_writer_addrset (wr); + wr->num_readers++; wr->num_reliable_readers += m->is_reliable; ddsrt_mutex_unlock (&wr->e.lock); @@ -2275,7 +2311,7 @@ static void writer_add_local_connection (struct writer *wr, struct reader *rd) } } -static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr, nn_count_t *init_count, const struct alive_state *alive_state) +static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr, nn_count_t *init_count, const struct alive_state *alive_state, int64_t crypto_handle) { struct rd_pwr_match *m = ddsrt_malloc (sizeof (*m)); ddsrt_avl_ipath_t path; @@ -2283,6 +2319,11 @@ static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr, m->pwr_guid = pwr->e.guid; m->pwr_alive = alive_state->alive; m->pwr_alive_vclock = alive_state->vclock; +#ifdef DDSI_INCLUDE_SECURITY + m->crypto_handle = crypto_handle; +#else + DDSRT_UNUSED_ARG(crypto_handle); +#endif ddsrt_mutex_lock (&rd->e.lock); @@ -2307,7 +2348,9 @@ static void reader_add_connection (struct reader *rd, struct proxy_writer *pwr, { ELOGDISC (rd, " reader_add_connection(pwr "PGUIDFMT" rd "PGUIDFMT")\n", PGUID (pwr->e.guid), PGUID (rd->e.guid)); + ddsrt_avl_insert_ipath (&rd_writers_treedef, &rd->writers, m, &path); + rd->num_writers++; ddsrt_mutex_unlock (&rd->e.lock); #ifdef DDSI_INCLUDE_SSM @@ -2390,7 +2433,7 @@ static void reader_add_local_connection (struct reader *rd, struct writer *wr, c } } -static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader *rd, nn_mtime_t tnow, nn_count_t init_count) +static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader *rd, nn_mtime_t tnow, nn_count_t init_count, int64_t crypto_handle) { struct pwr_rd_match *m = ddsrt_malloc (sizeof (*m)); ddsrt_avl_ipath_t path; @@ -2428,6 +2471,12 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader m->last_seq = 0; m->filtered = 0; +#ifdef DDSI_INCLUDE_SECURITY + m->crypto_handle = crypto_handle; +#else + DDSRT_UNUSED_ARG(crypto_handle); +#endif + /* These can change as a consequence of handling data and/or discovery activities. The safe way of dealing with them is to lock the proxy writer */ @@ -2525,12 +2574,18 @@ already_matched: -static void proxy_reader_add_connection (struct proxy_reader *prd, struct writer *wr) +static void proxy_reader_add_connection (struct proxy_reader *prd, struct writer *wr, int64_t crypto_handle) { struct prd_wr_match *m = ddsrt_malloc (sizeof (*m)); ddsrt_avl_ipath_t path; m->wr_guid = wr->e.guid; +#ifdef DDSI_INCLUDE_SECURITY + m->crypto_handle = crypto_handle; +#else + DDSRT_UNUSED_ARG(crypto_handle); +#endif + ddsrt_mutex_lock (&prd->e.lock); if (ddsrt_avl_lookup_ipath (&prd_writers_treedef, &prd->writers, &wr->e.guid, &path)) { @@ -2547,6 +2602,7 @@ static void proxy_reader_add_connection (struct proxy_reader *prd, struct writer ddsrt_avl_insert_ipath (&prd_writers_treedef, &prd->writers, m, &path); ddsrt_mutex_unlock (&prd->e.lock); qxev_prd_entityid (prd, &wr->e.guid); + } } @@ -2680,14 +2736,14 @@ static bool topickind_qos_match_p_lock (struct entity_common *rd, const dds_qos_ return ret; } -void connect_writer_with_proxy_reader_secure(struct writer *wr, struct proxy_reader *prd, nn_mtime_t tnow) +void connect_writer_with_proxy_reader_secure(struct writer *wr, struct proxy_reader *prd, nn_mtime_t tnow, int64_t crypto_handle) { DDSRT_UNUSED_ARG(tnow); - proxy_reader_add_connection (prd, wr); - writer_add_connection (wr, prd); + proxy_reader_add_connection (prd, wr, crypto_handle); + writer_add_connection (wr, prd, crypto_handle); } -void connect_reader_with_proxy_writer_secure(struct reader *rd, struct proxy_writer *pwr, nn_mtime_t tnow) +void connect_reader_with_proxy_writer_secure(struct reader *rd, struct proxy_writer *pwr, nn_mtime_t tnow, int64_t crypto_handle) { nn_count_t init_count; struct alive_state alive_state; @@ -2696,8 +2752,8 @@ void connect_reader_with_proxy_writer_secure(struct reader *rd, struct proxy_wri sensible, but that may be outdated by the time the reader gets added to the writer's list of matching readers. */ proxy_writer_get_alive_state (pwr, &alive_state); - reader_add_connection (rd, pwr, &init_count, &alive_state); - proxy_writer_add_connection (pwr, rd, tnow, init_count); + reader_add_connection (rd, pwr, &init_count, &alive_state, crypto_handle); + proxy_writer_add_connection (pwr, rd, tnow, init_count, crypto_handle); /* Once everything is set up: update with the latest state, any updates to the alive state happening in parallel will cause this to become a no-op. */ @@ -2710,6 +2766,8 @@ static void connect_writer_with_proxy_reader (struct writer *wr, struct proxy_re const int isb0 = (is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE) != 0); const int isb1 = (is_builtin_entityid (prd->e.guid.entityid, prd->c.vendor) != 0); dds_qos_policy_id_t reason; + int64_t crypto_handle; + DDSRT_UNUSED_ARG(tnow); if (isb0 != isb1) return; @@ -2726,15 +2784,15 @@ static void connect_writer_with_proxy_reader (struct writer *wr, struct proxy_re EELOGDISC (&wr->e, "connect_writer_with_proxy_reader (wr "PGUIDFMT") with (prd "PGUIDFMT") not allowed by security\n", PGUID (wr->e.guid), PGUID (prd->e.guid)); } - else if (!q_omg_security_match_remote_reader_enabled (wr, prd)) + else if (!q_omg_security_match_remote_reader_enabled (wr, prd, &crypto_handle)) { EELOGDISC (&wr->e, "connect_writer_with_proxy_reader (wr "PGUIDFMT") with (prd "PGUIDFMT") waiting for approval by security\n", PGUID (wr->e.guid), PGUID (prd->e.guid)); } else { - proxy_reader_add_connection (prd, wr); - writer_add_connection (wr, prd); + proxy_reader_add_connection (prd, wr, crypto_handle); + writer_add_connection (wr, prd, crypto_handle); } } @@ -2745,6 +2803,8 @@ static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct r dds_qos_policy_id_t reason; nn_count_t init_count; struct alive_state alive_state; + int64_t crypto_handle; + if (isb0 != isb1) return; if (rd->e.onlylocal) @@ -2760,7 +2820,7 @@ static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct r EELOGDISC (&rd->e, "connect_proxy_writer_with_reader (pwr "PGUIDFMT") with (rd "PGUIDFMT") not allowed by security\n", PGUID (pwr->e.guid), PGUID (rd->e.guid)); } - else if (!q_omg_security_match_remote_writer_enabled(rd, pwr)) + else if (!q_omg_security_match_remote_writer_enabled(rd, pwr, &crypto_handle)) { EELOGDISC (&rd->e, "connect_proxy_writer_with_reader (pwr "PGUIDFMT") with (rd "PGUIDFMT") waiting for approval by security\n", PGUID (pwr->e.guid), PGUID (rd->e.guid)); @@ -2771,8 +2831,8 @@ static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct r sensible, but that may be outdated by the time the reader gets added to the writer's list of matching readers. */ proxy_writer_get_alive_state (pwr, &alive_state); - reader_add_connection (rd, pwr, &init_count, &alive_state); - proxy_writer_add_connection (pwr, rd, tnow, init_count); + reader_add_connection (rd, pwr, &init_count, &alive_state, crypto_handle); + proxy_writer_add_connection (pwr, rd, tnow, init_count, crypto_handle); /* Once everything is set up: update with the latest state, any updates to the alive state happening in parallel will cause this to become a no-op. */ @@ -3108,7 +3168,7 @@ static void update_proxy_participant_endpoint_matching (struct proxy_participant enum entity_kind mkind; guid.entityid = endpoint_ids[i]; - if ((e = entidx_lookup_guid_untyped(proxypp->e.gv->entity_index, &guid)) == NULL) + if ((e = entidx_lookup_guid_untyped(entidx, &guid)) == NULL) continue; mkind = generic_do_match_mkind (e->kind, false); @@ -3119,10 +3179,10 @@ static void update_proxy_participant_endpoint_matching (struct proxy_participant struct match_entities_range_key max; const char *tp = entity_topic_name (e); - entidx_enum_init_topic_w_prefix (&it, entidx, mkind, tp, &pp->e.guid.prefix, &max); + entidx_enum_init_topic(&it, entidx, mkind, tp, &max); while ((em = entidx_enum_next_max (&it, &max)) != NULL) { - if (&pp->e == get_entity_parent(e)) + if (&pp->e == get_entity_parent(em)) generic_do_match_connect (e, em, tnow, false); } entidx_enum_fini (&it); @@ -3498,6 +3558,7 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se wr->retransmitting = 0; wr->t_rexmit_end.v = 0; wr->t_whc_high_upd.v = 0; + wr->num_readers = 0; wr->num_reliable_readers = 0; wr->num_acks_received = 0; wr->num_nacks_received = 0; @@ -3511,6 +3572,9 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se wr->status_cb = status_cb; wr->status_cb_entity = status_entity; +#ifdef DDSI_INCLUDE_SECURITY + wr->sec_attr = NULL; +#endif /* Copy QoS, merging in defaults */ @@ -3646,8 +3710,7 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se wr->whc_low = wr->e.gv->config.whc_lowwater_mark; wr->whc_high = wr->e.gv->config.whc_init_highwater_mark.value; } - assert (!(wr->e.guid.entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER) - || + assert (!(is_builtin_entityid(wr->e.guid.entityid, NN_VENDORID_ECLIPSE) && !is_builtin_volatile_endpoint(wr->e.guid.entityid)) || (wr->whc_low == wr->whc_high && wr->whc_low == INT32_MAX)); /* Connection admin */ @@ -3679,6 +3742,10 @@ static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_g endpoint_common_init (&wr->e, &wr->c, pp->e.gv, EK_WRITER, guid, group_guid, pp, onlylocal); new_writer_guid_common_init(wr, topic, xqos, whc, status_cb, status_entity); +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_register_writer(wr); +#endif + /* entity_index needed for protocol handling, so add it before we send out our first message. Also: needed for matching, and swapping the order if hash insert & matching creates a window during which @@ -3745,6 +3812,16 @@ dds_return_t new_writer (struct writer **wr_out, struct ddsi_domaingv *gv, struc return DDS_RETCODE_BAD_PARAMETER; } +#ifdef DDSI_INCLUDE_SECURITY + /* Check if DDS Security is enabled */ + if (q_omg_participant_is_secure (pp)) + { + /* ask to access control security plugin for create writer permissions */ + if (!q_omg_security_check_create_writer (pp, gv->config.domainId, topic->name, xqos)) + return DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; + } +#endif + /* participant can't be freed while we're mucking around cos we are awake and do not touch the thread's vtime (entidx_lookup already verifies we're awake) */ @@ -3811,7 +3888,7 @@ static void gc_delete_writer (struct gcreq *gcreq) struct wr_prd_match *m = ddsrt_avl_root_non_empty (&wr_readers_treedef, &wr->readers); ddsrt_avl_delete (&wr_readers_treedef, &wr->readers, m); proxy_reader_drop_connection (&m->prd_guid, wr); - free_wr_prd_match (m); + free_wr_prd_match (wr->e.gv, &wr->e.guid, m); } while (!ddsrt_avl_is_empty (&wr->local_readers)) { @@ -3835,6 +3912,9 @@ static void gc_delete_writer (struct gcreq *gcreq) if (wr->status_cb) (wr->status_cb) (wr->status_cb_entity, NULL); +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_deregister_writer(wr); +#endif #ifdef DDSI_INCLUDE_SSM if (wr->ssm_as) unref_addrset (wr->ssm_as); @@ -3956,6 +4036,9 @@ dds_return_t delete_writer_nolinger (struct ddsi_domaingv *gv, const struct ddsi return DDS_RETCODE_BAD_PARAMETER; } GVLOGDISC ("delete_writer_nolinger(guid "PGUIDFMT") ...\n", PGUID (*guid)); +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_deregister_writer(wr); +#endif ddsrt_mutex_lock (&wr->e.lock); delete_writer_nolinger_locked (wr); ddsrt_mutex_unlock (&wr->e.lock); @@ -4174,8 +4257,12 @@ static dds_return_t new_reader_guid rd->ddsi2direct_cb = 0; rd->ddsi2direct_cbarg = 0; rd->init_acknack_count = 0; + rd->num_writers = 0; #ifdef DDSI_INCLUDE_SSM rd->favours_ssm = 0; +#endif +#ifdef DDSI_INCLUDE_SECURITY + rd->sec_attr = NULL; #endif if (topic == NULL) { @@ -4191,6 +4278,10 @@ static dds_return_t new_reader_guid } assert (rd->xqos->present & QP_LIVELINESS); +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_register_reader(rd); +#endif + #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS rd->as = new_addrset (); if (pp->e.gv->config.allowMulticast & ~AMC_SPDP) @@ -4282,6 +4373,17 @@ dds_return_t new_reader GVLOGDISC ("new_reader - participant "PGUIDFMT" not found\n", PGUID (*ppguid)); return DDS_RETCODE_BAD_PARAMETER; } + +#ifdef DDSI_INCLUDE_SECURITY + /* Check if DDS Security is enabled */ + if (q_omg_participant_is_secure (pp)) + { + /* ask to access control security plugin for create writer permissions */ + if (!q_omg_security_check_create_reader (pp, gv->config.domainId, topic->name, xqos)) + return DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; + } +#endif + rdguid->prefix = pp->e.guid.prefix; kind = topic->topickind_no_key ? NN_ENTITYID_KIND_READER_NO_KEY : NN_ENTITYID_KIND_READER_WITH_KEY; if ((rc = pp_allocate_entityid (&rdguid->entityid, kind, pp)) < 0) @@ -4301,7 +4403,7 @@ static void gc_delete_reader (struct gcreq *gcreq) struct rd_pwr_match *m = ddsrt_avl_root_non_empty (&rd_writers_treedef, &rd->writers); ddsrt_avl_delete (&rd_writers_treedef, &rd->writers, m); proxy_writer_drop_connection (&m->pwr_guid, rd); - free_rd_pwr_match (rd->e.gv, m); + free_rd_pwr_match (rd->e.gv, &rd->e.guid, m); } while (!ddsrt_avl_is_empty (&rd->local_writers)) { @@ -4311,6 +4413,10 @@ static void gc_delete_reader (struct gcreq *gcreq) free_rd_wr_match (m); } +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_deregister_reader(rd); +#endif + if (!is_builtin_entityid (rd->e.guid.entityid, NN_VENDORID_ECLIPSE)) sedp_dispose_unregister_reader (rd); #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS @@ -4353,6 +4459,9 @@ dds_return_t delete_reader (struct ddsi_domaingv *gv, const struct ddsi_guid *gu GVLOGDISC ("delete_reader_guid(guid "PGUIDFMT") ...\n", PGUID (*guid)); builtintopic_write (rd->e.gv->builtin_topic_interface, &rd->e, now(), false); entidx_remove_reader_guid (gv->entity_index, rd); +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_deregister_reader(rd); +#endif gcreq_reader (rd); return 0; } @@ -4639,58 +4748,34 @@ static void proxy_participant_remove_pwr_lease_locked (struct proxy_participant #ifdef DDSI_INCLUDE_SECURITY -void handshake_end_cb -( - struct ddsi_domaingv const * const gv, - struct ddsi_handshake *handshake, - const struct ddsi_guid *lpguid, - const struct ddsi_guid *ppguid, - enum ddsi_handshake_state result) +void handshake_end_cb(struct ddsi_handshake *handshake, struct participant *pp, struct proxy_participant *proxypp, enum ddsi_handshake_state result) { - struct proxy_participant *proxypp; - struct participant *pp; + const struct ddsi_domaingv * const gv = pp->e.gv; int64_t shared_secret; - int64_t permissions_hdl; - - assert(handshake); - assert(lpguid); - assert(ppguid); - - assert(gv); - - proxypp = entidx_lookup_proxy_participant_guid (gv->entity_index, ppguid); - if (!proxypp) - return; - - pp = entidx_lookup_participant_guid (gv->entity_index, lpguid); - if (!pp) - return; switch(result) { case STATE_HANDSHAKE_PROCESSED: shared_secret = ddsi_handshake_get_shared_secret(handshake); - DDS_CLOG (DDS_LC_DISCOVERY, &gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") processed\n", PGUID (*lpguid), PGUID (*ppguid)); - permissions_hdl = q_omg_security_check_remote_participant_permissions(gv->config.domainId, pp, proxypp); - if (permissions_hdl != 0) { - q_omg_security_register_remote_participant(pp, proxypp, shared_secret, permissions_hdl); + DDS_CLOG (DDS_LC_DISCOVERY, &gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") processed\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid)); + if (q_omg_security_register_remote_participant(pp, proxypp, shared_secret)) { match_volatile_secure_endpoints(pp, proxypp); } break; case STATE_HANDSHAKE_SEND_TOKENS: - DDS_CLOG (DDS_LC_DISCOVERY, &gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") send tokens\n", PGUID (*lpguid), PGUID (*ppguid)); + DDS_CLOG (DDS_LC_DISCOVERY, &gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") send tokens\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid)); q_omg_security_participant_send_tokens(pp, proxypp); break; case STATE_HANDSHAKE_OK: - DDS_CLOG (DDS_LC_DISCOVERY, &gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") succeeded\n", PGUID (*lpguid), PGUID (*ppguid)); + DDS_CLOG (DDS_LC_DISCOVERY, &gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") succeeded\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid)); update_proxy_participant_endpoint_matching(proxypp, pp); ddsi_handshake_remove(pp, proxypp, handshake); break; case STATE_HANDSHAKE_TIMED_OUT: - DDS_CERROR (&gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") failed: (%d) Timed out\n", PGUID (*lpguid), PGUID (*ppguid), (int)result); + DDS_CERROR (&gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") failed: (%d) Timed out\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid), (int)result); if (q_omg_participant_allow_unauthenticated(pp)) { downgrade_to_nonsecure(proxypp); update_proxy_participant_endpoint_matching(proxypp, pp); @@ -4698,7 +4783,7 @@ void handshake_end_cb ddsi_handshake_remove(pp, proxypp, handshake); break; case STATE_HANDSHAKE_FAILED: - DDS_CERROR (&gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") failed: (%d) Failed\n", PGUID (*lpguid), PGUID (*ppguid), (int)result); + DDS_CERROR (&gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") failed: (%d) Failed\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid), (int)result); if (q_omg_participant_allow_unauthenticated(pp)) { downgrade_to_nonsecure(proxypp); update_proxy_participant_endpoint_matching(proxypp, pp); @@ -4706,7 +4791,7 @@ void handshake_end_cb ddsi_handshake_remove(pp, proxypp, handshake); break; default: - DDS_CERROR (&gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") failed: (%d) Unknown failure\n", PGUID (*lpguid), PGUID (*ppguid), (int)result); + DDS_CERROR (&gv->logconfig, "handshake (lguid="PGUIDFMT" rguid="PGUIDFMT") failed: (%d) Unknown failure\n", PGUID (pp->e.guid), PGUID (proxypp->e.guid), (int)result); ddsi_handshake_remove(pp, proxypp, handshake); break; } @@ -4729,22 +4814,37 @@ static int proxy_participant_check_security_info(struct ddsi_domaingv *gv, struc return r; } - static void proxy_participant_create_handshakes(struct ddsi_domaingv *gv, struct proxy_participant *proxypp) { struct participant *pp; struct entidx_enum_participant est; + q_omg_security_remote_participant_set_initialized(proxypp); + entidx_enum_participant_init (&est, gv->entity_index); while (((pp = entidx_enum_participant_next (&est)) != NULL)) { - if (q_omg_participant_is_secure(pp)) - { + if (q_omg_security_participant_is_initialized(pp)) ddsi_handshake_register(pp, proxypp, handshake_end_cb); - } } entidx_enum_participant_fini(&est); } +static void disconnect_proxy_participant_secure(struct proxy_participant *proxypp) +{ + struct participant *pp; + struct entidx_enum_participant it; + struct ddsi_domaingv * const gv = proxypp->e.gv; + + if (q_omg_proxy_participant_is_secure(proxypp)) + { + entidx_enum_participant_init (&it, gv->entity_index); + while ((pp = entidx_enum_participant_next (&it)) != NULL) + { + ddsi_handshake_remove(pp, proxypp, NULL); + } + entidx_enum_participant_fini (&it); + } +} #endif static void free_proxy_participant(struct proxy_participant *proxypp) @@ -4765,6 +4865,7 @@ static void free_proxy_participant(struct proxy_participant *proxypp) lease_free (proxypp->lease); } #ifdef DDSI_INCLUDE_SECURITY + disconnect_proxy_participant_secure(proxypp); q_omg_security_deregister_remote_participant(proxypp); #endif unref_addrset (proxypp->as_default); @@ -4870,7 +4971,6 @@ void new_proxy_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *pp ddsrt_avl_init (&proxypp_groups_treedef, &proxypp->groups); #ifdef DDSI_INCLUDE_SECURITY - proxypp->remote_identity_handle = 0; proxypp->sec_attr = NULL; set_proxy_participant_security_info (proxypp, plist); if (is_secure) @@ -4879,7 +4979,7 @@ void new_proxy_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *pp /* check if the proxy participant has a match with a local participant */ if (!proxy_participant_check_security_info (gv, proxypp)) { - GVWARNING ("Remote secure participant "PGUIDFMT" not allowed\n", PGUID (*ppguid)); + // GVWARNING ("Remote secure participant "PGUIDFMT" not allowed\n", PGUID (*ppguid)); free_proxy_participant (proxypp); return; } @@ -4903,7 +5003,9 @@ void new_proxy_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *pp #ifdef DDSI_INCLUDE_SECURITY if (is_secure) + { proxy_participant_create_handshakes (gv, proxypp); + } #endif } @@ -5399,7 +5501,10 @@ int new_proxy_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid, pwr->ddsi2direct_cb = 0; pwr->ddsi2direct_cbarg = 0; +#ifdef DDSI_INCLUDE_SECURITY set_proxy_writer_security_info(pwr, plist); + q_omg_get_proxy_writer_security_info(pwr, plist, &(pwr->security_info)); +#endif local_reader_ary_init (&pwr->rdary); @@ -5678,11 +5783,14 @@ int new_proxy_reader (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid, #endif prd->is_fict_trans_reader = 0; +#ifdef DDSI_INCLUDE_SECURITY set_proxy_reader_security_info(prd, plist); +#endif ddsrt_avl_init (&prd_writers_treedef, &prd->writers); #ifdef DDSI_INCLUDE_SECURITY + q_omg_get_proxy_reader_security_info(prd, plist, &(prd->security_info)); if (prd->e.guid.entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER) prd->filter = volatile_secure_data_filter; else @@ -5762,7 +5870,6 @@ static void gc_delete_proxy_reader (struct gcreq *gcreq) writer_drop_connection (&m->wr_guid, prd); free_prd_wr_match (m); } - proxy_endpoint_common_fini (&prd->e, &prd->c); ddsrt_free (prd); } diff --git a/src/core/ddsi/src/q_init.c b/src/core/ddsi/src/q_init.c index a140b33..ed8e8e2 100644 --- a/src/core/ddsi/src/q_init.c +++ b/src/core/ddsi/src/q_init.c @@ -57,6 +57,7 @@ #include "dds/ddsi/ddsi_raweth.h" #include "dds/ddsi/ddsi_mcgroup.h" #include "dds/ddsi/ddsi_serdata_default.h" +#include "dds/ddsi/ddsi_security_omg.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds__whc.h" @@ -1131,7 +1132,7 @@ int rtps_init (struct ddsi_domaingv *gv) add_property_to_xqos(&gv->builtin_volatile_xqos_rd, "dds.sec.builtin_endpoint_name", "BuiltinParticipantVolatileMessageSecureReader"); add_property_to_xqos(&gv->builtin_volatile_xqos_wr, "dds.sec.builtin_endpoint_name", "BuiltinParticipantVolatileMessageSecureWriter"); - q_omg_security_init( &gv->security_context, &gv->logconfig ); + q_omg_security_init(gv); #endif ddsrt_mutex_init (&gv->sertopics_lock); @@ -1482,7 +1483,7 @@ err_unicast_sockets: ddsi_xqos_fini (&gv->builtin_volatile_xqos_wr); ddsi_xqos_fini (&gv->builtin_volatile_xqos_rd); - q_omg_security_deinit( &gv->security_context ); + q_omg_security_deinit (gv); #endif ddsi_xqos_fini (&gv->builtin_endpoint_xqos_wr); ddsi_xqos_fini (&gv->builtin_endpoint_xqos_rd); @@ -1838,7 +1839,7 @@ void rtps_fini (struct ddsi_domaingv *gv) ddsi_xqos_fini (&gv->builtin_volatile_xqos_wr); ddsi_xqos_fini (&gv->builtin_volatile_xqos_rd); - q_omg_security_deinit( &gv->security_context); + q_omg_security_deinit (gv); #endif ddsi_xqos_fini (&gv->builtin_endpoint_xqos_wr); ddsi_xqos_fini (&gv->builtin_endpoint_xqos_rd); diff --git a/src/core/ddsi/src/q_misc.c b/src/core/ddsi/src/q_misc.c index 06a6a2c..dac4cbe 100644 --- a/src/core/ddsi/src/q_misc.c +++ b/src/core/ddsi/src/q_misc.c @@ -42,6 +42,11 @@ int WildcardOverlap(char * p1, char * p2) } #endif +bool guid_prefix_zero (const ddsi_guid_prefix_t *a) +{ + return a->u[0] == 0 && a->u[1] == 0 && a->u[2] == 0; +} + int guid_prefix_eq (const ddsi_guid_prefix_t *a, const ddsi_guid_prefix_t *b) { return a->u[0] == b->u[0] && a->u[1] == b->u[1] && a->u[2] == b->u[2]; diff --git a/src/core/ddsi/src/q_receive.c b/src/core/ddsi/src/q_receive.c index 7cc6f7b..640436b 100644 --- a/src/core/ddsi/src/q_receive.c +++ b/src/core/ddsi/src/q_receive.c @@ -80,11 +80,6 @@ static void deliver_user_data_synchronously (struct nn_rsample_chain *sc, const static void maybe_set_reader_in_sync (struct proxy_writer *pwr, struct pwr_rd_match *wn, seqno_t last_deliv_seq) { - if (wn->filtered) - { - wn->in_sync = PRMSS_OUT_OF_SYNC; - return; - } switch (wn->in_sync) { case PRMSS_SYNC: @@ -99,12 +94,15 @@ static void maybe_set_reader_in_sync (struct proxy_writer *pwr, struct pwr_rd_ma } break; case PRMSS_OUT_OF_SYNC: - assert (nn_reorder_next_seq (wn->u.not_in_sync.reorder) <= nn_reorder_next_seq (pwr->reorder)); - if (pwr->have_seen_heartbeat && nn_reorder_next_seq (wn->u.not_in_sync.reorder) == nn_reorder_next_seq (pwr->reorder)) + if (!wn->filtered) { - ETRACE (pwr, " msr_in_sync("PGUIDFMT" out-of-sync to tlcatchup)", PGUID (wn->rd_guid)); - wn->in_sync = PRMSS_TLCATCHUP; - maybe_set_reader_in_sync (pwr, wn, last_deliv_seq); + assert (nn_reorder_next_seq (wn->u.not_in_sync.reorder) <= nn_reorder_next_seq (pwr->reorder)); + if (pwr->have_seen_heartbeat && nn_reorder_next_seq (wn->u.not_in_sync.reorder) == nn_reorder_next_seq (pwr->reorder)) + { + ETRACE (pwr, " msr_in_sync("PGUIDFMT" out-of-sync to tlcatchup)", PGUID (wn->rd_guid)); + wn->in_sync = PRMSS_TLCATCHUP; + maybe_set_reader_in_sync (pwr, wn, last_deliv_seq); + } } break; } @@ -1929,6 +1927,12 @@ static struct ddsi_serdata *remote_make_sample (struct ddsi_tkmap_instance **tk, failmsg = "no content"; else if (!(qos->present & PP_KEYHASH)) failmsg = "qos present but without keyhash"; + else if (q_omg_plist_keyhash_is_protected(qos)) + { + /* If the keyhash is protected, then it is forced to be an actual MD5 + * hash. This means the keyhash can't be decoded into a sample. */ + failmsg = "keyhash is protected"; + } else if ((sample = ddsi_serdata_from_keyhash (topic, &qos->keyhash)) == NULL) failmsg = "keyhash is MD5 and can't be converted to key value"; else @@ -3018,7 +3022,7 @@ static int handle_submsg_sequence case SMID_SEC_PREFIX: state = "parse:sec_prefix"; { - GVTRACE ("SEC_PREFIX"); + GVTRACE ("SEC_PREFIX "); if (!decode_SecPrefix(rst, submsg, submsg_size, end, &rst->src_guid_prefix, &rst->dst_guid_prefix, byteswap)) goto malformed; } diff --git a/src/core/ddsi/src/q_transmit.c b/src/core/ddsi/src/q_transmit.c index 063d2a1..cdc7485 100644 --- a/src/core/ddsi/src/q_transmit.c +++ b/src/core/ddsi/src/q_transmit.c @@ -867,7 +867,7 @@ static void transmit_sample_unlocks_wr (struct nn_xpack *xp, struct writer *wr, assert((wr->heartbeat_xevent != NULL) == (whcst != NULL)); sz = ddsi_serdata_size (serdata); - if (sz > gv->config.fragment_size || !isnew || plist != NULL || prd != NULL) + if (sz > gv->config.fragment_size || !isnew || plist != NULL || prd != NULL || q_omg_writer_is_submessage_protected(wr)) { uint32_t nfrags; ddsrt_mutex_unlock (&wr->e.lock); diff --git a/src/core/ddsi/src/q_xevent.c b/src/core/ddsi/src/q_xevent.c index 41b91a7..3b3e22a 100644 --- a/src/core/ddsi/src/q_xevent.c +++ b/src/core/ddsi/src/q_xevent.c @@ -104,7 +104,8 @@ enum xeventkind_nt { XEVK_MSG, XEVK_MSG_REXMIT, - XEVK_ENTITYID + XEVK_ENTITYID, + XEVK_NT_CALLBACK }; struct untimed_listelem { @@ -131,6 +132,10 @@ struct xevent_nt /* xmsg is self-contained / relies on reference counts */ struct nn_xmsg *msg; } entityid; + struct { + void (*cb) (void *arg); + void *arg; + } callback; } u; }; @@ -972,12 +977,16 @@ static void handle_xevk_acknack (struct nn_xpack *xp, struct xevent *ev, nn_mtim if (addrset_any_uc (pwr->c.as, &loc) || addrset_any_mc (pwr->c.as, &loc)) { + struct participant *pp = NULL; seqno_t nack_seq; - struct participant *pp = NULL; - struct reader *rd = entidx_lookup_reader_guid(pwr->e.gv->entity_index, &ev->u.acknack.rd_guid); - if (rd) - pp = rd->c.pp; + if (q_omg_proxy_participant_is_secure(pwr->c.proxypp)) + { + struct reader *rd = entidx_lookup_reader_guid(pwr->e.gv->entity_index, &ev->u.acknack.rd_guid); + + if (rd) + pp = rd->c.pp; + } if ((msg = nn_xmsg_new (gv->xmsgpool, &ev->u.acknack.rd_guid, pp, ACKNACK_SIZE_MAX, NN_XMSG_KIND_CONTROL)) == NULL) goto outofmem; @@ -1303,6 +1312,9 @@ static void handle_individual_xevent_nt (struct xevent_nt *xev, struct nn_xpack case XEVK_ENTITYID: handle_xevk_entityid (xp, xev); break; + case XEVK_NT_CALLBACK: + xev->u.callback.cb (xev->u.callback.arg); + break; } ddsrt_free (xev); } @@ -1459,6 +1471,18 @@ void qxev_msg (struct xeventq *evq, struct nn_xmsg *msg) ddsrt_mutex_unlock (&evq->lock); } +void qxev_nt_callback (struct xeventq *evq, void (*cb) (void *arg), void *arg) +{ + struct xevent_nt *ev; + assert (evq); + ddsrt_mutex_lock (&evq->lock); + ev = qxev_common_nt (evq, XEVK_NT_CALLBACK); + ev->u.callback.cb = cb; + ev->u.callback.arg = arg; + qxev_insert_nt (ev); + ddsrt_mutex_unlock (&evq->lock); +} + void qxev_prd_entityid (struct proxy_reader *prd, const ddsi_guid_t *guid) { struct ddsi_domaingv * const gv = prd->e.gv; diff --git a/src/core/ddsi/src/q_xmsg.c b/src/core/ddsi/src/q_xmsg.c index 695c47d..93a70a2 100644 --- a/src/core/ddsi/src/q_xmsg.c +++ b/src/core/ddsi/src/q_xmsg.c @@ -920,22 +920,31 @@ void nn_xmsg_setwriterseq_fragid (struct nn_xmsg *msg, const ddsi_guid_t *wrguid msg->kindspecific.data.wrfragid = wrfragid; } -void *nn_xmsg_addpar (struct nn_xmsg *m, nn_parameterid_t pid, size_t len) +void *nn_xmsg_addpar_bo (struct nn_xmsg *m, nn_parameterid_t pid, size_t len, bool be) { +#define BO2U(x) (be ? ddsrt_toBE2u((x)) : (x)) + const size_t len4 = (len + 3) & ~(size_t)3; /* must alloc a multiple of 4 */ nn_parameter_t *phdr; char *p; assert (len4 < UINT16_MAX); /* FIXME: return error */ m->have_params = 1; phdr = nn_xmsg_append (m, NULL, sizeof (nn_parameter_t) + len4); - phdr->parameterid = pid; - phdr->length = (uint16_t) len4; + phdr->parameterid = BO2U(pid); + phdr->length = BO2U((uint16_t) len4); p = (char *) (phdr + 1); /* zero out padding bytes added to satisfy parameter alignment: this way valgrind can tell us where we forgot to initialize something */ while (len < len4) p[len++] = 0; return p; + +#undef BO2U +} + +void *nn_xmsg_addpar (struct nn_xmsg *m, nn_parameterid_t pid, size_t len) +{ + return nn_xmsg_addpar_bo(m, pid, len, false); } void nn_xmsg_addpar_keyhash (struct nn_xmsg *m, const struct ddsi_serdata *serdata, bool force_md5) @@ -974,6 +983,11 @@ void nn_xmsg_addpar_sentinel (struct nn_xmsg * m) nn_xmsg_addpar (m, PID_SENTINEL, 0); } +void nn_xmsg_addpar_sentinel_bo (struct nn_xmsg * m, bool be) +{ + nn_xmsg_addpar_bo (m, PID_SENTINEL, 0, be); +} + int nn_xmsg_addpar_sentinel_ifparam (struct nn_xmsg * m) { if (m->have_params) @@ -1188,6 +1202,7 @@ static ssize_t nn_xpack_send_rtps(struct nn_xpack * xp, const nn_locator_t *loc) if (xp->sec_info.use_rtps_encoding) { ret = secure_conn_write( + xp->gv, xp->conn, loc, xp->niov, diff --git a/src/security/builtin_plugins/access_control/src/access_control_parser.c b/src/security/builtin_plugins/access_control/src/access_control_parser.c index fbf106c..efd72ef 100644 --- a/src/security/builtin_plugins/access_control/src/access_control_parser.c +++ b/src/security/builtin_plugins/access_control/src/access_control_parser.c @@ -958,8 +958,10 @@ static int permissions_element_open_cb(void *varg, uintptr_t parentinfo, uintptr { parser->current = new_element(ELEMENT_KIND_IGNORED, parser->current, sizeof(struct element)); /*if this is the first element in the IGNORED branch, then give warning for the user*/ +#if 0 if (parser->current->parent->kind != ELEMENT_KIND_IGNORED) printf("Warning: Unsupported element \"%s\" has been ignored in permissions file.\n", name); +#endif } else { diff --git a/src/security/builtin_plugins/authentication/src/auth_utils.c b/src/security/builtin_plugins/authentication/src/auth_utils.c index 54b2224..d2ec77a 100644 --- a/src/security/builtin_plugins/authentication/src/auth_utils.c +++ b/src/security/builtin_plugins/authentication/src/auth_utils.c @@ -1225,7 +1225,8 @@ get_trusted_ca_list ( const char* trusted_ca_dir, if( loading_result == DDS_SECURITY_VALIDATION_OK ){ ca_buffer_array[ca_buffer_array_size] = identityCA; ca_buffer_array_size++; - + } else { + DDS_Security_Exception_reset(ex); } } } diff --git a/src/security/builtin_plugins/authentication/src/authentication.c b/src/security/builtin_plugins/authentication/src/authentication.c index 09d3425..63f4a60 100644 --- a/src/security/builtin_plugins/authentication/src/authentication.c +++ b/src/security/builtin_plugins/authentication/src/authentication.c @@ -21,7 +21,6 @@ #include #include "authentication.h" #include "dds/ddsrt/heap.h" -#include "dds/ddsrt/avl.h" #include "dds/security/dds_security_api.h" #include "dds/security/core/dds_security_timed_cb.h" @@ -120,8 +119,8 @@ typedef enum { typedef enum { CREATEDREQUEST, CREATEDREPLY -} CreatedHandshakeStep_t; +} CreatedHandshakeStep_t; typedef struct SecurityObject SecurityObject; @@ -130,6 +129,7 @@ typedef void (*SecurityObjectDestructor)(SecurityObject *obj); struct SecurityObject { int64_t handle; SecurityObjectKind_t kind; + SecurityObjectDestructor destructor; }; @@ -146,35 +146,6 @@ struct SecurityObject { #define SECURITY_OBJECT_VALID(o,k) security_object_valid((SecurityObject *)(o), k) -struct LocalIdentityInfo; -struct HandshakeInfo; - -typedef struct RemoteIdentityInfo { - SecurityObject _parent; - uint32_t refc; - DDS_Security_GUID_t guid; - X509 *identityCert; - AuthenticationAlgoKind_t dsignAlgoKind; - AuthenticationAlgoKind_t kagreeAlgoKind; - DDS_Security_IdentityToken *remoteIdentityToken; - DDS_Security_OctetSeq pdata; - char *permissionsDocument; -} RemoteIdentityInfo; - -/* This structure contains the relation between a local and a remote identity - * The handle for this object is the same as the handle of the associated - * local identity object. The IdentityRelation object will be stored with the - * remote identity. - */ -typedef struct IdentityRelation { - SecurityObject _parent; - ddsrt_avl_node_t avlnode; - struct LocalIdentityInfo *localIdentity; - struct RemoteIdentityInfo *remoteIdentity; - AuthenticationChallenge *lchallenge; - AuthenticationChallenge *rchallenge; - struct HandshakeInfo *handshake; -} IdentityRelation; typedef struct LocalIdentityInfo { SecurityObject _parent; @@ -188,12 +159,36 @@ typedef struct LocalIdentityInfo { AuthenticationAlgoKind_t dsignAlgoKind; AuthenticationAlgoKind_t kagreeAlgoKind; char *permissionsDocument; - ddsrt_avl_tree_t relations; /* contains the IdentityRelation objects */ } LocalIdentityInfo; +typedef struct RemoteIdentityInfo { + SecurityObject _parent; + DDS_Security_GUID_t guid; + X509 *identityCert; + AuthenticationAlgoKind_t dsignAlgoKind; + AuthenticationAlgoKind_t kagreeAlgoKind; + DDS_Security_IdentityToken *remoteIdentityToken; + DDS_Security_OctetSeq pdata; + char *permissionsDocument; + struct ddsrt_hh *linkHash; /* contains the IdentityRelation objects */ +} RemoteIdentityInfo; + + +/* This structure contains the relation between a local and a remote identity + * The handle for this object is the same as the handle of the associated + * local identity object. The IdentityRelation object will be stored with the + * remote identity. + */ +typedef struct IdentityRelation { + SecurityObject _parent; + LocalIdentityInfo *localIdentity; + RemoteIdentityInfo *remoteIdentity; + AuthenticationChallenge *lchallenge; + AuthenticationChallenge *rchallenge; +} IdentityRelation; + typedef struct HandshakeInfo { SecurityObject _parent; - ddsrt_avl_node_t avlnode; IdentityRelation *relation; HashValue_t hash_c1; HashValue_t hash_c2; @@ -208,7 +203,6 @@ typedef struct dds_security_authentication_impl { ddsrt_mutex_t lock; struct ddsrt_hh *objectHash; struct ddsrt_hh *remoteGuidHash; - struct ddsrt_hh *handshakes; struct dds_security_timed_cb_data *timed_callbacks; struct dds_security_timed_dispatcher_t *dispatcher; X509Seq trustedCAList; @@ -221,11 +215,6 @@ typedef struct { } validity_cb_info; -static int compare_relation (const void *va, const void *vb); - -const ddsrt_avl_treedef_t relations_treedef = - DDSRT_AVL_TREEDEF_INITIALIZER_INDKEY (offsetof (struct IdentityRelation, avlnode), offsetof (struct IdentityRelation, remoteIdentity), compare_relation, 0); - static bool security_object_valid( SecurityObject *obj, @@ -233,7 +222,14 @@ security_object_valid( { if (!obj) return false; if (obj->kind != kind) return false; - if ((uintptr_t)obj->handle != (uintptr_t)obj) return false; + if (kind == SECURITY_OBJECT_KIND_IDENTITY_RELATION) { + IdentityRelation *relation = (IdentityRelation *)obj; + if (!relation->localIdentity || !relation->remoteIdentity || (ddsrt_address)obj->handle != (ddsrt_address)relation->localIdentity) { + return false; + } + } else if ((ddsrt_address)obj->handle != (ddsrt_address)obj) { + return false; + } return true; } @@ -269,31 +265,20 @@ security_object_find( template.handle = handle; - return (SecurityObject *) ddsrt_hh_lookup(hh, &template); -} - -static int compare_relation (const void *va, const void *vb) -{ - const struct RemoteIdentityInfo * ha = va; - const struct RemoteIdentityInfo * hb = vb; - - if (IDENTITY_HANDLE(ha) < IDENTITY_HANDLE(hb)) { - return -1; - } else if (IDENTITY_HANDLE(ha) > IDENTITY_HANDLE(hb)) { - return 1; - } - return 0; + return (SecurityObject *) ddsrt_hh_lookup(hh, &template);; } static void security_object_init( SecurityObject *obj, - SecurityObjectKind_t kind) + SecurityObjectKind_t kind, + SecurityObjectDestructor destructor) { assert(obj); obj->kind = kind; - obj->handle = (int64_t)(uintptr_t)obj; + obj->handle = (int64_t)(ddsrt_address)obj; + obj->destructor = destructor; } static void @@ -304,8 +289,25 @@ security_object_deinit( assert(obj); obj->handle = DDS_SECURITY_HANDLE_NIL; obj->kind = SECURITY_OBJECT_KIND_UNKNOWN; + obj->destructor = NULL; } +static void +security_object_free( + SecurityObject *obj) +{ + assert(obj); + if (obj && obj->destructor) { + obj->destructor(obj); + } +} + +static void +localIdentityInfoFree( + SecurityObject *obj); + + + static LocalIdentityInfo * localIdentityInfoNew( DDS_Security_DomainId domainId, @@ -327,7 +329,10 @@ localIdentityInfoNew( identity = ddsrt_malloc(sizeof(*identity)); memset(identity, 0, sizeof(*identity)); - security_object_init((SecurityObject *)identity, SECURITY_OBJECT_KIND_LOCAL_IDENTITY); + security_object_init((SecurityObject *)identity, SECURITY_OBJECT_KIND_LOCAL_IDENTITY, localIdentityInfoFree); + + + identity->domainId = domainId; identity->identityCert = identityCert; @@ -340,33 +345,31 @@ localIdentityInfoNew( memcpy(&identity->candidateGUID, candidate_participant_guid, sizeof(DDS_Security_GUID_t)); memcpy(&identity->adjustedGUID, adjusted_participant_guid, sizeof(DDS_Security_GUID_t)); - ddsrt_avl_init(&relations_treedef, &identity->relations); - return identity; } static void localIdentityInfoFree( - LocalIdentityInfo *info) + SecurityObject *obj) { - CHECK_OBJECT_KIND(info, SECURITY_OBJECT_KIND_LOCAL_IDENTITY); + LocalIdentityInfo *identity = (LocalIdentityInfo *)obj; - if (info) { - assert(ddsrt_avl_is_empty(&info->relations)); - ddsrt_avl_free(&relations_treedef, &info->relations, NULL); - if (info->identityCert) { - X509_free(info->identityCert); + CHECK_OBJECT_KIND(obj, SECURITY_OBJECT_KIND_LOCAL_IDENTITY); + + if (identity) { + if (identity->identityCert) { + X509_free(identity->identityCert); } - if (info->identityCA) { - X509_free(info->identityCA); + if (identity->identityCA) { + X509_free(identity->identityCA); } - if (info->privateKey) { - EVP_PKEY_free(info->privateKey); + if (identity->privateKey) { + EVP_PKEY_free(identity->privateKey); } - ddsrt_free(info->pdata._buffer); - ddsrt_free(info->permissionsDocument); - security_object_deinit((SecurityObject *)info); - ddsrt_free(info); + ddsrt_free(identity->pdata._buffer); + ddsrt_free(identity->permissionsDocument); + security_object_deinit((SecurityObject *)identity); + ddsrt_free(identity); } } @@ -405,6 +408,10 @@ find_remote_identity_by_guid( return (RemoteIdentityInfo *) ddsrt_hh_lookup(hh, &template); } +static void +remoteIdentityInfoFree( + SecurityObject *obj); + static RemoteIdentityInfo * remoteIdentityInfoNew( const DDS_Security_GUID_t *guid, @@ -418,39 +425,47 @@ remoteIdentityInfoNew( identity = ddsrt_malloc(sizeof(*identity)); memset(identity, 0, sizeof(*identity)); - security_object_init((SecurityObject *)identity, SECURITY_OBJECT_KIND_REMOTE_IDENTITY); + security_object_init((SecurityObject *)identity, SECURITY_OBJECT_KIND_REMOTE_IDENTITY, remoteIdentityInfoFree); memcpy(&identity->guid, guid, sizeof(DDS_Security_GUID_t)); - identity->refc = 0; identity->remoteIdentityToken = DDS_Security_DataHolder_alloc(); DDS_Security_DataHolder_copy(identity->remoteIdentityToken, remote_identity_token); identity->identityCert = NULL; identity->dsignAlgoKind = AUTH_ALGO_KIND_UNKNOWN; identity->kagreeAlgoKind = AUTH_ALGO_KIND_UNKNOWN; identity->permissionsDocument = ddsrt_strdup(""); + identity->linkHash = ddsrt_hh_new(32, security_object_hash, security_object_equal); return identity; } static void remoteIdentityInfoFree( - RemoteIdentityInfo *info) + SecurityObject *obj) { - CHECK_OBJECT_KIND(info, SECURITY_OBJECT_KIND_REMOTE_IDENTITY); + RemoteIdentityInfo *identity = (RemoteIdentityInfo *)obj; - if (info) { - assert(info->refc == 0); - if (info->identityCert) { - X509_free(info->identityCert); + CHECK_OBJECT_KIND(obj, SECURITY_OBJECT_KIND_REMOTE_IDENTITY); + + if (identity) { + if (identity->identityCert) { + X509_free(identity->identityCert); } - DDS_Security_DataHolder_free(info->remoteIdentityToken); - ddsrt_free(info->pdata._buffer); - ddsrt_free(info->permissionsDocument); - security_object_deinit((SecurityObject *)info); - ddsrt_free(info); + DDS_Security_DataHolder_free(identity->remoteIdentityToken); + + ddsrt_hh_free(identity->linkHash); + + ddsrt_free(identity->pdata._buffer); + ddsrt_free(identity->permissionsDocument); + security_object_deinit((SecurityObject *)identity); + ddsrt_free(identity); } } +static void +identityRelationFree( + SecurityObject *obj); + /* The IdentityRelation provides the association between a local and a remote * identity. This object manages the challenges which are created for * each association between a local and a remote identity. @@ -474,23 +489,24 @@ identityRelationNew( relation = ddsrt_malloc(sizeof(*relation)); memset(relation, 0, sizeof(*relation)); - security_object_init((SecurityObject *)relation, SECURITY_OBJECT_KIND_IDENTITY_RELATION); + security_object_init((SecurityObject *)relation, SECURITY_OBJECT_KIND_IDENTITY_RELATION, identityRelationFree); + relation->_parent.handle = SECURITY_OBJECT_HANDLE(localIdentity); relation->localIdentity = localIdentity; relation->remoteIdentity = remoteIdentity; - remoteIdentity->refc++; relation->lchallenge = lchallenge; relation->rchallenge = rchallenge; - relation->handshake = NULL; return relation; } static void identityRelationFree( - IdentityRelation *relation) + SecurityObject *obj) { - CHECK_OBJECT_KIND(relation, SECURITY_OBJECT_KIND_IDENTITY_RELATION); + IdentityRelation *relation = (IdentityRelation *)obj; + + CHECK_OBJECT_KIND(obj, SECURITY_OBJECT_KIND_IDENTITY_RELATION); if (relation) { ddsrt_free(relation->lchallenge); @@ -500,16 +516,27 @@ identityRelationFree( } } +static void +handshakeInfoFree( + SecurityObject *obj); + static HandshakeInfo * handshakeInfoNew( + LocalIdentityInfo *localIdentity, + RemoteIdentityInfo *remoteIdentity, IdentityRelation *relation) { HandshakeInfo *handshake; + assert(localIdentity); + assert(remoteIdentity); + + DDSRT_UNUSED_ARG(localIdentity); + DDSRT_UNUSED_ARG(remoteIdentity); handshake = ddsrt_malloc(sizeof(*handshake)); memset(handshake, 0, sizeof(*handshake)); - security_object_init((SecurityObject *)handshake, SECURITY_OBJECT_KIND_HANDSHAKE); + security_object_init((SecurityObject *)handshake, SECURITY_OBJECT_KIND_HANDSHAKE, handshakeInfoFree); handshake->relation = relation; handshake->shared_secret_handle_impl = NULL; @@ -519,14 +546,13 @@ handshakeInfoNew( static void handshakeInfoFree( - HandshakeInfo *handshake) + SecurityObject *obj) { - CHECK_OBJECT_KIND(handshake, SECURITY_OBJECT_KIND_HANDSHAKE); + HandshakeInfo *handshake = (HandshakeInfo *)obj; + + CHECK_OBJECT_KIND(obj, SECURITY_OBJECT_KIND_HANDSHAKE); if (handshake) { - assert(handshake->relation && handshake->relation->handshake == handshake); - handshake->relation->handshake = NULL; - if (handshake->ldh) { EVP_PKEY_free(handshake->ldh); } @@ -542,6 +568,48 @@ handshakeInfoFree( } } +static IdentityRelation * +find_identity_relation( + const RemoteIdentityInfo *remote, + int64_t lid) +{ + return (IdentityRelation *)security_object_find(remote->linkHash, lid); +} + +static void +remove_identity_relation( + RemoteIdentityInfo *remote, + IdentityRelation *relation) +{ + (void)ddsrt_hh_remove(remote->linkHash, relation); + security_object_free((SecurityObject *) relation); +} + +static HandshakeInfo * +find_handshake( + const dds_security_authentication_impl *auth, + int64_t localId, + int64_t remoteId) +{ + struct ddsrt_hh_iter it; + SecurityObject *obj; + IdentityRelation *relation; + HandshakeInfo *found = NULL; + + for (obj = ddsrt_hh_iter_first(auth->objectHash, &it); obj && !found; obj = ddsrt_hh_iter_next(&it)) { + if (obj->kind == SECURITY_OBJECT_KIND_HANDSHAKE) { + relation = ((HandshakeInfo *)obj)->relation; + assert(relation); + if ((SECURITY_OBJECT_HANDLE(relation->localIdentity) == localId) && + (SECURITY_OBJECT_HANDLE(relation->remoteIdentity) == remoteId)) { + found = (HandshakeInfo *)obj; + } + } + } + + return found; +} + static char * get_authentication_class_id( void) @@ -1287,6 +1355,8 @@ fill_auth_request_token( token->binary_properties._buffer->value._length = len; token->binary_properties._buffer->value._buffer = ddsrt_malloc(len); memcpy(token->binary_properties._buffer->value._buffer, challenge->value, len); + token->binary_properties._buffer->propagate = true; + } DDS_Security_ValidationResult_t @@ -1303,10 +1373,11 @@ validate_remote_identity( DDS_Security_ValidationResult_t result = DDS_SECURITY_VALIDATION_OK; dds_security_authentication_impl *impl = (dds_security_authentication_impl *) instance; SecurityObject *obj; - LocalIdentityInfo *linfo; - RemoteIdentityInfo *rinfo; - IdentityRelation *relation = NULL; + LocalIdentityInfo *localIdent; + RemoteIdentityInfo *remoteIdent; + IdentityRelation *relation; AuthenticationChallenge *lchallenge = NULL, *rchallenge = NULL; + int r; /* validate provided arguments */ if (!instance || !remote_identity_handle || !local_auth_request_token || !remote_identity_token || !remote_participant_guid) { @@ -1321,10 +1392,10 @@ validate_remote_identity( DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "validate_remote_identity: Invalid handle provided"); goto err_inv_handle; } - linfo = (LocalIdentityInfo *) obj; + localIdent = (LocalIdentityInfo *) obj; /* Check if the provided remote_identity_token is compatible */ - result = validate_remote_identity_token(linfo, remote_identity_token, ex); + result = validate_remote_identity_token(localIdent, remote_identity_token, ex); if (result != DDS_SECURITY_VALIDATION_OK) { goto err_remote_identity_token; } @@ -1349,29 +1420,30 @@ validate_remote_identity( */ /* Check if the remote identity has already been validated by a previous validation request. */ - rinfo = find_remote_identity_by_guid(impl->remoteGuidHash, remote_participant_guid); - if (!rinfo) { - rinfo = remoteIdentityInfoNew(remote_participant_guid, remote_identity_token); - (void)ddsrt_hh_add(impl->remoteGuidHash, rinfo); - relation = identityRelationNew(linfo, rinfo, lchallenge, rchallenge); - (void)ddsrt_hh_add(impl->objectHash, relation); - ddsrt_avl_insert(&relations_treedef, &linfo->relations, relation); + remoteIdent = find_remote_identity_by_guid(impl->remoteGuidHash, remote_participant_guid); + if (!remoteIdent) { + remoteIdent = remoteIdentityInfoNew(remote_participant_guid, remote_identity_token); + (void)ddsrt_hh_add(impl->objectHash, remoteIdent); + (void)ddsrt_hh_add(impl->remoteGuidHash, remoteIdent); + relation = identityRelationNew(localIdent, remoteIdent, lchallenge, rchallenge); + (void)ddsrt_hh_add(remoteIdent->linkHash, relation); } else { - ddsrt_avl_ipath_t path; /* When the remote identity has already been validated before, check if the remote identity token matches with the existing one */ - if (!DDS_Security_DataHolder_equal(rinfo->remoteIdentityToken, remote_identity_token)) { + if (!DDS_Security_DataHolder_equal(remoteIdent->remoteIdentityToken, remote_identity_token)) { result = DDS_SECURITY_VALIDATION_FAILED; DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "validate_remote_identity: remote_identity_token does not match with previously received one"); goto err_inv_duplicate; } - relation = ddsrt_avl_lookup_ipath(&relations_treedef, &linfo->relations, rinfo, &path); + + relation = find_identity_relation(remoteIdent, SECURITY_OBJECT_HANDLE(localIdent)); if (!relation) { - relation = identityRelationNew(linfo, rinfo, lchallenge, rchallenge); - (void)ddsrt_hh_add(impl->objectHash, relation); - ddsrt_avl_insert_ipath(&relations_treedef, &linfo->relations, relation, &path); + relation = identityRelationNew(localIdent, remoteIdent, lchallenge, rchallenge); + r = ddsrt_hh_add(remoteIdent->linkHash, relation); + assert(r); + (void)r; } else { if (remote_auth_request_token) { assert(rchallenge); @@ -1392,9 +1464,9 @@ validate_remote_identity( DDS_Security_set_token_nil(local_auth_request_token); } - *remote_identity_handle = IDENTITY_HANDLE(relation); + *remote_identity_handle = IDENTITY_HANDLE(remoteIdent);; - if (memcmp(&linfo->adjustedGUID, &rinfo->guid, sizeof(DDS_Security_GUID_t)) < 0) { + if (memcmp(&localIdent->adjustedGUID, &remoteIdent->guid, sizeof(DDS_Security_GUID_t)) < 0) { result = DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST; } else { result = DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE; @@ -1429,7 +1501,8 @@ begin_handshake_request( HandshakeInfo *handshake = NULL; IdentityRelation *relation = NULL; SecurityObject *obj; - LocalIdentityInfo *linfo; + LocalIdentityInfo *localIdent; + RemoteIdentityInfo *remoteIdent; EVP_PKEY *dhkey; DDS_Security_BinaryProperty_t *tokens; DDS_Security_BinaryProperty_t *c_id; @@ -1460,47 +1533,50 @@ begin_handshake_request( "begin_handshake_request: Invalid initiator_identity_handle provided"); goto err_inv_handle; } - linfo = (LocalIdentityInfo *) obj; + localIdent = (LocalIdentityInfo *) obj; obj = security_object_find(impl->objectHash, replier_identity_handle); - if (!obj || !security_object_valid(obj, SECURITY_OBJECT_KIND_IDENTITY_RELATION)) { + if (!obj || !security_object_valid(obj, SECURITY_OBJECT_KIND_REMOTE_IDENTITY)) { DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "begin_handshake_request: Invalid replier_identity_handle provided"); goto err_inv_handle; } - relation = (IdentityRelation *)obj; - handshake = relation->handshake; + remoteIdent = (RemoteIdentityInfo *)obj; - result = get_certificate_contents(linfo->identityCert, &certData, &certDataSize, ex); + result = get_certificate_contents(localIdent->identityCert, &certData, &certDataSize, ex); if (result != DDS_SECURITY_VALIDATION_OK) { goto err_alloc_cid; } + handshake = find_handshake(impl, SECURITY_OBJECT_HANDLE(localIdent), SECURITY_OBJECT_HANDLE(remoteIdent)); if (!handshake) { - handshake = handshakeInfoNew(relation); + relation = find_identity_relation(remoteIdent, SECURITY_OBJECT_HANDLE(localIdent)); + assert(relation); + handshake = handshakeInfoNew(localIdent, remoteIdent, relation); handshake->created_in = CREATEDREQUEST; - relation->handshake = handshake; - (void)ddsrt_hh_add(impl->handshakes, handshake); + (void)ddsrt_hh_add(impl->objectHash, handshake); created = 1; + } else { + relation = handshake->relation; + assert(relation); } - assert(handshake->relation == relation); - if (!handshake->ldh) { - result = generate_dh_keys(&dhkey, linfo->kagreeAlgoKind, ex); + result = generate_dh_keys(&dhkey, localIdent->kagreeAlgoKind, ex); if (result != DDS_SECURITY_VALIDATION_OK) { goto err_gen_dh_keys; } + handshake->ldh = dhkey; } - result = dh_public_key_to_oct(handshake->ldh, linfo->kagreeAlgoKind, &dhPubKeyData, &dhPubKeyDataSize, ex); + result = dh_public_key_to_oct(handshake->ldh, localIdent->kagreeAlgoKind, &dhPubKeyData, &dhPubKeyDataSize, ex); if (result != DDS_SECURITY_VALIDATION_OK) { goto err_get_public_key; } - if (linfo->pdata._length == 0) { - DDS_Security_OctetSeq_copy(&linfo->pdata, serialized_local_participant_data); + if (localIdent->pdata._length == 0) { + DDS_Security_OctetSeq_copy(&localIdent->pdata, serialized_local_participant_data); } tokens = DDS_Security_BinaryPropertySeq_allocbuf(8); @@ -1517,8 +1593,8 @@ begin_handshake_request( DDS_Security_BinaryProperty_set_by_ref(c_id, "c.id", certData, certDataSize); /* Store the permission document in the c.perm property */ - if (linfo->permissionsDocument) { - DDS_Security_BinaryProperty_set_by_string(c_perm, "c.perm", linfo->permissionsDocument); + if (localIdent->permissionsDocument) { + DDS_Security_BinaryProperty_set_by_string(c_perm, "c.perm", localIdent->permissionsDocument); } else { DDS_Security_BinaryProperty_set_by_string(c_perm, "c.perm", ""); } @@ -1527,10 +1603,10 @@ begin_handshake_request( DDS_Security_BinaryProperty_set_by_value(c_pdata, "c.pdata", serialized_local_participant_data->_buffer, serialized_local_participant_data->_length); /* Set the used signing algorithm descriptor in c.dsign_algo */ - DDS_Security_BinaryProperty_set_by_string(c_dsign_algo, "c.dsign_algo", get_dsign_algo(linfo->dsignAlgoKind)); + DDS_Security_BinaryProperty_set_by_string(c_dsign_algo, "c.dsign_algo", get_dsign_algo(localIdent->dsignAlgoKind)); /* Set the used key algorithm descriptor in c.kagree_algo */ - DDS_Security_BinaryProperty_set_by_string(c_kagree_algo, "c.kagree_algo", get_kagree_algo(linfo->kagreeAlgoKind)); + DDS_Security_BinaryProperty_set_by_string(c_kagree_algo, "c.kagree_algo", get_kagree_algo(localIdent->kagreeAlgoKind)); /* Calculate the hash_c1 */ { @@ -1551,6 +1627,8 @@ begin_handshake_request( /* Set the challenge in challenge1 property */ DDS_Security_BinaryProperty_set_by_value(challenge, "challenge1", relation->lchallenge->value, sizeof(AuthenticationChallenge)); + (void)ddsrt_hh_add(impl->objectHash, handshake); + ddsrt_mutex_unlock(&impl->lock); handshake_message->class_id = ddsrt_strdup(AUTH_HANDSHAKE_REQUEST_TOKEN_ID); @@ -1565,8 +1643,8 @@ begin_handshake_request( err_get_public_key: err_gen_dh_keys: if (created) { - (void)ddsrt_hh_remove(impl->handshakes, handshake); - handshakeInfoFree(handshake); + (void)ddsrt_hh_remove(impl->objectHash, handshake); + security_object_free((SecurityObject *)handshake); } err_alloc_cid: ddsrt_free(certData); @@ -2424,8 +2502,8 @@ begin_handshake_reply( HandshakeInfo *handshake = NULL; IdentityRelation *relation = NULL; SecurityObject *obj; - LocalIdentityInfo *linfo; - RemoteIdentityInfo *rinfo; + LocalIdentityInfo *localIdent; + RemoteIdentityInfo *remoteIdent; EVP_PKEY *dhkeyLocal = NULL; DDS_Security_BinaryProperty_t *tokens; DDS_Security_BinaryProperty_t *c_id; @@ -2469,40 +2547,41 @@ begin_handshake_reply( "begin_handshake_reply: Invalid replier_identity_handle provided"); goto err_inv_handle; } - linfo = (LocalIdentityInfo *) obj; + localIdent = (LocalIdentityInfo *) obj; obj = security_object_find(impl->objectHash, initiator_identity_handle); - if (!obj || !security_object_valid(obj, SECURITY_OBJECT_KIND_IDENTITY_RELATION)) { + if (!obj || !security_object_valid(obj, SECURITY_OBJECT_KIND_REMOTE_IDENTITY)) { DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "begin_handshake_reply: Invalid initiator_identity_handle provided"); goto err_inv_handle; } - relation = (IdentityRelation *)obj; - rinfo = relation->remoteIdentity; - handshake = relation->handshake; + remoteIdent = (RemoteIdentityInfo *)obj; + handshake = find_handshake(impl, SECURITY_OBJECT_HANDLE(localIdent), SECURITY_OBJECT_HANDLE(remoteIdent)); if (!handshake) { - handshake = handshakeInfoNew(relation); - relation->handshake = handshake; + relation = find_identity_relation(remoteIdent, SECURITY_OBJECT_HANDLE(localIdent)); + assert(relation); + handshake = handshakeInfoNew(localIdent, remoteIdent, relation); handshake->created_in = CREATEDREPLY; - (void)ddsrt_hh_add(impl->handshakes, handshake); + (void)ddsrt_hh_add(impl->objectHash, handshake); created = 1; + } else { + relation = handshake->relation; + assert(relation); } - assert(handshake->relation == relation); - result = validate_handshake_request_token(handshake_message_in, handshake, &(impl->trustedCAList), ex); if (result != DDS_SECURITY_VALIDATION_OK) { goto err_inv_token; } - result = get_certificate_contents(linfo->identityCert, &certData, &certDataSize, ex); + result = get_certificate_contents(localIdent->identityCert, &certData, &certDataSize, ex); if (result != DDS_SECURITY_VALIDATION_OK) { goto err_alloc_cid; } if (!handshake->ldh) { - result = generate_dh_keys(&dhkeyLocal, rinfo->kagreeAlgoKind, ex); + result = generate_dh_keys(&dhkeyLocal, remoteIdent->kagreeAlgoKind, ex); if (result != DDS_SECURITY_VALIDATION_OK) { goto err_gen_dh_keys; } @@ -2511,13 +2590,13 @@ begin_handshake_reply( EVP_PKEY_copy_parameters(handshake->rdh, handshake->ldh); } - result = dh_public_key_to_oct(handshake->ldh, rinfo->kagreeAlgoKind, &dhPubKeyData, &dhPubKeyDataSize, ex); + result = dh_public_key_to_oct(handshake->ldh, remoteIdent->kagreeAlgoKind, &dhPubKeyData, &dhPubKeyDataSize, ex); if (result != DDS_SECURITY_VALIDATION_OK) { goto err_get_public_key; } - if (linfo->pdata._length == 0) { - DDS_Security_OctetSeq_copy(&linfo->pdata, serialized_local_participant_data); + if (localIdent->pdata._length == 0) { + DDS_Security_OctetSeq_copy(&localIdent->pdata, serialized_local_participant_data); } hash_c1_ref = DDS_Security_DataHolder_find_binary_property(handshake_message_in, "hash_c1"); @@ -2543,8 +2622,8 @@ begin_handshake_reply( certData = NULL; /* Store the permission document in the c.perm property */ - if (linfo->permissionsDocument) { - DDS_Security_BinaryProperty_set_by_string(c_perm, "c.perm", linfo->permissionsDocument); + if (localIdent->permissionsDocument) { + DDS_Security_BinaryProperty_set_by_string(c_perm, "c.perm", localIdent->permissionsDocument); } else { DDS_Security_BinaryProperty_set_by_string(c_perm, "c.perm", ""); } @@ -2553,10 +2632,10 @@ begin_handshake_reply( DDS_Security_BinaryProperty_set_by_value(c_pdata, "c.pdata", serialized_local_participant_data->_buffer, serialized_local_participant_data->_length); /* Set the used signing algorithm descriptor in c.dsign_algo */ - DDS_Security_BinaryProperty_set_by_string(c_dsign_algo, "c.dsign_algo", get_dsign_algo(linfo->dsignAlgoKind)); + DDS_Security_BinaryProperty_set_by_string(c_dsign_algo, "c.dsign_algo", get_dsign_algo(localIdent->dsignAlgoKind)); /* Set the used key algorithm descriptor in c.kagree_algo */ - DDS_Security_BinaryProperty_set_by_string(c_kagree_algo, "c.kagree_algo", get_kagree_algo(rinfo->kagreeAlgoKind)); + DDS_Security_BinaryProperty_set_by_string(c_kagree_algo, "c.kagree_algo", get_kagree_algo(remoteIdent->kagreeAlgoKind)); /* Calculate the hash_c2 */ { @@ -2609,7 +2688,7 @@ begin_handshake_reply( binary_properties[4] = dh1; binary_properties[5] = hash_c1_val; - result = create_signature(linfo->privateKey, binary_properties, HANDSHAKE_SIGNATURE_CONTENT_SIZE , &sign, &signlen, ex); + result = create_signature(localIdent->privateKey, binary_properties, HANDSHAKE_SIGNATURE_CONTENT_SIZE , &sign, &signlen, ex); DDS_Security_BinaryProperty_free(hash_c1_val); DDS_Security_BinaryProperty_free(hash_c2_val); @@ -2620,12 +2699,15 @@ begin_handshake_reply( DDS_Security_BinaryProperty_set_by_ref(signature, "signature", sign, (uint32_t)signlen); } + (void)ddsrt_hh_add(impl->objectHash, handshake); + handshake_message_out->class_id = ddsrt_strdup(AUTH_HANDSHAKE_REPLY_TOKEN_ID); handshake_message_out->binary_properties._length = tokenSize; handshake_message_out->binary_properties._buffer = tokens; ddsrt_mutex_unlock(&impl->lock); + *handshake_handle = HANDSHAKE_HANDLE(handshake); if (result == DDS_SECURITY_VALIDATION_OK) { @@ -2642,8 +2724,8 @@ err_gen_dh_keys: err_alloc_cid: err_inv_token: if (created) { - (void)ddsrt_hh_remove(impl->handshakes, handshake); - handshakeInfoFree(handshake); + (void)ddsrt_hh_remove(impl->objectHash, handshake); + security_object_free((SecurityObject *)handshake); } err_inv_handle: ddsrt_mutex_unlock(&impl->lock); @@ -2651,6 +2733,7 @@ err_bad_param: return DDS_SECURITY_VALIDATION_FAILED; } + static bool generate_shared_secret( const HandshakeInfo *handshake, @@ -2716,6 +2799,9 @@ fail_ctx_new: return result; } + + + DDS_Security_ValidationResult_t process_handshake( dds_security_authentication *instance, @@ -2759,7 +2845,7 @@ process_handshake( ddsrt_mutex_lock(&impl->lock); - obj = security_object_find(impl->handshakes, handshake_handle); + obj = security_object_find(impl->objectHash, handshake_handle); if (!obj || !security_object_valid(obj, SECURITY_OBJECT_KIND_HANDSHAKE)) { DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, @@ -2847,6 +2933,7 @@ process_handshake( challenge2_ref->value._length); } + /* Calculate the signature */ { const DDS_Security_BinaryProperty_t * binary_properties[ HANDSHAKE_SIGNATURE_CONTENT_SIZE ]; @@ -2895,10 +2982,12 @@ process_handshake( goto err_inv_token; } + challenge2_ref_for_shared_secret = (DDS_Security_octet*)(handshake->relation->lchallenge); challenge1_ref_for_shared_secret = (DDS_Security_octet*)(handshake->relation->rchallenge); result = DDS_SECURITY_VALIDATION_OK; + break; default: ddsrt_mutex_unlock(&impl->lock); @@ -2931,9 +3020,10 @@ process_handshake( goto err_invalid_expiry; } else if( certExpiry != DDS_NEVER ){ add_validity_end_trigger( impl, - IDENTITY_HANDLE( handshake->relation ), + IDENTITY_HANDLE( handshake->relation->remoteIdentity ), certExpiry); } + } ddsrt_mutex_unlock(&impl->lock); @@ -2971,14 +3061,14 @@ DDS_Security_SharedSecretHandle get_shared_secret( } ddsrt_mutex_lock(&impl->lock); - obj = security_object_find(impl->handshakes, handshake_handle); + obj = security_object_find(impl->objectHash, handshake_handle); if (!obj || !security_object_valid(obj, SECURITY_OBJECT_KIND_HANDSHAKE)) { DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "return_handshake_handle: Invalid handle provided"); goto err_invalid_handle; } ddsrt_mutex_unlock(&impl->lock); - return (DDS_Security_SharedSecretHandle)(uintptr_t)((HandshakeInfo*)obj)->shared_secret_handle_impl; + return (DDS_Security_SharedSecretHandle)(ddsrt_address)((HandshakeInfo*)obj)->shared_secret_handle_impl; err_invalid_handle: @@ -3011,7 +3101,7 @@ get_authenticated_peer_credential_token( ddsrt_mutex_lock(&impl->lock); - handshake = (HandshakeInfo *) security_object_find(impl->handshakes, handshake_handle); + handshake = (HandshakeInfo *) security_object_find(impl->objectHash, handshake_handle); if (!handshake || !SECURITY_OBJECT_VALID(handshake, SECURITY_OBJECT_KIND_HANDSHAKE)) { DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, @@ -3136,15 +3226,18 @@ return_handshake_handle(dds_security_authentication *instance, } ddsrt_mutex_lock(&impl->lock); - obj = security_object_find(impl->handshakes, handshake_handle); + obj = security_object_find(impl->objectHash, handshake_handle); if (!obj || !security_object_valid(obj, SECURITY_OBJECT_KIND_HANDSHAKE)) { DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "return_handshake_handle: Invalid handle provided"); goto err_invalid_handle; } handshake = (HandshakeInfo *)obj; - (void)ddsrt_hh_remove(impl->handshakes, handshake); - handshakeInfoFree(handshake); + assert(handshake->relation); + + (void)ddsrt_hh_remove(impl->objectHash, obj); + security_object_free((SecurityObject *)handshake); + ddsrt_mutex_unlock(&impl->lock); return true; @@ -3155,63 +3248,56 @@ err_bad_param: return false; } -static void -release_remote_info( - dds_security_authentication_impl *impl, - RemoteIdentityInfo *info) -{ - if (--info->refc == 0) { - (void)ddsrt_hh_remove(impl->remoteGuidHash, info); - remoteIdentityInfoFree(info); - } -} static void invalidate_local_related_objects( dds_security_authentication_impl *impl, - LocalIdentityInfo *linfo) + LocalIdentityInfo *localIdent) { - IdentityRelation *relation; + struct ddsrt_hh_iter it; + SecurityObject *obj; - relation = ddsrt_avl_find_min(&relations_treedef, &linfo->relations); - while (relation) { - IdentityRelation *next = ddsrt_avl_find_succ(&relations_treedef, &linfo->relations, relation); + for (obj = ddsrt_hh_iter_first(impl->objectHash, &it); obj != NULL; obj = ddsrt_hh_iter_next(&it)) { + if (obj->kind == SECURITY_OBJECT_KIND_REMOTE_IDENTITY) { + RemoteIdentityInfo *remoteIdent = (RemoteIdentityInfo *)obj; + IdentityRelation *relation; + HandshakeInfo *handshake; - assert(relation->remoteIdentity); + handshake = find_handshake(impl, SECURITY_OBJECT_HANDLE(localIdent), SECURITY_OBJECT_HANDLE(remoteIdent)); + if (handshake) { + (void)ddsrt_hh_remove(impl->objectHash, handshake); + security_object_free((SecurityObject *) handshake); + } - if (relation->handshake) { - (void)ddsrt_hh_remove(impl->handshakes, relation->handshake); - handshakeInfoFree(relation->handshake); + relation = find_identity_relation(remoteIdent, SECURITY_OBJECT_HANDLE(localIdent)); + if (relation) { + remove_identity_relation(remoteIdent, relation); + } } - release_remote_info(impl, relation->remoteIdentity); - ddsrt_avl_delete(&relations_treedef, &linfo->relations, relation); - (void)ddsrt_hh_remove(impl->objectHash, relation); - identityRelationFree(relation); - relation = next; } - (void)ddsrt_hh_remove(impl->objectHash, linfo); - localIdentityInfoFree(linfo); } static void invalidate_remote_related_objects( dds_security_authentication_impl *impl, - IdentityRelation *relation) + RemoteIdentityInfo *remoteIdentity) { - assert(relation->remoteIdentity); - assert(relation->localIdentity); + struct ddsrt_hh_iter it; + IdentityRelation *relation; + HandshakeInfo *handshake; - if (relation->handshake) { - (void)ddsrt_hh_remove(impl->handshakes, relation->handshake); - handshakeInfoFree(relation->handshake); + for (relation = ddsrt_hh_iter_first(remoteIdentity->linkHash, &it); relation != NULL; relation = ddsrt_hh_iter_next(&it)) { + handshake = find_handshake(impl, SECURITY_OBJECT_HANDLE(relation->localIdentity), SECURITY_OBJECT_HANDLE(remoteIdentity)); + if (handshake) { + (void)ddsrt_hh_remove(impl->objectHash, handshake); + security_object_free((SecurityObject *) handshake); + } + + (void)ddsrt_hh_remove(remoteIdentity->linkHash, relation); + security_object_free((SecurityObject *) relation); } - release_remote_info(impl, relation->remoteIdentity); - ddsrt_avl_delete(&relations_treedef, &relation->localIdentity->relations, relation); - (void)ddsrt_hh_remove(impl->objectHash, relation); - identityRelationFree(relation); } - DDS_Security_boolean return_identity_handle( dds_security_authentication *instance, @@ -3221,8 +3307,8 @@ return_identity_handle( DDS_Security_boolean result = true; dds_security_authentication_impl *impl = (dds_security_authentication_impl *) instance; SecurityObject *obj; - LocalIdentityInfo *linfo; - IdentityRelation *relation; + LocalIdentityInfo *localIdent; + RemoteIdentityInfo *remoteIdent; /* validate provided arguments */ if (!instance || !identity_handle) { @@ -3245,12 +3331,17 @@ return_identity_handle( switch (obj->kind) { case SECURITY_OBJECT_KIND_LOCAL_IDENTITY: - linfo = (LocalIdentityInfo *) obj; - invalidate_local_related_objects(impl, linfo); + localIdent = (LocalIdentityInfo *) obj; + invalidate_local_related_objects(impl, localIdent); + (void)ddsrt_hh_remove(impl->objectHash, obj); + security_object_free(obj); break; - case SECURITY_OBJECT_KIND_IDENTITY_RELATION: - relation = (IdentityRelation *) obj; - invalidate_remote_related_objects(impl, relation); + case SECURITY_OBJECT_KIND_REMOTE_IDENTITY: + remoteIdent = (RemoteIdentityInfo *) obj; + invalidate_remote_related_objects(impl, remoteIdent); + (void)ddsrt_hh_remove(impl->remoteGuidHash, remoteIdent); + (void)ddsrt_hh_remove(impl->objectHash, obj); + security_object_free(obj); break; default: DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "return_identity_handle: Invalid handle provided"); @@ -3259,6 +3350,7 @@ return_identity_handle( } ddsrt_mutex_unlock(&impl->lock); + return result; err_invalid_handle: @@ -3279,8 +3371,10 @@ DDS_Security_boolean return_sharedsecret_handle( return true; } -int32_t init_authentication( const char *argument, void **context) +int32_t +init_authentication( const char *argument, void **context) { + dds_security_authentication_impl *authentication; DDSRT_UNUSED_ARG(argument); @@ -3296,31 +3390,51 @@ int32_t init_authentication( const char *argument, void **context) /* assign the interface functions */ authentication->base.validate_local_identity = &validate_local_identity; + authentication->base.get_identity_token = &get_identity_token; + authentication->base.get_identity_status_token = &get_identity_status_token; - authentication->base.set_permissions_credential_and_token = &set_permissions_credential_and_token; + + authentication->base.set_permissions_credential_and_token = + &set_permissions_credential_and_token; + authentication->base.validate_remote_identity = &validate_remote_identity; + authentication->base.begin_handshake_request = &begin_handshake_request; + authentication->base.begin_handshake_reply = &begin_handshake_reply; + authentication->base.process_handshake = &process_handshake; + authentication->base.get_shared_secret = &get_shared_secret; - authentication->base.get_authenticated_peer_credential_token = &get_authenticated_peer_credential_token; + + authentication->base.get_authenticated_peer_credential_token = + &get_authenticated_peer_credential_token; + authentication->base.set_listener = &set_listener; + authentication->base.return_identity_token = &return_identity_token; - authentication->base.return_identity_status_token = &return_identity_status_token; - authentication->base.return_authenticated_peer_credential_token = &return_authenticated_peer_credential_token; + + authentication->base.return_identity_status_token = + &return_identity_status_token; + + authentication->base.return_authenticated_peer_credential_token = + &return_authenticated_peer_credential_token; + authentication->base.return_handshake_handle = &return_handshake_handle; + authentication->base.return_identity_handle = &return_identity_handle; + authentication->base.return_sharedsecret_handle = &return_sharedsecret_handle; ddsrt_mutex_init(&authentication->lock); authentication->objectHash = ddsrt_hh_new(32, security_object_hash, security_object_equal); authentication->remoteGuidHash = ddsrt_hh_new(32, remote_guid_hash, remote_guid_equal); - authentication->handshakes = ddsrt_hh_new(32, security_object_hash, security_object_equal); memset( &authentication->trustedCAList, 0, sizeof(X509Seq)); + /* Initialize openssl */ OpenSSL_add_all_algorithms(); OpenSSL_add_all_ciphers(); @@ -3343,8 +3457,6 @@ err_mutex_failed: int32_t finalize_authentication(void *instance) { dds_security_authentication_impl *authentication = instance; - LocalIdentityInfo *linfo; - IdentityRelation *relation; if( authentication ){ ddsrt_mutex_lock(&authentication->lock); @@ -3352,37 +3464,25 @@ int32_t finalize_authentication(void *instance) dds_security_timed_dispatcher_free(authentication->timed_callbacks, authentication->dispatcher); dds_security_timed_cb_free(authentication->timed_callbacks); - if (authentication->objectHash) { - struct ddsrt_hh_iter it; - SecurityObject *obj; - for (obj = ddsrt_hh_iter_first(authentication->objectHash, &it); obj != NULL; obj = ddsrt_hh_iter_next(&it)) { - switch (obj->kind) { - case SECURITY_OBJECT_KIND_LOCAL_IDENTITY: - linfo = (LocalIdentityInfo *) obj; - invalidate_local_related_objects(authentication, linfo); - break; - case SECURITY_OBJECT_KIND_IDENTITY_RELATION: - relation = (IdentityRelation *) obj; - invalidate_remote_related_objects(authentication, relation); - break; - default: - break; - } - } - ddsrt_hh_free(authentication->objectHash); - } - if (authentication->remoteGuidHash) { ddsrt_hh_free(authentication->remoteGuidHash); } - if (authentication->handshakes) { - ddsrt_hh_free(authentication->handshakes); + if (authentication->objectHash) { + struct ddsrt_hh_iter it; + SecurityObject *obj; + for (obj = ddsrt_hh_iter_first(authentication->objectHash, &it); obj != NULL; obj = ddsrt_hh_iter_next(&it)) { + security_object_free(obj); + } + ddsrt_hh_free(authentication->objectHash); } free_ca_list_contents(&(authentication->trustedCAList)); + ddsrt_mutex_unlock(&authentication->lock); + ddsrt_mutex_destroy(&authentication->lock); + ddsrt_free((dds_security_authentication_impl*) instance); } diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.c b/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.c index f002ad7..59d19af 100644 --- a/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.c +++ b/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.c @@ -71,21 +71,35 @@ static bool check_not_data_empty(const DDS_Security_OctetSeq *seq) return false; } -static bool check_crypto_keymaterial(const DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat) +static bool check_crypto_keymaterial( + const dds_security_crypto_key_exchange_impl *impl, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat, + const int64_t handle) { - bool status; - + bool status = false; uint32_t transform_kind = CRYPTO_TRANSFORM_KIND(keymat->transformation_kind); uint32_t key_sz = CRYPTO_KEY_SIZE_BYTES(transform_kind); - status = (transform_kind >= CRYPTO_TRANSFORMATION_KIND_AES128_GMAC && transform_kind <= CRYPTO_TRANSFORMATION_KIND_AES256_GCM && - keymat->master_salt._length == key_sz && keymat->master_salt._buffer != NULL && check_not_data_empty(&keymat->master_salt) && - keymat->master_sender_key._length == key_sz && keymat->master_sender_key._buffer != NULL && check_not_data_empty(&keymat->master_sender_key)); - - if (status && CRYPTO_TRANSFORM_ID(keymat->receiver_specific_key_id)) + if (transform_kind != CRYPTO_TRANSFORMATION_KIND_NONE) { - status = (keymat->master_receiver_specific_key._length == key_sz && - keymat->master_receiver_specific_key._buffer != NULL && check_not_data_empty(&keymat->master_receiver_specific_key)); + status = (transform_kind <= CRYPTO_TRANSFORMATION_KIND_AES256_GCM && + keymat->master_salt._length == key_sz && keymat->master_salt._buffer != NULL && check_not_data_empty(&keymat->master_salt) && + keymat->master_sender_key._length == key_sz && keymat->master_sender_key._buffer != NULL && check_not_data_empty(&keymat->master_sender_key)); + + if (status && CRYPTO_TRANSFORM_ID(keymat->receiver_specific_key_id)) + { + status = (keymat->master_receiver_specific_key._length == key_sz && + keymat->master_receiver_specific_key._buffer != NULL && check_not_data_empty(&keymat->master_receiver_specific_key)); + } + } + else + { + const dds_security_crypto_key_factory *factory; + DDS_Security_ProtectionKind kind; + + factory = cryptography_get_crypto_key_factory(impl->crypto); + if (crypto_factory_get_protection_kind(factory, handle, &kind)) + status = (kind == DDS_SECURITY_PROTECTION_KIND_NONE); } return status; @@ -179,12 +193,34 @@ create_local_participant_crypto_tokens( tokens->_buffer[0].binary_properties._buffer[0].value._length = tokens->_buffer[0].binary_properties._buffer[0].value._maximum = length; tokens->_buffer[0].binary_properties._buffer[0].value._buffer = buffer; + tokens->_buffer[0].binary_properties._buffer[0].propagate = true; return true; fail_invalid_arg: return false; } + +static DDS_Security_boolean +allow_empty_tokens( + const dds_security_crypto_key_exchange_impl *impl, + const DDS_Security_ParticipantCryptoTokenSeq *tokens, + const int64_t handle) +{ + const dds_security_crypto_key_factory *factory; + DDS_Security_ProtectionKind kind; + + if (tokens->_length > 0) + return false; + + factory = cryptography_get_crypto_key_factory(impl->crypto); + if (crypto_factory_get_protection_kind(factory, handle, &kind)) + return (kind == DDS_SECURITY_PROTECTION_KIND_NONE); + + return false; +} + + static DDS_Security_boolean set_remote_participant_crypto_tokens( dds_security_crypto_key_exchange *instance, @@ -207,6 +243,9 @@ set_remote_participant_crypto_tokens( return false; } + if (allow_empty_tokens(impl, tokens, remote_id)) + return true; + if (!check_crypto_tokens(tokens)) { DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, @@ -229,7 +268,7 @@ set_remote_participant_crypto_tokens( "set_remote_participant_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); result = false; } - else if (!check_crypto_keymaterial(&remote_key_mat)) + else if (!check_crypto_keymaterial(impl, &remote_key_mat, remote_id)) { DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, "set_remote_participant_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); @@ -290,6 +329,7 @@ create_local_datawriter_crypto_tokens( tokens->_buffer[i].binary_properties._buffer[0].value._length = tokens->_buffer[i].binary_properties._buffer[0].value._maximum = length; tokens->_buffer[i].binary_properties._buffer[0].value._buffer = buffer; + tokens->_buffer[i].binary_properties._buffer[0].propagate = true; CRYPTO_OBJECT_RELEASE(key_mat[i]); } @@ -317,6 +357,9 @@ set_remote_datawriter_crypto_tokens( return false; } + if (allow_empty_tokens(impl, tokens, remote_writer_handle)) + return true; + if (!check_crypto_tokens(tokens)) { DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, @@ -347,7 +390,7 @@ set_remote_datawriter_crypto_tokens( "set_remote_datawriter_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); result = false; } - else if (!check_crypto_keymaterial(&remote_key_mat[i])) + else if (!check_crypto_keymaterial(impl, &remote_key_mat[i], remote_writer_handle)) { DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, "set_remote_datawriter_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); @@ -409,6 +452,7 @@ create_local_datareader_crypto_tokens( tokens->_buffer[0].binary_properties._buffer[0].value._length = tokens->_buffer[0].binary_properties._buffer[0].value._maximum = length; tokens->_buffer[0].binary_properties._buffer[0].value._buffer = buffer; + tokens->_buffer[0].binary_properties._buffer[0].propagate = true; CRYPTO_OBJECT_RELEASE(key_mat); } @@ -444,6 +488,9 @@ set_remote_datareader_crypto_tokens( return false; } + if (allow_empty_tokens(impl, tokens, remote_reader_handle)) + return true; + if (!check_crypto_tokens(tokens)) { DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, @@ -466,7 +513,7 @@ set_remote_datareader_crypto_tokens( "set_remote_datareader_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); result = false; } - else if (!check_crypto_keymaterial(&remote_key_mat)) + else if (!check_crypto_keymaterial(impl, &remote_key_mat, remote_reader_handle)) { DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, "set_remote_datareader_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.c b/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.c index e77c99c..61e3f9e 100644 --- a/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.c +++ b/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.c @@ -245,6 +245,7 @@ remove_relation_from_keymaterial( CryptoObject *remote_crypto) { endpoint_relation *relation; + relation = crypto_endpoint_relation_find_by_crypto(key_material->endpoint_relations, local_crypto, remote_crypto); if (relation) { @@ -258,24 +259,21 @@ remove_remote_writer_relation( dds_security_crypto_key_factory_impl *implementation, remote_datawriter_crypto *remote_writer) { - local_datareader_crypto *local_reader; remote_participant_crypto *remote_participant; participant_key_material *key_material; + DDSRT_UNUSED_ARG(implementation); + assert(remote_writer); remote_participant = remote_writer->participant; assert(remote_participant); - local_reader = (local_datareader_crypto *)crypto_object_table_find(implementation->crypto_objects, remote_writer->local_reader_handle); - if (local_reader) + + key_material = (participant_key_material *)crypto_object_table_find( + remote_participant->key_material, CRYPTO_OBJECT_HANDLE(remote_writer->local_reader->participant)); + if (key_material) { - key_material = (participant_key_material *)crypto_object_table_find( - remote_participant->key_material, CRYPTO_OBJECT_HANDLE(local_reader->participant)); - if (key_material) - { - remove_relation_from_keymaterial(key_material, (CryptoObject *)local_reader, (CryptoObject *)remote_writer); - CRYPTO_OBJECT_RELEASE(key_material); - } - CRYPTO_OBJECT_RELEASE(local_reader); + remove_relation_from_keymaterial(key_material, (CryptoObject *)remote_writer->local_reader, (CryptoObject *)remote_writer); + CRYPTO_OBJECT_RELEASE(key_material); } } @@ -284,24 +282,21 @@ remove_remote_reader_relation( dds_security_crypto_key_factory_impl *implementation, remote_datareader_crypto *remote_reader) { - local_datawriter_crypto *local_writer; remote_participant_crypto *remote_participant; participant_key_material *key_material; + DDSRT_UNUSED_ARG(implementation); + assert(remote_reader); remote_participant = remote_reader->participant; assert(remote_participant); - local_writer = (local_datawriter_crypto *)crypto_object_table_find(implementation->crypto_objects, remote_reader->local_writer_handle); - if (local_writer) + + key_material = (participant_key_material *)crypto_object_table_find( + remote_participant->key_material, CRYPTO_OBJECT_HANDLE(remote_reader->local_writer->participant)); + if (key_material) { - key_material = (participant_key_material *)crypto_object_table_find( - remote_participant->key_material, CRYPTO_OBJECT_HANDLE(local_writer->participant)); - if (key_material) - { - remove_relation_from_keymaterial(key_material, (CryptoObject *)local_writer, (CryptoObject *)remote_reader); - CRYPTO_OBJECT_RELEASE(key_material); - } - CRYPTO_OBJECT_RELEASE(local_writer); + remove_relation_from_keymaterial(key_material, (CryptoObject *)remote_reader->local_writer, (CryptoObject *)remote_reader); + CRYPTO_OBJECT_RELEASE(key_material); } } @@ -562,6 +557,7 @@ register_local_datawriter( crypto_object_table_insert(implementation->crypto_objects, (CryptoObject *)writer_crypto); CRYPTO_OBJECT_RELEASE(participant_crypto); CRYPTO_OBJECT_RELEASE(writer_crypto); + return writer_crypto->_parent.handle; err_random_generation: @@ -619,7 +615,7 @@ register_matched_remote_datareader( data_protectionKind = local_writer->data_protectionKind; metadata_protectionKind = local_writer->metadata_protectionKind; - reader_crypto = crypto_remote_datareader_crypto__new(remote_participant, metadata_protectionKind, data_protectionKind, local_datawriter_crypto_handle); + reader_crypto = crypto_remote_datareader_crypto__new(remote_participant, metadata_protectionKind, data_protectionKind, local_writer); /* check if the writer is BuiltinParticipantVolatileMessageSecureWriter */ if (local_writer->is_builtin_participant_volatile_message_secure_writer) @@ -667,6 +663,7 @@ register_matched_remote_datareader( CRYPTO_OBJECT_RELEASE(remote_participant); CRYPTO_OBJECT_RELEASE(local_writer); CRYPTO_OBJECT_RELEASE(reader_crypto); + return DATAREADER_CRYPTO_HANDLE(reader_crypto); err_random_generation: @@ -736,6 +733,7 @@ register_local_datareader( crypto_object_table_insert(implementation->crypto_objects, (CryptoObject *)reader_crypto); CRYPTO_OBJECT_RELEASE(participant_crypto); CRYPTO_OBJECT_RELEASE(reader_crypto); + return DATAREADER_CRYPTO_HANDLE(reader_crypto); err_random_generation: @@ -786,8 +784,7 @@ register_matched_remote_datawriter( goto err_invalid_parameter; } - writer_crypto = crypto_remote_datawriter_crypto__new(remote_participant, local_reader->metadata_protectionKind, - local_reader->data_protectionKind, local_datareader_crypto_handle); + writer_crypto = crypto_remote_datawriter_crypto__new(remote_participant, local_reader->metadata_protectionKind, local_reader->data_protectionKind, local_reader); /* check if the writer is BuiltinParticipantVolatileMessageSecureWriter */ if (local_reader->is_builtin_participant_volatile_message_secure_reader) @@ -833,6 +830,7 @@ register_matched_remote_datawriter( CRYPTO_OBJECT_RELEASE(remote_participant); CRYPTO_OBJECT_RELEASE(local_reader); CRYPTO_OBJECT_RELEASE(writer_crypto); + return DATAREADER_CRYPTO_HANDLE(writer_crypto); err_random_generation: @@ -983,6 +981,51 @@ void dds_security_crypto_key_factory__dealloc(dds_security_crypto_key_factory *i ddsrt_free(implementation); } + +bool +crypto_factory_get_protection_kind( + const dds_security_crypto_key_factory *factory, + int64_t handle, + DDS_Security_ProtectionKind *kind) +{ + const dds_security_crypto_key_factory_impl *impl = (const dds_security_crypto_key_factory_impl *)factory; + CryptoObject *obj; + bool result = true; + + obj = crypto_object_table_find(impl->crypto_objects, handle); + if (!obj) + { + return false; + } + + switch (obj->kind) + { + case CRYPTO_OBJECT_KIND_LOCAL_CRYPTO: + *kind = ((local_participant_crypto *)obj)->rtps_protection_kind; + break; + case CRYPTO_OBJECT_KIND_REMOTE_CRYPTO: + *kind = ((remote_participant_crypto *)obj)->rtps_protection_kind; + break; + case CRYPTO_OBJECT_KIND_LOCAL_WRITER_CRYPTO: + *kind = ((local_datawriter_crypto *)obj)->metadata_protectionKind; + break; + case CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO: + *kind = ((remote_datawriter_crypto *)obj)->metadata_protectionKind; + break; + case CRYPTO_OBJECT_KIND_LOCAL_READER_CRYPTO: + *kind = ((local_datareader_crypto *)obj)->metadata_protectionKind; + break; + case CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO: + *kind = ((remote_datareader_crypto *)obj)->metadata_protectionKind; + break; + default: + result = false; + break; + } + CRYPTO_OBJECT_RELEASE(obj); + return result; +} + bool crypto_factory_get_participant_crypto_tokens( const dds_security_crypto_key_factory *factory, @@ -1110,7 +1153,7 @@ crypto_factory_get_datawriter_crypto_tokens( goto err_inv_remote; } - if (remote_reader_crypto->local_writer_handle != local_writer_handle) + if (CRYPTO_OBJECT_HANDLE(remote_reader_crypto->local_writer) != local_writer_handle) { DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); @@ -1180,7 +1223,7 @@ crypto_factory_set_datawriter_crypto_tokens( goto err_inv_local; } - if (remote_writer_crypto->local_reader_handle != local_reader_handle) + if (CRYPTO_OBJECT_HANDLE(remote_writer_crypto->local_reader) != local_reader_handle) { DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); @@ -1254,7 +1297,7 @@ crypto_factory_get_datareader_crypto_tokens( goto err_inv_remote; } - if (remote_writer_crypto->local_reader_handle != local_reader_handle) + if (CRYPTO_OBJECT_HANDLE(remote_writer_crypto->local_reader) != local_reader_handle) { DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); @@ -1317,7 +1360,7 @@ crypto_factory_set_datareader_crypto_tokens( goto err_inv_local; } - if (remote_reader_crypto->local_writer_handle != local_writer_handle) + if (CRYPTO_OBJECT_HANDLE(remote_reader_crypto->local_writer) != local_writer_handle) { DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); @@ -1582,7 +1625,7 @@ crypto_factory_get_remote_writer_key_material( DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); goto err_inv_crypto; } - if (writer_crypto->local_reader_handle != reader_id) + if (CRYPTO_OBJECT_HANDLE(writer_crypto->local_reader) != reader_id) { DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); @@ -1646,7 +1689,7 @@ crypto_factory_get_remote_reader_key_material( DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); goto err_inv_crypto; } - if (reader_crypto->local_writer_handle != writer_id) + if (CRYPTO_OBJECT_HANDLE(reader_crypto->local_writer) != writer_id) { DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.h b/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.h index 5818b37..2fec8d7 100644 --- a/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.h +++ b/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.h @@ -29,6 +29,11 @@ int generate_key_pairs( char **private_key, char **public_key); +bool crypto_factory_get_protection_kind( + const dds_security_crypto_key_factory *factory, + int64_t handle, + DDS_Security_ProtectionKind *kind); + bool crypto_factory_get_participant_crypto_tokens( const dds_security_crypto_key_factory *factory, DDS_Security_ParticipantCryptoHandle local_id, diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_objects.c b/src/security/builtin_plugins/cryptographic/src/crypto_objects.c index 8fa9a06..86b1ea0 100644 --- a/src/security/builtin_plugins/cryptographic/src/crypto_objects.c +++ b/src/security/builtin_plugins/cryptographic/src/crypto_objects.c @@ -11,6 +11,7 @@ */ #include #include +#include #include "dds/ddsrt/heap.h" #include "dds/ddsrt/hopscotch.h" #include "dds/ddsrt/types.h" @@ -63,7 +64,9 @@ void crypto_object_free(CryptoObject *obj) CryptoObject * crypto_object_keep(CryptoObject *obj) { if (obj) + { ddsrt_atomic_inc32(&obj->refcount); + } return obj; } @@ -455,6 +458,7 @@ static void remote_datawriter_crypto__free(CryptoObject *obj) CRYPTO_OBJECT_RELEASE(datawriter_crypto->reader2writer_key_material); CRYPTO_OBJECT_RELEASE(datawriter_crypto->writer2reader_key_material[0]); CRYPTO_OBJECT_RELEASE(datawriter_crypto->writer2reader_key_material[1]); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->local_reader); CRYPTO_OBJECT_RELEASE(datawriter_crypto->participant); crypto_object_deinit((CryptoObject *)datawriter_crypto); ddsrt_free(datawriter_crypto); @@ -462,14 +466,14 @@ static void remote_datawriter_crypto__free(CryptoObject *obj) } remote_datawriter_crypto * crypto_remote_datawriter_crypto__new(const remote_participant_crypto *participant, - DDS_Security_ProtectionKind meta_protection, DDS_Security_BasicProtectionKind data_protection, DDS_Security_DatareaderCryptoHandle local_reader_handle) + DDS_Security_ProtectionKind meta_protection, DDS_Security_BasicProtectionKind data_protection, local_datareader_crypto *local_reader) { remote_datawriter_crypto *writer_crypto = ddsrt_calloc(1, sizeof(*writer_crypto)); crypto_object_init((CryptoObject *)writer_crypto, CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO, remote_datawriter_crypto__free); writer_crypto->participant = (remote_participant_crypto *)CRYPTO_OBJECT_KEEP(participant); writer_crypto->metadata_protectionKind = meta_protection; writer_crypto->data_protectionKind = data_protection; - writer_crypto->local_reader_handle = local_reader_handle; + writer_crypto->local_reader = (local_datareader_crypto *)CRYPTO_OBJECT_KEEP(local_reader); writer_crypto->is_builtin_participant_volatile_message_secure_writer = false; return writer_crypto; @@ -514,6 +518,7 @@ static void remote_datareader_crypto__free(CryptoObject *obj) CRYPTO_OBJECT_RELEASE(datareader_crypto->reader2writer_key_material); CRYPTO_OBJECT_RELEASE(datareader_crypto->writer2reader_key_material_message); CRYPTO_OBJECT_RELEASE(datareader_crypto->writer2reader_key_material_payload); + CRYPTO_OBJECT_RELEASE(datareader_crypto->local_writer); CRYPTO_OBJECT_RELEASE(datareader_crypto->participant); crypto_object_deinit((CryptoObject *)datareader_crypto); ddsrt_free(datareader_crypto); @@ -521,14 +526,14 @@ static void remote_datareader_crypto__free(CryptoObject *obj) } remote_datareader_crypto *crypto_remote_datareader_crypto__new(const remote_participant_crypto *participant, DDS_Security_ProtectionKind metadata_protectionKind, - DDS_Security_BasicProtectionKind data_protectionKind, DDS_Security_DatawriterCryptoHandle local_writer_handle) + DDS_Security_BasicProtectionKind data_protectionKind, local_datawriter_crypto *local_writer) { remote_datareader_crypto *reader_crypto = ddsrt_calloc(1, sizeof(*reader_crypto)); crypto_object_init((CryptoObject *)reader_crypto, CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO, remote_datareader_crypto__free); reader_crypto->participant = (remote_participant_crypto *)CRYPTO_OBJECT_KEEP(participant); reader_crypto->metadata_protectionKind = metadata_protectionKind; reader_crypto->data_protectionKind = data_protectionKind; - reader_crypto->local_writer_handle = local_writer_handle; + reader_crypto->local_writer = (local_datawriter_crypto *)CRYPTO_OBJECT_KEEP(local_writer); reader_crypto->is_builtin_participant_volatile_message_secure_reader = false; return reader_crypto; diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_objects.h b/src/security/builtin_plugins/cryptographic/src/crypto_objects.h index 3edb6a4..9a55570 100644 --- a/src/security/builtin_plugins/cryptographic/src/crypto_objects.h +++ b/src/security/builtin_plugins/cryptographic/src/crypto_objects.h @@ -165,7 +165,7 @@ typedef struct remote_datawriter_crypto master_key_material *reader2writer_key_material; master_key_material *writer2reader_key_material[2]; session_key_material *reader_session; /* reference to the session key used by the reader */ - DDS_Security_DatareaderCryptoHandle local_reader_handle; + struct local_datareader_crypto *local_reader; bool is_builtin_participant_volatile_message_secure_writer; } remote_datawriter_crypto; @@ -190,7 +190,7 @@ typedef struct remote_datareader_crypto master_key_material *writer2reader_key_material_message; master_key_material *writer2reader_key_material_payload; session_key_material *writer_session; /* reference to the session key used by the writer */ - DDS_Security_DatawriterCryptoHandle local_writer_handle; + local_datawriter_crypto *local_writer; bool is_builtin_participant_volatile_message_secure_reader; } remote_datareader_crypto; @@ -257,7 +257,7 @@ crypto_remote_datareader_crypto__new( const remote_participant_crypto *participant, DDS_Security_ProtectionKind metadata_protectionKind, DDS_Security_BasicProtectionKind data_protectionKind, - DDS_Security_DatawriterCryptoHandle local_writer_handle); + local_datawriter_crypto *local_writer); local_datareader_crypto * crypto_local_datareader_crypto__new( @@ -270,7 +270,7 @@ crypto_remote_datawriter_crypto__new( const remote_participant_crypto *participant, DDS_Security_ProtectionKind meta_protection, DDS_Security_BasicProtectionKind data_protection, - DDS_Security_DatareaderCryptoHandle local_reader_handle); + local_datareader_crypto *local_reader); CryptoObject * crypto_object_keep( diff --git a/src/security/builtin_plugins/tests/set_remote_datareader_crypto_tokens/src/set_remote_datareader_crypto_tokens_utests.c b/src/security/builtin_plugins/tests/set_remote_datareader_crypto_tokens/src/set_remote_datareader_crypto_tokens_utests.c index c8297bb..68e3448 100644 --- a/src/security/builtin_plugins/tests/set_remote_datareader_crypto_tokens/src/set_remote_datareader_crypto_tokens_utests.c +++ b/src/security/builtin_plugins/tests/set_remote_datareader_crypto_tokens/src/set_remote_datareader_crypto_tokens_utests.c @@ -149,6 +149,7 @@ register_local_datawriter(void) memset(&datawriter_security_attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); datawriter_security_attributes.is_discovery_protected = true; + datawriter_security_attributes.is_submessage_protected = true; local_writer_crypto = crypto->crypto_key_factory->register_local_datawriter( diff --git a/src/security/builtin_plugins/tests/set_remote_datawriter_crypto_tokens/src/set_remote_datawriter_crypto_tokens_utests.c b/src/security/builtin_plugins/tests/set_remote_datawriter_crypto_tokens/src/set_remote_datawriter_crypto_tokens_utests.c index 90c8112..a223604 100644 --- a/src/security/builtin_plugins/tests/set_remote_datawriter_crypto_tokens/src/set_remote_datawriter_crypto_tokens_utests.c +++ b/src/security/builtin_plugins/tests/set_remote_datawriter_crypto_tokens/src/set_remote_datawriter_crypto_tokens_utests.c @@ -141,6 +141,7 @@ static int register_local_datareader(void) memset(&datareader_properties, 0, sizeof(datareader_properties)); memset(&datareader_security_attributes, 0, sizeof(datareader_security_attributes)); datareader_security_attributes.is_discovery_protected = true; + datareader_security_attributes.is_submessage_protected = true; local_reader_crypto = crypto->crypto_key_factory->register_local_datareader( diff --git a/src/security/core/CMakeLists.txt b/src/security/core/CMakeLists.txt index 8719946..41ea708 100644 --- a/src/security/core/CMakeLists.txt +++ b/src/security/core/CMakeLists.txt @@ -53,7 +53,8 @@ target_include_directories(security_core if(BUILD_TESTING) add_subdirectory(tests) - add_subdirectory(tests/plugin_loading) +# Temporarily disabled because needs refractoring w.r.t. security implementation +# add_subdirectory(tests/plugin_loading) endif() install( diff --git a/src/security/core/include/dds/security/core/dds_security_utils.h b/src/security/core/include/dds/security/core/dds_security_utils.h index a66c4d3..d6a745e 100644 --- a/src/security/core/include/dds/security/core/dds_security_utils.h +++ b/src/security/core/include/dds/security/core/dds_security_utils.h @@ -26,8 +26,8 @@ typedef DDS_Security_long_long DDS_Security_Handle; typedef DDS_Security_LongLongSeq DDS_Security_HandleSeq; #define DDS_SECURITY_SEQUENCE_INIT {0, 0, NULL} -#define DDS_SECURITY_TOKEN_INIT {NULL, DDS_SECURITY_SEQUENCE_INIT, DDS_SECURITY_SEQUENCE_INIT} - +#define DDS_SECURITY_TOKEN_INIT {NULL, DDS_SECURITY_SEQUENCE_INIT, DDS_SECURITY_SEQUENCE_INIT} +#define DDS_SECURITY_EXCEPTION_INIT {NULL, 0, 0} typedef enum { DDS_SECURITY_CONFIG_ITEM_PREFIX_UNKNOWN, diff --git a/src/security/core/src/dds_security_fsm.c b/src/security/core/src/dds_security_fsm.c index ce1a2bb..8685ed0 100644 --- a/src/security/core/src/dds_security_fsm.c +++ b/src/security/core/src/dds_security_fsm.c @@ -49,7 +49,8 @@ struct dds_security_fsm { struct dds_security_fsm *next_fsm; struct dds_security_fsm *prev_fsm; - bool active; + bool busy; + bool deleting; struct dds_security_fsm_control *control; const dds_security_fsm_transition *transitions; uint32_t size; @@ -69,8 +70,10 @@ struct dds_security_fsm_control struct ddsi_domaingv *gv; struct dds_security_fsm *first_fsm; struct dds_security_fsm *last_fsm; - struct fsm_event *event_queue; + struct fsm_event *first_event; + struct fsm_event *last_event; ddsrt_fibheap_t timers; + ddsrt_thread_t tid; bool running; }; @@ -86,6 +89,68 @@ static int compare_timer_event (const void *va, const void *vb) return (a->endtime == b->endtime) ? 0 : (a->endtime < b->endtime) ? -1 : 1; } +static void append_event(struct dds_security_fsm_control *control, struct fsm_event *event) +{ + event->next = NULL; + event->prev = control->last_event; + if (control->last_event) + control->last_event->next = event; + else + control->first_event = event; + control->last_event = event; +} + +static void insert_event(struct dds_security_fsm_control *control, struct fsm_event *event) +{ + event->prev = NULL; + event->next = control->first_event; + if (control->first_event) + control->first_event->prev = event; + else + control->last_event = event; + control->first_event = event; +} + +static struct fsm_event *get_event(struct dds_security_fsm_control *control) +{ + struct fsm_event *event = control->first_event; + + if (event) + { + control->first_event = event->next; + if (event->next) + event->next->prev = NULL; + else + control->last_event = NULL; + event->next = NULL; + event->prev = NULL; + } + return event; +} + +static void remove_events(struct dds_security_fsm_control *control, struct dds_security_fsm *fsm) +{ + struct fsm_event *event = control->first_event; + + while (event) + { + struct fsm_event *next = event->next; + if (event->fsm == fsm) + { + if (event->prev) + event->prev->next = event->next; + else + control->first_event = event->next; + if (event->next) + event->next->prev = event->prev; + else + control->last_event = event->prev; + ddsrt_free(event); + } + event = next; + } +} + static void fsm_dispatch (struct dds_security_fsm *fsm, int event_id, bool lifo) { struct dds_security_fsm_control *control = fsm->control; @@ -103,26 +168,10 @@ static void fsm_dispatch (struct dds_security_fsm *fsm, int event_id, bool lifo) event->next = NULL; event->prev = NULL; - if (lifo) { - /* Insert event at the top of the event list */ - if (control->event_queue) { - control->event_queue->prev = event; - } - event->next = control->event_queue; - control->event_queue = event; - } else { - /* Insert FIFO event */ - if (control->event_queue) { - struct fsm_event *last = control->event_queue; - while (last->next != NULL ) { - last = last->next; - } - last->next = event; - event->prev = last; - } else { - control->event_queue = event; - } - } + if (lifo) + insert_event(control, event); + else + append_event(control, event); } static void set_state_timer (struct dds_security_fsm *fsm) @@ -142,16 +191,18 @@ static void clear_state_timer (struct dds_security_fsm *fsm) { struct dds_security_fsm_control *control = fsm->control; - if (fsm->current && fsm->state_timeout_event.endtime != DDS_NEVER) + if (fsm->state_timeout_event.endtime != DDS_NEVER) ddsrt_fibheap_delete (&timer_events_fhdef, &control->timers, &fsm->state_timeout_event); + fsm->state_timeout_event.endtime = DDS_NEVER; } static void clear_overall_timer (struct dds_security_fsm *fsm) { struct dds_security_fsm_control *control = fsm->control; - if (fsm->current && fsm->overall_timeout_event.endtime != DDS_NEVER) + if (fsm->overall_timeout_event.endtime != DDS_NEVER) ddsrt_fibheap_delete (&timer_events_fhdef, &control->timers, &fsm->overall_timeout_event); + fsm->overall_timeout_event.endtime = DDS_NEVER; } static dds_time_t first_timeout (struct dds_security_fsm_control *control) @@ -185,57 +236,57 @@ static void fsm_state_change (struct thread_state1 *ts1, struct dds_security_fsm int event_id = event->event_id; uint32_t i; - if (fsm->active) + if (fsm->debug_func) + fsm->debug_func (fsm, DDS_SECURITY_FSM_DEBUG_ACT_HANDLING, fsm->current, event_id, fsm->arg); + + for (i = 0; i < fsm->size; i++) { - if (fsm->debug_func) - fsm->debug_func (fsm, DDS_SECURITY_FSM_DEBUG_ACT_HANDLING, fsm->current, event_id, fsm->arg); - - for (i = 0; i < fsm->size; i++) + if ((fsm->transitions[i].begin == fsm->current) && (fsm->transitions[i].event_id == event_id)) { - if ((fsm->transitions[i].begin == fsm->current) && (fsm->transitions[i].event_id == event_id)) - { - clear_state_timer (fsm); - fsm->current = fsm->transitions[i].end; - set_state_timer (fsm); + clear_state_timer (fsm); + fsm->current = fsm->transitions[i].end; + set_state_timer (fsm); + fsm->busy = true; - ddsrt_mutex_unlock (&control->lock); + ddsrt_mutex_unlock (&control->lock); - thread_state_asleep (ts1); - if (fsm->transitions[i].func) - fsm->transitions[i].func (fsm, fsm->arg); - if (fsm->current && fsm->current->func) - fsm->current->func (fsm, fsm->arg); + thread_state_awake (ts1, control->gv); + if (fsm->transitions[i].func) + fsm->transitions[i].func (fsm, fsm->arg); + if (fsm->current && fsm->current->func) + fsm->current->func (fsm, fsm->arg); - thread_state_awake (ts1, control->gv); - ddsrt_mutex_lock (&control->lock); + thread_state_asleep (ts1); + ddsrt_mutex_lock (&control->lock); + fsm->busy = false; + if (!fsm->deleting) fsm_check_auto_state_change (fsm); - break; - } + else + ddsrt_cond_broadcast(&control->cond); + break; } } - else if (event_id == DDS_SECURITY_FSM_EVENT_DELETE) - fsm_delete (control, fsm); - } static void fsm_handle_timeout (struct dds_security_fsm_control *control, struct fsm_timer_event *timer_event) { struct dds_security_fsm *fsm = timer_event->fsm; - if (fsm->active) + switch (timer_event->kind) { - switch (timer_event->kind) - { - case FSM_TIMEOUT_STATE: - fsm_dispatch (fsm, DDS_SECURITY_FSM_EVENT_TIMEOUT, true); - break; - case FSM_TIMEOUT_OVERALL: - ddsrt_mutex_unlock (&control->lock); - if (fsm->overall_timeout_action) - fsm->overall_timeout_action (fsm, fsm->arg); - ddsrt_mutex_lock (&control->lock); - break; - } + case FSM_TIMEOUT_STATE: + fsm_dispatch (fsm, DDS_SECURITY_FSM_EVENT_TIMEOUT, true); + break; + case FSM_TIMEOUT_OVERALL: + fsm->busy = true; + ddsrt_mutex_unlock (&control->lock); + if (fsm->overall_timeout_action) + fsm->overall_timeout_action (fsm, fsm->arg); + ddsrt_mutex_lock (&control->lock); + fsm->busy = false; + if (fsm->deleting) + ddsrt_cond_broadcast(&control->cond); + break; } /* mark timer event as being processed */ @@ -245,17 +296,16 @@ static void fsm_handle_timeout (struct dds_security_fsm_control *control, struct static uint32_t handle_events (struct dds_security_fsm_control *control) { struct thread_state1 * const ts1 = lookup_thread_state (); + struct fsm_event *event; + + control->tid = ddsrt_thread_self(); + thread_state_awake (ts1, control->gv); ddsrt_mutex_lock (&control->lock); while (control->running) { - if (control->event_queue) + if ((event = get_event(control)) != NULL) { - struct fsm_event *event = control->event_queue; - - control->event_queue = event->next; - if (control->event_queue) - control->event_queue->prev = NULL; fsm_state_change (ts1, control, event); ddsrt_free (event); } @@ -288,7 +338,7 @@ void dds_security_fsm_set_timeout (struct dds_security_fsm *fsm, dds_security_fs assert(timeout > 0); ddsrt_mutex_lock (&fsm->control->lock); - if (fsm->active) + if (!fsm->deleting) { if (timeout != DDS_NEVER) { @@ -297,7 +347,7 @@ void dds_security_fsm_set_timeout (struct dds_security_fsm *fsm, dds_security_fs fsm->overall_timeout_event.endtime = ddsrt_time_add_duration(dds_time(), timeout); ddsrt_fibheap_insert (&timer_events_fhdef, &fsm->control->timers, &fsm->overall_timeout_event); if (fsm->overall_timeout_event.endtime < first_timeout(fsm->control)) - ddsrt_cond_signal (&fsm->control->cond); + ddsrt_cond_broadcast (&fsm->control->cond); } else clear_overall_timer (fsm); @@ -311,10 +361,10 @@ void dds_security_fsm_dispatch (struct dds_security_fsm *fsm, int32_t event_id, assert(fsm->control); ddsrt_mutex_lock (&fsm->control->lock); - if (fsm->active) + if (!fsm->deleting) { fsm_dispatch (fsm, event_id, prio); - ddsrt_cond_signal (&fsm->control->cond); + ddsrt_cond_broadcast (&fsm->control->cond); } ddsrt_mutex_unlock (&fsm->control->lock); } @@ -324,7 +374,6 @@ const dds_security_fsm_state * dds_security_fsm_current_state (struct dds_securi const dds_security_fsm_state *state; assert(fsm); - assert(fsm->active); ddsrt_mutex_lock (&fsm->control->lock); state = fsm->current; @@ -407,7 +456,8 @@ struct dds_security_fsm * dds_security_fsm_create (struct dds_security_fsm_contr fsm->overall_timeout_event.kind = FSM_TIMEOUT_OVERALL; fsm->overall_timeout_event.endtime = DDS_NEVER; fsm->overall_timeout_event.fsm = fsm; - fsm->active = true; + fsm->busy = false; + fsm->deleting = false; fsm->next_fsm = NULL; fsm->prev_fsm = NULL; fsm->control = control; @@ -425,16 +475,17 @@ dds_security_fsm_start (struct dds_security_fsm *fsm) dds_security_fsm_dispatch(fsm, DDS_SECURITY_FSM_EVENT_AUTO, false); } -static void fsm_deactivate (struct dds_security_fsm *fsm, bool gen_del_event) +static void fsm_deactivate (struct dds_security_fsm_control *control, struct dds_security_fsm *fsm) { - if (fsm->active) + fsm->deleting = true; + remove_events(control, fsm); + clear_state_timer (fsm); + clear_overall_timer (fsm); + fsm->current = NULL; + if (!ddsrt_thread_equal(control->tid, ddsrt_thread_self())) { - fsm->active = false; - clear_state_timer (fsm); - clear_overall_timer (fsm); - fsm->current = NULL; - if (gen_del_event) - fsm_dispatch (fsm, DDS_SECURITY_FSM_EVENT_DELETE, false); + while (fsm->busy) + ddsrt_cond_wait(&control->cond, &control->lock); } } @@ -447,14 +498,14 @@ void dds_security_fsm_free (struct dds_security_fsm *fsm) control = fsm->control; ddsrt_mutex_lock (&control->lock); - fsm_deactivate (fsm, true); + fsm_deactivate (control, fsm); ddsrt_mutex_unlock (&control->lock); } static void fsm_delete (struct dds_security_fsm_control *control, struct dds_security_fsm *fsm) { - fsm_deactivate (fsm, false); remove_fsm_from_list (control, fsm); + fsm_deactivate (control, fsm); ddsrt_free(fsm); } @@ -464,7 +515,8 @@ struct dds_security_fsm_control * dds_security_fsm_control_create (struct ddsi_d control = ddsrt_malloc (sizeof(*control)); control->running = false; - control->event_queue = NULL; + control->first_event = NULL; + control->last_event = NULL; control->first_fsm = NULL; control->last_fsm = NULL; control->gv = gv; @@ -486,12 +538,11 @@ void dds_security_fsm_control_free (struct dds_security_fsm_control *control) while ((fsm = control->first_fsm) != NULL) { control->first_fsm = fsm->next_fsm; - fsm_deactivate (fsm, false); - ddsrt_free (fsm); + fsm_delete (control, fsm); } - while ((event = control->event_queue) != NULL) + while ((event = control->first_event) != NULL) { - control->event_queue = event->next; + control->first_event = event->next; ddsrt_free (event); } @@ -520,7 +571,7 @@ void dds_security_fsm_control_stop (struct dds_security_fsm_control *control) ddsrt_mutex_lock (&control->lock); control->running = false; - ddsrt_cond_signal (&control->cond); + ddsrt_cond_broadcast (&control->cond); ddsrt_mutex_unlock (&control->lock); join_thread (control->ts); diff --git a/src/security/core/src/dds_security_utils.c b/src/security/core/src/dds_security_utils.c index 42610af..ea5a7d8 100644 --- a/src/security/core/src/dds_security_utils.c +++ b/src/security/core/src/dds_security_utils.c @@ -124,6 +124,7 @@ DDS_Security_BinaryProperty_set_by_value( bp->name = ddsrt_strdup(name); bp->value._length = length; bp->value._maximum = length; + bp->propagate = true; if (length) { bp->value._buffer = ddsrt_malloc(length); memcpy(bp->value._buffer, data, length); @@ -164,6 +165,7 @@ DDS_Security_BinaryProperty_set_by_ref( bp->value._length = length; bp->value._maximum = length; bp->value._buffer = data; + bp->propagate = true; } DDS_Security_BinaryPropertySeq * @@ -840,7 +842,7 @@ DDS_Security_Exception_set_with_openssl_error( void DDS_Security_Exception_reset( - DDS_Security_SecurityException *ex) + DDS_Security_SecurityException *ex) { if (ex) { if (ex->message) { @@ -855,7 +857,9 @@ DDS_Security_Exception_clean( DDS_Security_SecurityException *ex) { if (ex) { - memset(ex, 0, sizeof(DDS_Security_SecurityException)); + ex->code = 0; + ex->minor_code = 0; + ex->message = NULL; } } diff --git a/src/security/core/tests/plugin_loading/plugin_loading.c b/src/security/core/tests/plugin_loading/plugin_loading.c index b3d145d..09c6c0b 100644 --- a/src/security/core/tests/plugin_loading/plugin_loading.c +++ b/src/security/core/tests/plugin_loading/plugin_loading.c @@ -20,6 +20,7 @@ #include "dds/ddsrt/cdtors.h" #include "dds/ddsrt/environ.h" #include "dds/ddsrt/heap.h" +#include "plugin_mock_common.h" //#include "dds/ddsi/ddsi_security_omg.h" #define FORCE_ENV @@ -87,7 +88,7 @@ static uint32_t found; static void logger(void *ptr, const dds_log_data_t *data) { char **expected = (char **) ptr; if (print_log) { - printf("%s\n", data->message); + fputs(data->message, stdout); } for (uint32_t i = 0; expected[i] != NULL; i++) { if (patmatch(expected[i], data->message)) { @@ -112,9 +113,9 @@ CU_Test(ddssec_security_plugin_loading, all_ok, .init = ddsrt_init, .fini = ddsr "" "" "" - "testtext_IdentityCertificate_testtext" - "testtext_IdentityCA_testtext" - "testtext_PrivateKey_testtext" + ""TEST_IDENTITY_CERTIFICATE_ALL_OK"" + ""TEST_CA_CERTIFICATE_ALL_OK"" + ""TEST_PRIVATE_KEY_ALL_OK"" "testtext_Password_testtext" "testtext_Dir_testtext" "" @@ -469,7 +470,7 @@ CU_Test(ddssec_security_plugin_loading, no_library_in_path, .init = ddsrt_init, #else dds_delete(participant); #endif - + CU_ASSERT_FATAL(found == 0xd || found == 0xe); dds_delete(participant); @@ -551,13 +552,13 @@ CU_Test(ddssec_security_plugin_loading, all_ok_with_props, .init = ddsrt_init, . dds_entity_t participant; dds_qos_t * qos; - - + + /* Set up the trace sinks to detect the config parsing. */ dds_set_log_mask(DDS_LC_INFO); dds_set_log_sink(&logger, (void*)log_expected); dds_set_trace_sink(&logger, (void*)log_expected); - + /* Create the qos */ unsigned char bvalue[3] = { 0x01, 0x02, 0x03 }; CU_ASSERT_FATAL ((qos = dds_create_qos()) != NULL); diff --git a/src/security/core/tests/plugin_loading/plugin_mock/authentication_all_ok/mock_authentication.c b/src/security/core/tests/plugin_loading/plugin_mock/authentication_all_ok/mock_authentication.c index cfe680a..03f9666 100644 --- a/src/security/core/tests/plugin_loading/plugin_mock/authentication_all_ok/mock_authentication.c +++ b/src/security/core/tests/plugin_loading/plugin_mock/authentication_all_ok/mock_authentication.c @@ -28,6 +28,11 @@ typedef struct dds_security_authentication_impl { int id; //sample internal member } dds_security_authentication_impl; + +static const char *test_identity_certificate = TEST_IDENTITY_CERTIFICATE_ALL_OK; +static const char *test_ca_certificate = TEST_CA_CERTIFICATE_ALL_OK; +static const char *test_private_key = TEST_PRIVATE_KEY_ALL_OK; + DDS_Security_ValidationResult_t validate_local_identity( dds_security_authentication *instance, DDS_Security_IdentityHandle *local_identity_handle, @@ -76,14 +81,17 @@ DDS_Security_ValidationResult_t validate_local_identity( } if( strcmp(identity_certificate, test_identity_certificate) != 0){ - + printf("identity received=%s\n", identity_certificate); + printf("identity expected=%s\n", test_identity_certificate); result = DDS_SECURITY_VALIDATION_FAILED; printf("FAILED: Could not get identity_certificate value properly\n"); } else if( strcmp(identity_ca, test_ca_certificate) != 0){ + printf("ca received=%s\n", identity_ca); + printf("ca expected=%s\n", test_ca_certificate); printf("FAILED: Could not get identity_ca value properly\n"); result = DDS_SECURITY_VALIDATION_FAILED; - }else if( strcmp(private_key, test_privatekey) != 0){ + }else if( strcmp(private_key, test_private_key) != 0){ printf("FAILED: Could not get private_key value properly\n"); result = DDS_SECURITY_VALIDATION_FAILED; } diff --git a/src/security/core/tests/plugin_loading/plugin_mock/authentication_all_ok/mock_authentication.h b/src/security/core/tests/plugin_loading/plugin_mock/authentication_all_ok/mock_authentication.h index 56d297c..bb4479f 100644 --- a/src/security/core/tests/plugin_loading/plugin_mock/authentication_all_ok/mock_authentication.h +++ b/src/security/core/tests/plugin_loading/plugin_mock/authentication_all_ok/mock_authentication.h @@ -9,6 +9,7 @@ #define SECURITY_BUILTIN_PLUGINS_AUTHENTICATION_H_ #include "dds/security/authentication_all_ok_export.h" +#include "../../plugin_mock_common.h" SECURITY_EXPORT int32_t init_authentication(const char *argument, void **context); @@ -16,83 +17,6 @@ init_authentication(const char *argument, void **context); SECURITY_EXPORT int32_t finalize_authentication(void *context); -char *test_identity_certificate="data:,-----BEGIN CERTIFICATE-----\n\ -MIIDYDCCAkigAwIBAgIBBDANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL\n\ -MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50\n\ -aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu\n\ -Y29tMB4XDTE4MDMxMjAwMDAwMFoXDTI3MDMxMTIzNTk1OVowdTELMAkGA1UEBhMC\n\ -TkwxCzAJBgNVBAgTAk9WMRAwDgYDVQQKEwdBRExpbmsgMREwDwYDVQQLEwhJU1Qg\n\ -VGVzdDETMBEGA1UEAxMKQWxpY2UgVGVzdDEfMB0GCSqGSIb3DQEJARYQYWxpY2VA\n\ -YWRsaW5rLmlzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANBW+tEZ\n\ -Baw7EQCEXyzH9n7IkZ8PQIKe8hG1LAOGYOF/oUYQZJO/HxbWoC4rFqOC20+A6is6\n\ -kFwr1Zzp/Wurk9CrFXo5Nomi6ActH6LUM57nYqN68w6U38z/XkQxVY/ESZ5dySfD\n\ -9Q1C8R+zdE8gwbimdYmwX7ioz336nghM2CoAHPDRthQeJupl8x4V7isOltr9CGx8\n\ -+imJXbGr39OK6u87cNLeu23sUkOIC0lSRMIqIQK3oJtHS70J2qecXdqp9MhE7Xky\n\ -/GPlI8ptQ1gJ8A3cAOvtI9mtMJMszs2EKWTLfeTcmfJHKKhKjvCgDdh3Jan4x5YP\n\ -Yg7HG6H+ceOUkMMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAkvuqZzyJ3Nu4/Eo5\n\ -kD0nVgYGBUl7cspu+636q39zPSrxLEDMUWz+u8oXLpyGcgiZ8lZulPTV8dmOn+3C\n\ -Vg55c5C+gbnbX3MDyb3wB17296RmxYf6YNul4sFOmj6+g2i+Dw9WH0PBCVKbA84F\n\ -jR3Gx2Pfoifor3DvT0YFSsjNIRt090u4dQglbIb6cWEafC7O24t5jFhGPvJ7L9SE\n\ -gB0Drh/HmKTVuaqaRkoOKkKaKuWoXsszK1ZFda1DHommnR5LpYPsDRQ2fVM4EuBF\n\ -By03727uneuG8HLuNcLEV9H0i7LxtyfFkyCPUQvWG5jehb7xPOz/Ml26NAwwjlTJ\n\ -xEEFrw==\n\ ------END CERTIFICATE-----"; - -char *test_ca_certificate="data:,-----BEGIN CERTIFICATE-----\n\ -MIIEKTCCAxGgAwIBAgIBATANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL\n\ -MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50\n\ -aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu\n\ -Y29tMB4XDTE4MDMxMjAwMDAwMFoXDTI3MDMxMTIzNTk1OVowcjELMAkGA1UEBhMC\n\ -TkwxCzAJBgNVBAgTAk9WMRMwEQYDVQQKEwpBRExpbmsgSVNUMRkwFwYDVQQDExBJ\n\ -ZGVudGl0eSBDQSBUZXN0MSYwJAYJKoZIhvcNAQkBFhdpbmZvQGlzdC5hZGxpbmt0\n\ -ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANa/ENFfGVXg\n\ -bPLTzBdDfiZQcp5dWZ//Pb8ErFOJu8uosVHFv8t69dgjHgNHB4OsjmjnR7GfKUZT\n\ -0cMvWJnjsC7DDlBwFET9rj4k40n96bbVCH9I7+tNhsoqzc6Eu+5h4sk7VfNGTM2Z\n\ -SyCd4GiSZRuA44rRbhXI7/LDpr4hY5J9ZDo5AM9ZyoLAoh774H3CZWD67S35XvUs\n\ -72dzE6uKG/vxBbvZ7eW2GLO6ewa9UxlnLVMPfJdpkp/xYXwwcPW2+2YXCge1ujxs\n\ -tjrOQJ5HUySh6DkE/kZpx8zwYWm9AaCrsvCIX1thsqgvKy+U5v1FS1L58eGc6s//\n\ -9yMgNhU29R0CAwEAAaOByTCBxjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRNVUJN\n\ -FzhJPReYT4QSx6dK53CXCTAfBgNVHSMEGDAWgBRNVUJNFzhJPReYT4QSx6dK53CX\n\ -CTAPBgNVHQ8BAf8EBQMDB/+AMGUGA1UdJQEB/wRbMFkGCCsGAQUFBwMBBggrBgEF\n\ -BQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkGCCsG\n\ -AQUFBwMNBggrBgEFBQcDDgYHKwYBBQIDBTANBgkqhkiG9w0BAQsFAAOCAQEAcOLF\n\ -ZYdJguj0uxeXB8v3xnUr1AWz9+gwg0URdfNLU2KvF2lsb/uznv6168b3/FcPgezN\n\ -Ihl9GqB+RvGwgXS/1UelCGbQiIUdsNxk246P4uOGPIyW32RoJcYPWZcpY+cw11tQ\n\ -NOnk994Y5/8ad1DmcxVLLqq5kwpXGWQufV1zOONq8B+mCvcVAmM4vkyF/de56Lwa\n\ -sAMpk1p77uhaDnuq2lIR4q3QHX2wGctFid5Q375DRscFQteY01r/dtwBBrMn0wuL\n\ -AMNx9ZGD+zAoOUaslpIlEQ+keAxk3jgGMWFMxF81YfhEnXzevSQXWpyek86XUyFL\n\ -O9IAQi5pa15gXjSbUg==\n\ ------END CERTIFICATE-----"; - -char *test_privatekey = "data:,-----BEGIN RSA PRIVATE KEY-----\n\ -MIIEowIBAAKCAQEA0Fb60RkFrDsRAIRfLMf2fsiRnw9Agp7yEbUsA4Zg4X+hRhBk\n\ -k78fFtagLisWo4LbT4DqKzqQXCvVnOn9a6uT0KsVejk2iaLoBy0fotQznudio3rz\n\ -DpTfzP9eRDFVj8RJnl3JJ8P1DULxH7N0TyDBuKZ1ibBfuKjPffqeCEzYKgAc8NG2\n\ -FB4m6mXzHhXuKw6W2v0IbHz6KYldsavf04rq7ztw0t67bexSQ4gLSVJEwiohAreg\n\ -m0dLvQnap5xd2qn0yETteTL8Y+Ujym1DWAnwDdwA6+0j2a0wkyzOzYQpZMt95NyZ\n\ -8kcoqEqO8KAN2HclqfjHlg9iDscbof5x45SQwwIDAQABAoIBAG0dYPeqd0IhHWJ7\n\ -8azufbchLMN1pX/D51xG2uptssfnpHuhkkufSZUYi4QipRS2ME6PYhWJ8pmTi6lH\n\ -E6cUkbI0KGd/F4U2gPdhNrR9Fxwea5bbifkVF7Gx/ZkRjZJiZ3w9+mCNTQbJDKhh\n\ -wITAzzT6WYznhvqbzzBX1fTa6kv0GAQtX7aHKM+XIwkhX2gzU5TU80bvH8aMrT05\n\ -tAMGQqkUeRnpo0yucBl4VmTZzd/+X/d2UyXR0my15jE5iH5o+p+E6qTRE9D+MGUd\n\ -MQ6Ftj0Untqy1lcog1ZLL6zPlnwcD4jgY5VCYDgvabnrSwymOJapPLsAEdWdq+U5\n\ -ec44BMECgYEA/+3qPUrd4XxA517qO3fCGBvf2Gkr7w5ZDeATOTHGuD8QZeK0nxPl\n\ -CWhRjdgkqo0fyf1cjczL5XgYayo+YxkO1Z4RUU+8lJAHlVx9izOQo+MTQfkwH4BK\n\ -LYlHxMoHJwAOXXoE+dmBaDh5xT0mDUGU750r763L6EFovE4qRBn9hxkCgYEA0GWz\n\ -rpOPNxb419WxG9npoQYdCZ5IbmEOGDH3ReggVzWHmW8sqtkqTZm5srcyDpqAc1Gu\n\ -paUveMblEBbU+NFJjLWOfwB5PCp8jsrqRgCQSxolShiVkc3Vu3oyzMus9PDge1eo\n\ -9mwVGO7ojQKWRu/WVAakENPaAjeyyhv4dqSNnjsCgYEAlwe8yszqoY1k8+U0T0G+\n\ -HeIdOCXgkmOiNCj+zyrLvaEhuS6PLq1b5TBVqGJcSPWdQ+MrglbQIKu9pUg5ptt7\n\ -wJ5WU+i9PeK9Ruxc/g/BFKYFkFJQjtZzb+nqm3wpul8zGwDN/O/ZiTqCyd3rHbmM\n\ -/dZ/viKPCZHIEBAEq0m3LskCgYBndzcAo+5k8ZjWwBfQth5SfhCIp/daJgGzbYtR\n\ -P/BenAsY2KOap3tjT8Fsw5usuHSxzIojX6H0Gvu7Qzq11mLn43Q+BeQrRQTWeFRc\n\ -MQdy4iZFZXNNEp7dF8yE9VKHwdgSJPGUdxD6chMvf2tRCN6mlS171VLV6wVvZvez\n\ -H/vX5QKBgD2Dq/NHpjCpAsECP9awmNF5Akn5WJbRGmegwXIih2mOtgtYYDeuQyxY\n\ -ZCrdJFfIUjUVPagshEmUklKhkYMYpzy2PQDVtaVcm6UNFroxT5h+J+KDs1LN1H8G\n\ -LsASrzyAg8EpRulwXEfLrWKiu9DKv8bMEgO4Ovgz8zTKJZIFhcac\n\ ------END RSA PRIVATE KEY-----"; - - DDS_Security_ValidationResult_t validate_local_identity( dds_security_authentication *instance, diff --git a/src/security/core/tests/plugin_loading/plugin_mock_common.h b/src/security/core/tests/plugin_loading/plugin_mock_common.h new file mode 100644 index 0000000..3fe2768 --- /dev/null +++ b/src/security/core/tests/plugin_loading/plugin_mock_common.h @@ -0,0 +1,98 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef PLUGIN_MOCK_COMMON_H_ +#define PLUGIN_MOCK_COMMON_H_ + +#define TEST_IDENTITY_CERTIFICATE_ALL_OK "testtext_IdentityCertificate_testtext" +#define TEST_CA_CERTIFICATE_ALL_OK "testtext_IdentityCA_testtext" +#define TEST_PRIVATE_KEY_ALL_OK "testtext_PrivateKey_testtext" + +#define TEST_IDENTITY_CERTIFICATE "data:,-----BEGIN CERTIFICATE-----\n\ +MIIDYDCCAkigAwIBAgIBBDANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL\n\ +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50\n\ +aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu\n\ +Y29tMB4XDTE4MDMxMjAwMDAwMFoXDTI3MDMxMTIzNTk1OVowdTELMAkGA1UEBhMC\n\ +TkwxCzAJBgNVBAgTAk9WMRAwDgYDVQQKEwdBRExpbmsgMREwDwYDVQQLEwhJU1Qg\n\ +VGVzdDETMBEGA1UEAxMKQWxpY2UgVGVzdDEfMB0GCSqGSIb3DQEJARYQYWxpY2VA\n\ +YWRsaW5rLmlzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANBW+tEZ\n\ +Baw7EQCEXyzH9n7IkZ8PQIKe8hG1LAOGYOF/oUYQZJO/HxbWoC4rFqOC20+A6is6\n\ +kFwr1Zzp/Wurk9CrFXo5Nomi6ActH6LUM57nYqN68w6U38z/XkQxVY/ESZ5dySfD\n\ +9Q1C8R+zdE8gwbimdYmwX7ioz336nghM2CoAHPDRthQeJupl8x4V7isOltr9CGx8\n\ ++imJXbGr39OK6u87cNLeu23sUkOIC0lSRMIqIQK3oJtHS70J2qecXdqp9MhE7Xky\n\ +/GPlI8ptQ1gJ8A3cAOvtI9mtMJMszs2EKWTLfeTcmfJHKKhKjvCgDdh3Jan4x5YP\n\ +Yg7HG6H+ceOUkMMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAkvuqZzyJ3Nu4/Eo5\n\ +kD0nVgYGBUl7cspu+636q39zPSrxLEDMUWz+u8oXLpyGcgiZ8lZulPTV8dmOn+3C\n\ +Vg55c5C+gbnbX3MDyb3wB17296RmxYf6YNul4sFOmj6+g2i+Dw9WH0PBCVKbA84F\n\ +jR3Gx2Pfoifor3DvT0YFSsjNIRt090u4dQglbIb6cWEafC7O24t5jFhGPvJ7L9SE\n\ +gB0Drh/HmKTVuaqaRkoOKkKaKuWoXsszK1ZFda1DHommnR5LpYPsDRQ2fVM4EuBF\n\ +By03727uneuG8HLuNcLEV9H0i7LxtyfFkyCPUQvWG5jehb7xPOz/Ml26NAwwjlTJ\n\ +xEEFrw==\n\ +-----END CERTIFICATE-----" + +#define TEST_CA_CERTIFICATE_ALL "data:,-----BEGIN CERTIFICATE-----\n\ +MIIEKTCCAxGgAwIBAgIBATANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL\n\ +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50\n\ +aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu\n\ +Y29tMB4XDTE4MDMxMjAwMDAwMFoXDTI3MDMxMTIzNTk1OVowcjELMAkGA1UEBhMC\n\ +TkwxCzAJBgNVBAgTAk9WMRMwEQYDVQQKEwpBRExpbmsgSVNUMRkwFwYDVQQDExBJ\n\ +ZGVudGl0eSBDQSBUZXN0MSYwJAYJKoZIhvcNAQkBFhdpbmZvQGlzdC5hZGxpbmt0\n\ +ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANa/ENFfGVXg\n\ +bPLTzBdDfiZQcp5dWZ//Pb8ErFOJu8uosVHFv8t69dgjHgNHB4OsjmjnR7GfKUZT\n\ +0cMvWJnjsC7DDlBwFET9rj4k40n96bbVCH9I7+tNhsoqzc6Eu+5h4sk7VfNGTM2Z\n\ +SyCd4GiSZRuA44rRbhXI7/LDpr4hY5J9ZDo5AM9ZyoLAoh774H3CZWD67S35XvUs\n\ +72dzE6uKG/vxBbvZ7eW2GLO6ewa9UxlnLVMPfJdpkp/xYXwwcPW2+2YXCge1ujxs\n\ +tjrOQJ5HUySh6DkE/kZpx8zwYWm9AaCrsvCIX1thsqgvKy+U5v1FS1L58eGc6s//\n\ +9yMgNhU29R0CAwEAAaOByTCBxjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRNVUJN\n\ +FzhJPReYT4QSx6dK53CXCTAfBgNVHSMEGDAWgBRNVUJNFzhJPReYT4QSx6dK53CX\n\ +CTAPBgNVHQ8BAf8EBQMDB/+AMGUGA1UdJQEB/wRbMFkGCCsGAQUFBwMBBggrBgEF\n\ +BQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkGCCsG\n\ +AQUFBwMNBggrBgEFBQcDDgYHKwYBBQIDBTANBgkqhkiG9w0BAQsFAAOCAQEAcOLF\n\ +ZYdJguj0uxeXB8v3xnUr1AWz9+gwg0URdfNLU2KvF2lsb/uznv6168b3/FcPgezN\n\ +Ihl9GqB+RvGwgXS/1UelCGbQiIUdsNxk246P4uOGPIyW32RoJcYPWZcpY+cw11tQ\n\ +NOnk994Y5/8ad1DmcxVLLqq5kwpXGWQufV1zOONq8B+mCvcVAmM4vkyF/de56Lwa\n\ +sAMpk1p77uhaDnuq2lIR4q3QHX2wGctFid5Q375DRscFQteY01r/dtwBBrMn0wuL\n\ +AMNx9ZGD+zAoOUaslpIlEQ+keAxk3jgGMWFMxF81YfhEnXzevSQXWpyek86XUyFL\n\ +O9IAQi5pa15gXjSbUg==\n\ +-----END CERTIFICATE-----" + +#define TEST_PRIVATE_KEY_ALL "data:,-----BEGIN RSA PRIVATE KEY-----\n\ +MIIEowIBAAKCAQEA0Fb60RkFrDsRAIRfLMf2fsiRnw9Agp7yEbUsA4Zg4X+hRhBk\n\ +k78fFtagLisWo4LbT4DqKzqQXCvVnOn9a6uT0KsVejk2iaLoBy0fotQznudio3rz\n\ +DpTfzP9eRDFVj8RJnl3JJ8P1DULxH7N0TyDBuKZ1ibBfuKjPffqeCEzYKgAc8NG2\n\ +FB4m6mXzHhXuKw6W2v0IbHz6KYldsavf04rq7ztw0t67bexSQ4gLSVJEwiohAreg\n\ +m0dLvQnap5xd2qn0yETteTL8Y+Ujym1DWAnwDdwA6+0j2a0wkyzOzYQpZMt95NyZ\n\ +8kcoqEqO8KAN2HclqfjHlg9iDscbof5x45SQwwIDAQABAoIBAG0dYPeqd0IhHWJ7\n\ +8azufbchLMN1pX/D51xG2uptssfnpHuhkkufSZUYi4QipRS2ME6PYhWJ8pmTi6lH\n\ +E6cUkbI0KGd/F4U2gPdhNrR9Fxwea5bbifkVF7Gx/ZkRjZJiZ3w9+mCNTQbJDKhh\n\ +wITAzzT6WYznhvqbzzBX1fTa6kv0GAQtX7aHKM+XIwkhX2gzU5TU80bvH8aMrT05\n\ +tAMGQqkUeRnpo0yucBl4VmTZzd/+X/d2UyXR0my15jE5iH5o+p+E6qTRE9D+MGUd\n\ +MQ6Ftj0Untqy1lcog1ZLL6zPlnwcD4jgY5VCYDgvabnrSwymOJapPLsAEdWdq+U5\n\ +ec44BMECgYEA/+3qPUrd4XxA517qO3fCGBvf2Gkr7w5ZDeATOTHGuD8QZeK0nxPl\n\ +CWhRjdgkqo0fyf1cjczL5XgYayo+YxkO1Z4RUU+8lJAHlVx9izOQo+MTQfkwH4BK\n\ +LYlHxMoHJwAOXXoE+dmBaDh5xT0mDUGU750r763L6EFovE4qRBn9hxkCgYEA0GWz\n\ +rpOPNxb419WxG9npoQYdCZ5IbmEOGDH3ReggVzWHmW8sqtkqTZm5srcyDpqAc1Gu\n\ +paUveMblEBbU+NFJjLWOfwB5PCp8jsrqRgCQSxolShiVkc3Vu3oyzMus9PDge1eo\n\ +9mwVGO7ojQKWRu/WVAakENPaAjeyyhv4dqSNnjsCgYEAlwe8yszqoY1k8+U0T0G+\n\ +HeIdOCXgkmOiNCj+zyrLvaEhuS6PLq1b5TBVqGJcSPWdQ+MrglbQIKu9pUg5ptt7\n\ +wJ5WU+i9PeK9Ruxc/g/BFKYFkFJQjtZzb+nqm3wpul8zGwDN/O/ZiTqCyd3rHbmM\n\ +/dZ/viKPCZHIEBAEq0m3LskCgYBndzcAo+5k8ZjWwBfQth5SfhCIp/daJgGzbYtR\n\ +P/BenAsY2KOap3tjT8Fsw5usuHSxzIojX6H0Gvu7Qzq11mLn43Q+BeQrRQTWeFRc\n\ +MQdy4iZFZXNNEp7dF8yE9VKHwdgSJPGUdxD6chMvf2tRCN6mlS171VLV6wVvZvez\n\ +H/vX5QKBgD2Dq/NHpjCpAsECP9awmNF5Akn5WJbRGmegwXIih2mOtgtYYDeuQyxY\n\ +ZCrdJFfIUjUVPagshEmUklKhkYMYpzy2PQDVtaVcm6UNFroxT5h+J+KDs1LN1H8G\n\ +LsASrzyAg8EpRulwXEfLrWKiu9DKv8bMEgO4Ovgz8zTKJZIFhcac\n\ +-----END RSA PRIVATE KEY-----" + + + +#endif diff --git a/src/security/core/tests/plugin_loading/security_config.c b/src/security/core/tests/plugin_loading/security_config.c index 3c91f60..dbd0806 100644 --- a/src/security/core/tests/plugin_loading/security_config.c +++ b/src/security/core/tests/plugin_loading/security_config.c @@ -21,6 +21,7 @@ #include "dds/ddsrt/heap.h" #include "dds/ddsi/q_misc.h" #include "dds/ddsi/ddsi_xqos.h" +#include "plugin_mock_common.h" #include "dds/security/dds_security_api_defs.h" @@ -50,9 +51,9 @@ "0:\"dds.sec.access.library.path\":\""ac"\"," \ "0:\"dds.sec.access.library.init\":\"init_access_control\"," \ "0:\"dds.sec.access.library.finalize\":\"finalize_access_control\"," \ - "0:\"dds.sec.auth.identity_ca\":\"testtext_IdentityCA_testtext\"," \ - "0:\"dds.sec.auth.private_key\":\"testtext_PrivateKey_testtext\"," \ - "0:\"dds.sec.auth.identity_certificate\":\"testtext_IdentityCertificate_testtext\"," \ + "0:\"dds.sec.auth.identity_ca\":\"" TEST_CA_CERTIFICATE_ALL_OK "\"," \ + "0:\"dds.sec.auth.private_key\":\"" TEST_PRIVATE_KEY_ALL_OK "\"," \ + "0:\"dds.sec.auth.identity_certificate\":\"" TEST_IDENTITY_CERTIFICATE_ALL_OK "\"," \ "0:\"dds.sec.access.permissions_ca\":\"file:Permissions_CA.pem\"," \ "0:\"dds.sec.access.governance\":\"file:Governance.p7s\"," \ "0:\"dds.sec.access.permissions\":\"file:Permissions.p7s\"" \ @@ -206,9 +207,9 @@ CU_Test(ddsc_security_config, all, .init = ddsrt_init, .fini = ddsrt_fini) "config: Domain/DDSSecurity/Authentication/Library[@path]: "MOCKLIB_PATH("dds_security_authentication_all_ok")"*", "config: Domain/DDSSecurity/Authentication/Library[@initFunction]: init_authentication*", "config: Domain/DDSSecurity/Authentication/Library[@finalizeFunction]: finalize_authentication*", - "config: Domain/DDSSecurity/Authentication/IdentityCertificate/#text: testtext_IdentityCertificate_testtext*", - "config: Domain/DDSSecurity/Authentication/IdentityCA/#text: testtext_IdentityCA_testtext*", - "config: Domain/DDSSecurity/Authentication/PrivateKey/#text: testtext_PrivateKey_testtext*", + "config: Domain/DDSSecurity/Authentication/IdentityCertificate/#text: "TEST_IDENTITY_CERTIFICATE_ALL_OK"*", + "config: Domain/DDSSecurity/Authentication/IdentityCA/#text: "TEST_CA_CERTIFICATE_ALL_OK"*", + "config: Domain/DDSSecurity/Authentication/PrivateKey/#text: "TEST_PRIVATE_KEY_ALL_OK"*", "config: Domain/DDSSecurity/Authentication/Password/#text: testtext_Password_testtext*", "config: Domain/DDSSecurity/Authentication/TrustedCADirectory/#text: testtext_Dir_testtext*", "config: Domain/DDSSecurity/AccessControl/Library/#text: "MOCKLIB_PATH("dds_security_access_control_all_ok")"*", @@ -233,9 +234,9 @@ CU_Test(ddsc_security_config, all, .init = ddsrt_init, .fini = ddsrt_fini) " " " " " "MOCKLIB_ELEM_AUTH("dds_security_authentication_all_ok") - " testtext_IdentityCertificate_testtext" - " testtext_IdentityCA_testtext" - " testtext_PrivateKey_testtext" + " "TEST_IDENTITY_CERTIFICATE_ALL_OK"" + " "TEST_CA_CERTIFICATE_ALL_OK"" + " "TEST_PRIVATE_KEY_ALL_OK"" " testtext_Password_testtext" " testtext_Dir_testtext" " " @@ -281,9 +282,9 @@ CU_Test(ddsc_security_config, security, .init = ddsrt_init, .fini = ddsrt_fini) "config: Domain/DDSSecurity/Authentication/Library[@path]: "MOCKLIB_PATH("dds_security_authentication_all_ok")"*", "config: Domain/DDSSecurity/Authentication/Library[@initFunction]: init_authentication*", "config: Domain/DDSSecurity/Authentication/Library[@finalizeFunction]: finalize_authentication*", - "config: Domain/DDSSecurity/Authentication/IdentityCertificate/#text: testtext_IdentityCertificate_testtext*", - "config: Domain/DDSSecurity/Authentication/IdentityCA/#text: testtext_IdentityCA_testtext*", - "config: Domain/DDSSecurity/Authentication/PrivateKey/#text: testtext_PrivateKey_testtext*", + "config: Domain/DDSSecurity/Authentication/IdentityCertificate/#text: "TEST_IDENTITY_CERTIFICATE_ALL_OK"*", + "config: Domain/DDSSecurity/Authentication/IdentityCA/#text: "TEST_CA_CERTIFICATE_ALL_OK"*", + "config: Domain/DDSSecurity/Authentication/PrivateKey/#text: "TEST_PRIVATE_KEY_ALL_OK"*", "config: Domain/DDSSecurity/Authentication/Password/#text: {}*", "config: Domain/DDSSecurity/Authentication/TrustedCADirectory/#text: {}*", "config: Domain/DDSSecurity/AccessControl/Library/#text: "MOCKLIB_PATH("dds_security_access_control_all_ok")"*", @@ -307,9 +308,9 @@ CU_Test(ddsc_security_config, security, .init = ddsrt_init, .fini = ddsrt_fini) "" " " " "MOCKLIB_ELEM_AUTH("dds_security_authentication_all_ok") - " testtext_IdentityCertificate_testtext" - " testtext_IdentityCA_testtext" - " testtext_PrivateKey_testtext" + " "TEST_IDENTITY_CERTIFICATE_ALL_OK"" + " "TEST_CA_CERTIFICATE_ALL_OK"" + " "TEST_PRIVATE_KEY_ALL_OK"" " " " " " "MOCKLIB_ELEM_CRYPTO("dds_security_cryptography_all_ok") @@ -351,9 +352,9 @@ CU_Test(ddsc_security_config, deprecated, .init = ddsrt_init, .fini = ddsrt_fini "config: Domain/DDSSecurity/Authentication/Library[@path]: "MOCKLIB_PATH("dds_security_authentication_all_ok")"*", "config: Domain/DDSSecurity/Authentication/Library[@initFunction]: init_authentication*", "config: Domain/DDSSecurity/Authentication/Library[@finalizeFunction]: finalize_authentication*", - "config: Domain/DDSSecurity/Authentication/IdentityCertificate/#text: testtext_IdentityCertificate_testtext*", - "config: Domain/DDSSecurity/Authentication/IdentityCA/#text: testtext_IdentityCA_testtext*", - "config: Domain/DDSSecurity/Authentication/PrivateKey/#text: testtext_PrivateKey_testtext*", + "config: Domain/DDSSecurity/Authentication/IdentityCertificate/#text: "TEST_IDENTITY_CERTIFICATE_ALL_OK"*", + "config: Domain/DDSSecurity/Authentication/IdentityCA/#text: "TEST_CA_CERTIFICATE_ALL_OK"*", + "config: Domain/DDSSecurity/Authentication/PrivateKey/#text: "TEST_PRIVATE_KEY_ALL_OK"*", "config: Domain/DDSSecurity/Authentication/Password/#text: testtext_Password_testtext*", "config: Domain/DDSSecurity/Authentication/TrustedCADirectory/#text: testtext_Dir_testtext*", "config: Domain/DDSSecurity/AccessControl/Library/#text: "MOCKLIB_PATH("dds_security_access_control_all_ok")"*", @@ -378,9 +379,9 @@ CU_Test(ddsc_security_config, deprecated, .init = ddsrt_init, .fini = ddsrt_fini " " " " " "MOCKLIB_ELEM_AUTH("dds_security_authentication_all_ok") - " testtext_IdentityCertificate_testtext" - " testtext_IdentityCA_testtext" - " testtext_PrivateKey_testtext" + " "TEST_IDENTITY_CERTIFICATE_ALL_OK"" + " "TEST_CA_CERTIFICATE_ALL_OK"" + " "TEST_PRIVATE_KEY_ALL_OK"" " testtext_Password_testtext" " testtext_Dir_testtext" " " @@ -448,9 +449,9 @@ CU_Test(ddsc_security_config, qos, .init = ddsrt_init, .fini = ddsrt_fini) dds_qset_prop(qos, "dds.sec.access.library.path", ""MOCKLIB_PATH("dds_security_access_control_all_ok")""); dds_qset_prop(qos, "dds.sec.access.library.init", "init_access_control"); dds_qset_prop(qos, "dds.sec.access.library.finalize", "finalize_access_control"); - dds_qset_prop(qos, "dds.sec.auth.identity_ca", "testtext_IdentityCA_testtext"); - dds_qset_prop(qos, "dds.sec.auth.private_key", "testtext_PrivateKey_testtext"); - dds_qset_prop(qos, "dds.sec.auth.identity_certificate", "testtext_IdentityCertificate_testtext"); + dds_qset_prop(qos, "dds.sec.auth.identity_ca", TEST_CA_CERTIFICATE_ALL_OK); + dds_qset_prop(qos, "dds.sec.auth.private_key", TEST_PRIVATE_KEY_ALL_OK); + dds_qset_prop(qos, "dds.sec.auth.identity_certificate", TEST_IDENTITY_CERTIFICATE_ALL_OK); dds_qset_prop(qos, "dds.sec.access.permissions_ca", "file:Permissions_CA.pem"); dds_qset_prop(qos, "dds.sec.access.governance", "file:Governance.p7s"); dds_qset_prop(qos, "dds.sec.access.permissions", "file:Permissions.p7s"); @@ -494,6 +495,7 @@ CU_Test(ddsc_security_config, qos_props, .init = ddsrt_init, .fini = ddsrt_fini) PARTICIPANT_QOS_ALL_OK to work, the order must match that one */ unsigned char bvalue[3] = { 0x01, 0x02, 0x03 }; CU_ASSERT_FATAL((qos = dds_create_qos()) != NULL); + dds_qset_prop(qos, "dds.sec.auth.library.path", ""MOCKLIB_PATH("dds_security_authentication_all_ok")""); dds_qset_prop(qos, "dds.sec.auth.library.init", "init_authentication"); dds_qset_prop(qos, "dds.sec.auth.library.finalize", "finalize_authentication"); @@ -503,9 +505,9 @@ CU_Test(ddsc_security_config, qos_props, .init = ddsrt_init, .fini = ddsrt_fini) dds_qset_prop(qos, "dds.sec.access.library.path", ""MOCKLIB_PATH("dds_security_access_control_all_ok")""); dds_qset_prop(qos, "dds.sec.access.library.init", "init_access_control"); dds_qset_prop(qos, "dds.sec.access.library.finalize", "finalize_access_control"); - dds_qset_prop(qos, "dds.sec.auth.identity_ca", "testtext_IdentityCA_testtext"); - dds_qset_prop(qos, "dds.sec.auth.private_key", "testtext_PrivateKey_testtext"); - dds_qset_prop(qos, "dds.sec.auth.identity_certificate", "testtext_IdentityCertificate_testtext"); + dds_qset_prop(qos, "dds.sec.auth.identity_ca", TEST_CA_CERTIFICATE_ALL_OK); + dds_qset_prop(qos, "dds.sec.auth.private_key", TEST_PRIVATE_KEY_ALL_OK); + dds_qset_prop(qos, "dds.sec.auth.identity_certificate", TEST_IDENTITY_CERTIFICATE_ALL_OK); dds_qset_prop(qos, "dds.sec.access.permissions_ca", "file:Permissions_CA.pem"); dds_qset_prop(qos, "dds.sec.access.governance", "file:Governance.p7s"); dds_qset_prop(qos, "dds.sec.access.permissions", "file:Permissions.p7s"); @@ -514,7 +516,6 @@ CU_Test(ddsc_security_config, qos_props, .init = ddsrt_init, .fini = ddsrt_fini) dds_qset_prop(qos, "test.prop1", "testtext_value1_testtext"); dds_qset_prop(qos, "test.prop2", "testtext_value2_testtext"); - dds_qset_bprop(qos, "test.bprop1", bvalue, 3); /* Create participant with security config in qos. */ @@ -546,9 +547,9 @@ CU_Test(ddsc_security_config, config_qos, .init = ddsrt_init, .fini = ddsrt_fini "finest" "" " " - " testtext_IdentityCertificate_testtext" - " testtext_IdentityCA_testtext" - " testtext_PrivateKey_testtext" + " "TEST_IDENTITY_CERTIFICATE_ALL_OK"" + " "TEST_CA_CERTIFICATE_ALL_OK"" + " "TEST_PRIVATE_KEY_ALL_OK"" " " " " " file:Governance.p7s" @@ -572,9 +573,9 @@ CU_Test(ddsc_security_config, config_qos, .init = ddsrt_init, .fini = ddsrt_fini dds_qset_prop(qos, "dds.sec.access.library.path", ""MOCKLIB_PATH("dds_security_access_control_all_ok")""); dds_qset_prop(qos, "dds.sec.access.library.init", "init_access_control"); dds_qset_prop(qos, "dds.sec.access.library.finalize", "finalize_access_control"); - dds_qset_prop(qos, "dds.sec.auth.identity_ca", "testtext_IdentityCA_testtext"); - dds_qset_prop(qos, "dds.sec.auth.private_key", "testtext_PrivateKey_testtext"); - dds_qset_prop(qos, "dds.sec.auth.identity_certificate", "testtext_IdentityCertificate_testtext"); + dds_qset_prop(qos, "dds.sec.auth.identity_ca", TEST_CA_CERTIFICATE_ALL_OK); + dds_qset_prop(qos, "dds.sec.auth.private_key", TEST_PRIVATE_KEY_ALL_OK); + dds_qset_prop(qos, "dds.sec.auth.identity_certificate", TEST_IDENTITY_CERTIFICATE_ALL_OK); dds_qset_prop(qos, "dds.sec.access.permissions_ca", "file:Permissions_CA.pem"); dds_qset_prop(qos, "dds.sec.access.governance", "file:Governance.p7s"); dds_qset_prop(qos, "dds.sec.access.permissions", "file:Permissions.p7s"); @@ -614,9 +615,9 @@ CU_Test(ddsc_security_config, other_prop, .init = ddsrt_init, .fini = ddsrt_fini "" " " " "MOCKLIB_ELEM_AUTH("dds_security_authentication_all_ok") - " testtext_IdentityCertificate_testtext" - " testtext_IdentityCA_testtext" - " testtext_PrivateKey_testtext" + " "TEST_IDENTITY_CERTIFICATE_ALL_OK"" + " "TEST_CA_CERTIFICATE_ALL_OK"" + " "TEST_PRIVATE_KEY_ALL_OK"" " testtext_Password_testtext" " testtext_Dir_testtext" " " @@ -685,9 +686,9 @@ CU_Test(ddsc_security_config, qos_invalid, .init = ddsrt_init, .fini = ddsrt_fin "finest" "" " " - " testtext_IdentityCertificate_testtext" - " testtext_IdentityCA_testtext" - " testtext_PrivateKey_testtext" + " "TEST_IDENTITY_CERTIFICATE_ALL_OK"" + " "TEST_CA_CERTIFICATE_ALL_OK"" + " "TEST_PRIVATE_KEY_ALL_OK"" " " " " " file:Governance.p7s" diff --git a/src/security/core/tests/tc_fsm.c b/src/security/core/tests/tc_fsm.c index c2c7647..5489d19 100644 --- a/src/security/core/tests/tc_fsm.c +++ b/src/security/core/tests/tc_fsm.c @@ -369,16 +369,19 @@ static const uint32_t TransitionsSize = sizeof(Transitions)/sizeof(Transitions[0 **********************************************************************/ typedef enum { - eventToTimeout, eventToEnd, + eventToTimeout, eventToInterupt, eventToEnd, } timeout_events; +struct fsm_timeout_arg { + int id; +}; + static struct dds_security_fsm *fsm_timeout; static uint32_t visited_timeout = 0; static uint32_t correct_fsm_timeout = 0; static uint32_t correct_arg_timeout = 0; -static ddsrt_cond_t stop_timeout_cond; -static ddsrt_mutex_t stop_timeout_cond_mutex; -static uint32_t stop_timeout_cond_cnt = 0; +static struct fsm_timeout_arg fsm_arg = { .id = FSM_AUTH_ARG }; + /* The functions called from the state-machine. */ static void doInterupt(struct dds_security_fsm *fsm, void *arg) @@ -393,24 +396,15 @@ static void doInterupt(struct dds_security_fsm *fsm, void *arg) static void doTimeout(struct dds_security_fsm *fsm, void *arg) { - dds_duration_t delay4 = 4 * DDS_NSECS_IN_SEC; - DDSRT_UNUSED_ARG(arg); if (DB_TC_PRINT_DEBUG) { - printf("Transition >>>> %s %d\n", __FUNCTION__, stop_timeout_cond_cnt); + printf("Transition >>>> %s\n", __FUNCTION__); } visited_timeout |= 1UL << 1; - stop_timeout_cond_cnt++; - ddsrt_mutex_lock(&stop_timeout_cond_mutex); - (void) ddsrt_cond_waitfor(&stop_timeout_cond, &stop_timeout_cond_mutex, - delay4); - ddsrt_mutex_unlock(&stop_timeout_cond_mutex); - stop_timeout_cond_cnt--; - if (DB_TC_PRINT_DEBUG) { - printf("Transition <<<< %s %d\n", __FUNCTION__, stop_timeout_cond_cnt); + printf("Transition <<<< %s\n", __FUNCTION__); } dds_security_fsm_dispatch(fsm, eventToTimeout, false); @@ -418,7 +412,7 @@ static void doTimeout(struct dds_security_fsm *fsm, void *arg) static void TimeoutCallback(struct dds_security_fsm *fsm, void *arg) { - int *fsm_arg; + struct fsm_timeout_arg *farg = arg; if (DB_TC_PRINT_DEBUG) { printf("TimeoutCallback\n"); @@ -426,10 +420,8 @@ static void TimeoutCallback(struct dds_security_fsm *fsm, void *arg) visited_timeout |= 1UL << 2; - if (arg != NULL) { - fsm_arg = (int *) arg; - - if (*fsm_arg == FSM_AUTH_ARG) { + if (farg != NULL) { + if (farg->id == FSM_AUTH_ARG) { correct_arg_timeout = 1; } else { correct_arg_timeout = 0; @@ -452,14 +444,17 @@ static void TimeoutCallback2(struct dds_security_fsm *fsm, void *arg) visited_timeout |= 1UL << 3; } -static dds_security_fsm_state StateTimeout = {doTimeout, 0};static int fsm_arg = FSM_AUTH_ARG; +static dds_security_fsm_state StateInitial = {doTimeout, 0}; +static dds_security_fsm_state StateWaitTimeout = {NULL, DDS_SECS(4)}; +static dds_security_fsm_state StateInterupt = {doInterupt, 0}; -static dds_security_fsm_state StateInterupt = {doInterupt, 0}; static const dds_security_fsm_transition TimeoutTransitions[] = { - {NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &StateTimeout}, // NULL state is the start state - {&StateTimeout, eventToTimeout, NULL, &StateInterupt}, - {&StateInterupt,eventToEnd, NULL, NULL}, // Reaching NULL means end of state-diagram + {NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &StateInitial}, // NULL state is the start state + {&StateInitial, eventToTimeout, NULL, &StateWaitTimeout}, + {&StateWaitTimeout, DDS_SECURITY_FSM_EVENT_TIMEOUT, NULL, &StateInterupt}, + {&StateWaitTimeout, eventToInterupt, NULL, &StateInterupt}, + {&StateInterupt, eventToEnd, NULL, NULL}, // Reaching NULL means end of state-diagram }; static const uint32_t TimeoutTransitionsSize = sizeof(TimeoutTransitions)/sizeof(TimeoutTransitions[0]); @@ -541,16 +536,10 @@ static void fsm_control_init(void) rc = dds_security_fsm_control_start (g_fsm_control, NULL); CU_ASSERT_FATAL(rc == 0); - - ddsrt_mutex_init(&stop_timeout_cond_mutex); - ddsrt_cond_init(&stop_timeout_cond); } static void fsm_control_fini(void) { - ddsrt_cond_destroy(&stop_timeout_cond); - ddsrt_mutex_destroy(&stop_timeout_cond_mutex); - dds_security_fsm_control_stop(g_fsm_control); dds_security_fsm_control_free(g_fsm_control); @@ -697,12 +686,10 @@ CU_Test(ddssec_fsm, timeout, .init = fsm_control_init, .fini = fsm_control_fini) timeout--; } CU_ASSERT(timeout > 0); - CU_ASSERT( - CHECK_BIT(visited_timeout, 0) && CHECK_BIT(visited_timeout, 1) && CHECK_BIT(visited_timeout, 2)); + CU_ASSERT(CHECK_BIT(visited_timeout, 0) && CHECK_BIT(visited_timeout, 1) && CHECK_BIT(visited_timeout, 2)); CU_ASSERT(correct_arg_timeout && correct_fsm_timeout); dds_security_fsm_free(fsm_timeout); - } /** @@ -740,10 +727,6 @@ CU_Test(ddssec_fsm, double_timeout, .init = fsm_control_init, .fini = fsm_contro CU_ASSERT(CHECK_BIT(visited_timeout, 3)); dds_security_fsm_free(fsm_timeout); dds_security_fsm_free(fsm_timeout2); - ddsrt_mutex_lock(&stop_timeout_cond_mutex); - ddsrt_cond_signal(&stop_timeout_cond); - ddsrt_mutex_unlock(&stop_timeout_cond_mutex); - } /** @@ -840,15 +823,5 @@ CU_Test(ddssec_fsm, delete_with_timeout, .init = fsm_control_init, .fini = fsm_c } dds_security_fsm_free(fsm_timeout); - dds_sleepfor(100 * DDS_NSECS_IN_MSEC); - - /* Just for safety to be certain that the condition isn't used anymore before destroying it. */ - while (stop_timeout_cond_cnt > 0) { - dds_time_t d = DDS_NSECS_IN_SEC; - ddsrt_cond_signal(&stop_timeout_cond); - dds_sleepfor(d); - } - - }