diff --git a/.travis.yml b/.travis.yml index 4a1ed53..65b4303 100644 --- a/.travis.yml +++ b/.travis.yml @@ -143,33 +143,37 @@ windows_vs2017: &windows_vs2017 jobs: include: - <<: *linux_gcc8 - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles", COVERITY_SCAN=true ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles", COVERITY_SCAN=true ] if: type = cron - <<: *linux_gcc8 - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] - <<: *linux_gcc8 - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles", CONANFILE=conanfile102.txt ] - <<: *linux_gcc8 - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=NO, LIFESPAN=NO, DEADLINE=NO, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] + - <<: *linux_gcc8 + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=NO, SECURITY=YES, LIFESPAN=NO, DEADLINE=NO, GENERATOR="Unix Makefiles" ] - <<: *linux_clang - env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] - <<: *linux_clang - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, SECURITY=NO, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] + - <<: *linux_clang + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] - <<: *osx_xcode9 - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] if: type = cron - <<: *osx_xcode - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles", MACOSX_DEPLOYMENT_TARGET=10.12 ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=NO, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles", MACOSX_DEPLOYMENT_TARGET=10.12 ] - <<: *osx_xcode - env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=address, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] - <<: *osx_xcode - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Unix Makefiles" ] - <<: *windows_vs2017 - env: [ ARCH=x86, ASAN=none, BUILD_TYPE=Debug, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Visual Studio 15 2017" ] + env: [ ARCH=x86, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Visual Studio 15 2017", CONANFILE=conanfile102.txt ] - <<: *windows_vs2017 - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Visual Studio 15 2017 Win64" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Debug, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Visual Studio 15 2017 Win64" ] - <<: *windows_vs2017 - env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Visual Studio 15 2017 Win64" ] + env: [ ARCH=x86_64, ASAN=none, BUILD_TYPE=Release, SSL=YES, SECURITY=YES, LIFESPAN=YES, DEADLINE=YES, GENERATOR="Visual Studio 15 2017 Win64" ] before_script: - conan profile new default --detect @@ -195,12 +199,13 @@ script: - INSTALLPREFIX="$(pwd)/install" - mkdir build - cd build - - conan install -b missing -s arch=${ARCH} -s build_type=${BUILD_TYPE} .. + - conan install -b missing -s arch=${ARCH} -s build_type=${BUILD_TYPE} ../${CONANFILE:-conanfile.txt} - which trang && BUILD_SCHEMA=1 || BUILD_SCHEMA=0 - cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -DCMAKE_INSTALL_PREFIX=${INSTALLPREFIX} -DUSE_SANITIZER=${ASAN} -DENABLE_SSL=${SSL} + -DENABLE_SECURITY=${SECURITY} -DENABLE_LIFESPAN=${LIFESPAN} -DENABLE_DEADLINE_MISSED=${DEADLINE} -DBUILD_TESTING=on diff --git a/CMakeLists.txt b/CMakeLists.txt index ca28ca1..b999c04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ # SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause # cmake_minimum_required(VERSION 3.7) -project(CycloneDDS VERSION 0.6.0) +project(CycloneDDS VERSION 0.7.0) # Set a default build type if none was specified set(default_build_type "RelWithDebInfo") diff --git a/cmake/Modules/CUnit.cmake b/cmake/Modules/CUnit.cmake index 7453679..2fda997 100644 --- a/cmake/Modules/CUnit.cmake +++ b/cmake/Modules/CUnit.cmake @@ -281,12 +281,17 @@ function(add_cunit_executable TARGET) set_property( TEST ${ctest} PROPERTY ENVIRONMENT - "DYLD_LIBRARY_PATH=${CUNIT_LIBRARY_DIR}:$ENV{DYLD_LIBRARY_PATH}") + "DYLD_LIBRARY_PATH=${CUNIT_LIBRARY_DIR}:${CMAKE_LIBRARY_OUTPUT_DIRECTORY}:$ENV{DYLD_LIBRARY_PATH}") elseif(WIN32 AND ${CUNIT_LIBRARY_TYPE} STREQUAL "SHARED_LIBRARY") set_property( TEST ${ctest} PROPERTY ENVIRONMENT "PATH=${CUNIT_LIBRARY_DIR};$ENV{PATH}") + else() + set_property( + TEST ${ctest} + PROPERTY ENVIRONMENT + "LD_LIBRARY_PATH=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}:$ENV{LD_LIBRARY_PATH}") endif() endforeach() diff --git a/conanfile102.txt b/conanfile102.txt new file mode 100644 index 0000000..64560b9 --- /dev/null +++ b/conanfile102.txt @@ -0,0 +1,6 @@ +[requires] +cunit/2.1-3@bincrafters/stable +OpenSSL/1.0.2@conan/stable + +[generators] +cmake diff --git a/docs/dev/dds_security_effort.md b/docs/dev/dds_security_effort.md new file mode 100644 index 0000000..d554749 --- /dev/null +++ b/docs/dev/dds_security_effort.md @@ -0,0 +1,406 @@ +# DDS Security effort + +ADLink has decided to donate their Vortex OpenSplice DDS Security +implementation to the Cyclone DDS project. However, that will not be a simple +code drop. + +This document catches all the work that is foreseen to port Vortex OpenSplice +DDS Security to Cyclone DDS. + +This document can be removed when DDS Security has been implemented. + +**Table of contents** +- [Definition of done](#done) +- [Footprint](#footprint) +- [Multi process testing (done)](#testing) +- [Runtime library loading (done)](#loading) +- [Hopscotch utility (done)](#hopscotch) +- [FSM utility (in progress)](#fsm) +- [Port DDS Security plugin API (done)](#port-api) +- [De-Serializing messages in DDSI (done)](#deserializing) +- [De-Serializing security message parameters in DDSI (done)](#deserializing_plist) +- [Port DDS Security builtin plugins (in progress)](#port-plugins) +- [Port DDSI DDS Security (in progress)](#port-ddsi) +- [Move configuration (in progress)](#Move-configuration) +- [Failure handling](#failures) +- [Multiple configurations](#multiple-configurations) +- [Example](#example) +- [QosProvider](#qosprovider) +- [Data Tags (optional)](#datatags) + + +## Definition of done + +When this document tells that a certain aspect is 'done', it means that it +has been accepted into the security branch of the cyclonedds repository +(https://github.com/eclipse-cyclonedds/cyclonedds/tree/security). + +However, it is possible that various parts need some rework before the security +branch can be merged into the cyclonedds master branch. + + +## Footprint + +A non-functional requirement is that cyclonedds should be buildable without +the DDS Security support in it. That will reduce the footprint (and possibly +improve performance) for applications that don't need security. + +For that, the ENABLE_SECURITY build option is introduced that translates into +the DDSI_INCLUDE_SECURITY compile switch. However, the usage of that switch +should not explode. That'll reduce the maintainability. + +For instance, the usage of the switch can be minimized by using functions that +will reduce to an inline function that just returns a hardcode value when +security is not included (otherwise they'll do some certain task). +The compiler can use these inline functions to do clever stuff regarding +footprint and performance. + +There can be other solutions to decrease security footprint without impeding +on the maintainability of the code by inserting the switch too much. + + +## Multi process testing (done) + +To properly test DDS Security, multi process testing will be necessary. +This is not yet available in Cyclone DDS. +See the [Multi Process Testing](multi_process_testing.md) document for +more information. + + +## Runtime library loading (done) + +The ddsi component needs to be able to load DDS Security plugins at runtime. +These plugins are provided as libraries.
+Loading libraries at runtime is currently not possible in Cyclone DDS. + + +## Hopscotch utility (done)
+ +This hash table is used by the Security plugins.
+Both versions on OpenSplice and Cyclone are equivalent.
+No additional effort is expected. + + +## FSM utility (in progress)
+ +The Finite State Machine utility has been introduced in OpenSplice to support +the handshake of DDS Security.
+This has to be ported to Cyclone. + +However, it already has some technical dept, which should be removed before +adding it to Cyclone. This means that a refactor should happen as part of the +porting. + +The related DBTs should also be ported to Cyclone unit tests. + +It was decided to just port the FSM at the moment. The refactor will take place +when trying to get the security branch into master. + + +## Port DDS Security plugin API (done)
+ +The DDS Security plugin API are just a few header files. The ddsi component +uses that to link against. The implementation of the API is done in the +individual plugins. The plugins are [loaded at runtime](#loading) (when +configured). + +This means that ddsi can be DDS Security prepared (after building against this +API) without there being actual DDS Security plugins. + +It seems to be just a code drop of a number of header files.
+Maybe add some CMake module for both ddsi and the plugins to easily link +against? + + +## De-Serializing messages in DDSI (done)
+ +DDSI needs to be able to (de)serialize a few Security messages. In OpenSplice, +some functionality of the database is used. This is unavailable in Cyclone. + +What is available is a serializer that uses marshaling operations (see, for +for instance, m_ops in the dds_topic_descriptor struct). + +The (de)serializing of the Security messages should be supported by supplying +the m_ops sequences, message structs (if not yet available) and some +convenience functions using both. + + +## De-Serializing security message parameters in DDSI (done) + +DDSI needs to be able to (de)serialize a few message parameters that have +been introduced by the DDS Security spec. + + +## Port DDS Security builtin plugins (in progress) + +No major changes between the DDS Security plugins in OpenSplice and Cyclone +are expected. + +The DDS Security plugins require OpenSSL. Cyclone DDS already uses OpenSSL. +However, it expects (or at least it's preferred to have) version 1.1 or newer, +while the OpenSplice Security plugins are build against 1.0.2. There are some +API changes between the two versions. This will take some porting effort. + +The build system should be ported from makefiles to cmake files. + +There are security_plugin DBTs in OpenSplice. These tests are base on cunit, +which is also used in Cyclone. However, it is used slightly different. A small +porting effort is expected (i.e. let it work with cmake and runner generation). + +This means some additional effort, compared to just a code drop. But it is not +expected to be major. + +- Authentication plugin (done). +- Access Control plugin (in progress). +- Cryptography plugin (done). + +There are a few sub-features that can be implemented separately. +- Check/handle expiry dates (in progress). +- Trusted directory support. +- etc? + + +## Port DDSI DDS Security (in progress) + +There is already quite a bit of difference between the DDSI codebases in +OpenSplice and Cyclone. So, the copy/merge of the DDSI Security code from +OpenSplice to Cyclone will not be trivial. + +Most parts of the merging will not be trivial, but should be quite +straightforward nonetheless. Things that are noticed to be somewhat different +between the DDSI code bases that could impact the merging work: +- Entity matching is slightly different. +- The q_entity.c has a lot of differences that can obfuscate the differences + related to DDS Security. +- Unacked messages logic has changed a bit. Does that impact gaps? +- (De)serializing, of course + (see also [De-Serializing in DDSI](#deserializing)). +- Writer history cache is different, which can impact the builtin volatile + Security endpoints. +- Unknown unknowns. + +The buildsystem has to be upgraded.
+- A few files are added which are easy to add to cmake.
+- There's a new dependency on the [DDS Security API](#port-api), which is done. + +Then, of course, there are the tests
+First of all, [Multi Process Testing](#testing) should be available, which now +it is.
+When that's the case, then the OpenSplice tests business +logic have to be ported from scripts and applications to that new framework. +That porting shouldn't be that hard. However, it will probably take a while. + +The DDSI Port doesn't have to be a big bang. It can be split up into various +different pull requests. Examples are +- Extend configuration XML parsing with the security configuration (done). +- Extend nn_qos with security related policies. Fill them with values from the + configuration when applicable (done). +- Add DDS Security endpoints that are non-volatile (done). +- Add DDS Security endpoint that is volatile. This change has more impact than + all the non-volatile endpoints combined (done). +- Handshake (in progress). +- Payload (en)(de)coding (DDSI support: done. Wrapper: todo). +- Submsg (en)(de)coding (DDSI support: done. Wrapper: todo). +- RTPSmsg (en)(de)coding (DDSI support: done. Wrapper: todo). +- Etc + + + +## Move configuration (in progress)
+ +After the port, the DDS Security configuration is still (partly) done through +the overall configuration XML file (rest is coming from the permissions and +governance files).
+However, according to the specification, the configuration should happen by +means of the Participant QoS. + +The ddsc dds_qos_t is mapped on the ddsi xqos. The ddsi xqos already has the +necessary policy (after the [port](#port-ddsi)), namely the property_policy. +This means that the ddsc qos itself is automatically prepared.
+However, getting and setting policies are done through getter and setter +functions in ddsc.
+This means we have to add these functions for the security configuration values. + +The ddsc policy getter and setter functions use (arrays of) primitive types as +arguments. The configuration of Security is given by means of the property +policy, which isn't a primitive. To keep in line with the QoS API, we could add +something like: +```cpp +typedef struct dds_properties_t; /* opaque type in API, but mapped to + nn_property_qospolicy_t internally */ +dds_properties_t *dds_properties_create(); +void dds_properties_delete(dds_properties_t *); +void dds_properties_merge(dds_properties_t *, dds_properties_t *); +void dds_properties_add_property(dds_properties_t *, char *name, char *value); +void dds_properties_add_binaryproperty(dds_properties_t *, char *name, + uchar *value, int valuelength); +void dds_qset_properties(dds_qos_t*, dds_properties_t *); +void dds_qget_properties(dds_qos_t*, dds_properties_t **); +``` +But this is very preliminary and is still up for debate. + +After moving the Security configuration to the participant QoS, it's possible +to have different configurations within a single application if you have +multiple participants. However, ddsi only supports one Security configuration +for now. That doesn't change by changing where that configuration comes +from.
+To solve this, it is expected that creation of a participant with a different +configuration will force a failure for now. +Until [Multiple Configurations](#multiple-configurations) is implemented. + +After the ddsc API has been extended, we can decide on what to do with the +configuration through XML. +- Keep it. It seems usable: no need to change applications when changing (or + adding) Security settings. However, conflicts between XML and QoS + configuration could cause problems. Simplest seems to be to only allow QoS + security configuration when it's not configured in XML already. +- Remove it. No conflict resolving needed. + +All the Security tests depend on providing (different) configurations through +XML. Depending on if we keep or remove the XML configuration option, a lot of +tests have to be updated, or a few added (that test security configuration +through QoS). + +For the loading of the plugin libraries, properties with specific names have to +be added to the property policy to know the location and names of the plugins. +As inspiration, fastrtps can be used: +https://github.com/ros2/rmw_fastrtps/blob/master/rmw_fastrtps_shared_cpp/src/rmw_node.cpp#L296 + + +## Failure handling
+ +Currently, when an local action is tried that isn't allowed by DDS Security +(like creating a participant when it's not permitted), DDSI is shut down.
+Mainly because in OpenSplice it's quite hard to get a failure state from DDSI +to the application. + +In Cyclone, however, ddsc::dds_create_participant() results in a direct call to +ddsi::new_participant(). This means that if creation of an entity (or +participant in this example) fails due to security issues in ddsi, we can fail +the actual ddsc API call with a proper error result (there's already the +DDS_RETCODE_NOT_ALLOWED_BY_SECURITY in the ddsc API (not used)). + +Maybe we have to do some additional cleanup when a failure is encountered. + +Some tests probably have to be adjusted for the new behaviour. + + +## Multiple configurations
+ +Currently (because it's done through the overall XML configuration), only one +DDS Security configuration could be supported. Because of this fact, at various +locations, shortcuts could be made in both DDSI and plugins.
+However, because the configuration is coming from participants now (see +[Move Configuration](#Move-configuration), we should be able to support +multiple different DDS Security configurations. + +Until now, the creation of a second participant with a different configuration +would force a failure (again, see [Move Configuration](#Move-configuration)). + +It is expected that the plugin loading still happens through the configuration +XML (see [Move Configuration](#Move-configuration)). This means that DDSI doesn't have to support +multiple sets of plugins. Just the one set, provided at initialization. This +means that DDSI shouldn't have to be changed to support this. + +So, it's the plugins need to be able to support multiple configurations. + +The Cryptography plugin doesn't seem to care about global DDS Security +configurations. It has basically configurations per participant/topic/ +endpoints, which already works. So, this plugin doesn't have to be upgraded. + +The Authentication plugin does have global DDS Security configurations. Main +function related to that is validate_local_identity(). This function already +creates a new local identity every time it is called. So, this plugin doesn't +have to be upgraded either. + +That leaves the Access Control plugin.
+The main function related to configuration is validate_local_permissions(). +This function creates access rights depending on Permissions and Governance +files. Currently, there's only one local 'rights' structure that is linked +directly to the plugin (see also the ACCESS_CONTROL_USE_ONE_PERMISSION compile +switch).
+This has to change.
+The local rights structure needs to be coupled to a participant. This also +means that we have to search for it instead of having direct access when +entering the plugin.
+The remote rights can be used as example. That is basically a list of rights/ +permissions with the remote identity handle as key. + +Tests have to be added to make sure that a setup with different Security +configurations works. + + +## Example
+ +A Security example has to be added. + + +## QosProvider + +The Participant QoS now contains Security related information. This means that +the QosProvider has to be upgraded to support that. + + +## Data Tags (optional) + +The specification is somewhat fuzzy about the data tags. + +The following is a summary (still elaborate) of how it seems to work: + +The permissions document can contain the tag on publish and +subscribe level. It's related to the data samples, but don't have to be related +to the keys of those samples.
+The QoS of a writer/reader can also have data tags by means of the +DataTagQosPolicy. A writer/reader can only be created when the data_tags in the +QoS matches those in the permissions document. This check should happen on both +the local and remote level. + +This creation check is the only thing that DDS Security actually does with the +data tags. They are only authenticated by DDS Security, but not interpreted +further.
+This is only a minor security addition, because the publisher can still publish +data that doesn't match the data tags because DDS doesn't interpret the data +nor compares it with the data tags. + +What it can be used for is a kind of custom access control scheme on the +application level.
+An application that consumes data can see if a publisher is allowed to publish +that sample by comparing the data within the sample with the data tag(s) +associated with that publisher. As said, this comparison is not done on the DDS +level, but has to be done within the application itself. + +That leaves the question, how does the application get the tags associated with +the related writer?
+In other words; the application gets a sample. It has to know from which writer +it originated and it has to have access to the data tag(s) of that writer. +The dds_sample_info_t contains the dds_instance_handle_t publication_handle, +which is unique to the writer (locally).
+That dds_instance_handle_t can be used to get the right +DDS_Security_PublicationBuiltinTopicDataSecure sample for the related secure +builtin reader [**note1**].
+DDS_Security_PublicationBuiltinTopicDataSecure contains QoS information +regarding that writer, including the DataTagQosPolicy. The remote +DDS_Security_PublicationBuiltinTopicDataSecure contents have been authenticated +by DDS Security and the data tags can be trusted.
+The application can check the sample data against the data_tags within that +QoS. + +Things to do: +- Add DataTagQosPolicy to the ddsc API and the related QoSses. +- Add DDS_Security_PublicationBuiltinTopicDataSecure data type to the ddsc API + (better yet, all secure builtin types). +- Add the related builtin reader to the ddsc99 API (better yet, all secure + builtin readers). +- Add test regarding the secure builtin readers and data. +- Add data tag comparisons between QoS and permission documents during local + and remote entity creation. +- Add data tag remote/local (mis)match tests. + +Especially because of the lack of access to builtin secure readers, supporting +data tags doesn't seem feasible in the near future. Also, it's optional in the +specification. + +**note1** +That DDS_Security_PublicationBuiltinTopicDataSecure reader is not yet available +within the ddsc API, nor is the related data type. Don't know how much work it +would be to add them to that API. diff --git a/docs/dev/modules.md b/docs/dev/modules.md index 0ab8029..ef80590 100644 --- a/docs/dev/modules.md +++ b/docs/dev/modules.md @@ -195,3 +195,94 @@ automatic if the target supports it. Finalization is primarily used to release thread-specific memory and call routines registered by `ddsrt_thread_cleanup_push`. + +## DDS Security + +### Specification + +DDS Security is an [OMG specification](https://www.omg.org/spec/DDS-SECURITY/1.1/PDF) which adds several “DDS Security Support” +compliance points to the DDS Specification. +The specification defines the Security Model and Service Plugin Interface (SPI) +architecture for compliant DDS implementations. The DDS Security Model is enforced +by the invocation of these SPIs by the DDS implementation. +Security Model for DDS defines the security principals (users of the system), +the objects that are being secured, and the operations on the objects that are +to be restricted. + +SPIs are defined that when combined together provide Information Assurance to +DDS systems: +* Authentication Service Plugin. Provides the means to verify the identity of the +application and/or user that invokes operations on DDS. Includes facilities to +perform mutual authentication between participants and establish a shared secret. +* AccessControl Service Plugin. Provides the means to enforce policy decisions on +what DDS related operations an authenticated user can perform. For example, which +domains it can join, which Topics it can publish or subscribe to, etc. +* Cryptographic Service Plugin. Implements (or interfaces with libraries that +implement) all cryptographic operations including encryption, decryption, +* Logging Service Plugin. Supports auditing of all DDS security-relevant events +* Data Tagging Service Plugin. Provides a way to add tags to data samples. + +DDS Security Plugin Components + + +### Cyclone DDS Security + +Cyclone DDS Security implementation is composed of the following components/modifications: + +* DDS Security plugin API +* DDS Security built-in plugins that implement the API +* DDS Security Core Library that is used by the plugins and DDSI. +* Changes in the DDSI that moderate the specified security model. + +The dependency diagram: + + + DDSI ----> DDS Security API (headers only) <----- DDS Security Plugins + | ^ | + | | | + | | | + -------> DDS Security Core <------------------------ + | | | + | | | + | | | + | v | + -------> DDS_RT <------------------------ + +All security specific contents are under src/security. + +##### DDS Security API + +The DDS Security plugin API consists of just a few header files. There are separate +header files for each plugin: dds_security_api_authentication.h dds_security_api_cryptography.h +and dds_security_api_access_control.c + +The API functions and types are prepared from the IDL by adding DDS_Security_ namespace +prefix to functions and data types. Instead of extending DDS builtin topic data types, +separate DDS_Security_ data type is defined for the current type and the new secure data type. + +##### Built-in Plugins + +Cyclone DDS Security comes with three mandatory plugins: authentication, cryptography and access control. + +###### Authentication Plugin + +This plugin implements authentication using a trusted Certificate Authority (CA). It performs +mutual authentication between discovered participants using the RSA or ECDSA Digital Signature +Algorithms and establishes a shared secret using Diffie-Hellman (DH) or Elliptic Curve Diffie-Hellman +(ECDH) Key Agreement Methods. + +DDS Security Plugin Components + +###### Cryptography Plugin + +This plugin provides authenticated encryption using Advanced Encryption Standard (AES) in +Galois Counter Mode (AES-GCM). It supports two AES key sizes: 128 bits and 256 bits. It may +also provide additional reader-specific message authentication codes (MACs) using Galois MAC (AES-GMAC). + +DDS Security Plugin Components + + +###### Access Control Plugin + +DDS Security Plugin Components + diff --git a/docs/dev/pictures/dds_security_access_control_plugin.png b/docs/dev/pictures/dds_security_access_control_plugin.png new file mode 100644 index 0000000..13b28d9 Binary files /dev/null and b/docs/dev/pictures/dds_security_access_control_plugin.png differ diff --git a/docs/dev/pictures/dds_security_authentication_plugin.png b/docs/dev/pictures/dds_security_authentication_plugin.png new file mode 100644 index 0000000..a2b3ea5 Binary files /dev/null and b/docs/dev/pictures/dds_security_authentication_plugin.png differ diff --git a/docs/dev/pictures/dds_security_crypto_plugin.png b/docs/dev/pictures/dds_security_crypto_plugin.png new file mode 100644 index 0000000..d314978 Binary files /dev/null and b/docs/dev/pictures/dds_security_crypto_plugin.png differ diff --git a/docs/dev/pictures/dds_security_plugin_components.png b/docs/dev/pictures/dds_security_plugin_components.png new file mode 100644 index 0000000..cfcd692 Binary files /dev/null and b/docs/dev/pictures/dds_security_plugin_components.png differ diff --git a/docs/dev/todo_list.md b/docs/dev/todo_list.md new file mode 100644 index 0000000..909b953 --- /dev/null +++ b/docs/dev/todo_list.md @@ -0,0 +1,32 @@ +# TODO LIST + +## Security + +* Reassess Jeroen's comment: +https://github.com/eclipse-cyclonedds/cyclonedds/pull/177#issuecomment-494040238 +> 5. If the security_api just becomes part of ddsc, and it should in my opinion, then I'd prefer you propagate the naming scheme as introduced in ddsrt etc and name the header files e.g. dds/ddssec/auth.h or something instead of dds/security/dds_security_api_authentication.h. + +* Reassess Jeroen's comment: +https://github.com/eclipse-cyclonedds/cyclonedds/pull/177#issuecomment-494040238 +> I've spent a great deal of time stripping out all the various different error codes and make it so that we simply use DDS_RETCODE_ constants everywhere. This pull request reintroduces separate error codes and that's something I really don't approve of. The security error codes start at an offset of 100 and should nicely integrate with the other codes in dds/ddsrt/retcode.h. The messages should be retrievable using dds_strretcode if you ask me. + + +* reassess Erik's comment +https://github.com/eclipse-cyclonedds/cyclonedds/pull/177#issuecomment-490718462 +> GuidPrefix & BuiltinTopicKey change + +* reassess erik's comment +https://github.com/eclipse-cyclonedds/cyclonedds/pull/177#issuecomment-490718462 +> ddsrt_strchrs + +* Reassess Jeroen's comment: +https://github.com/eclipse-cyclonedds/cyclonedds/pull/177#issuecomment-494040238 +> If the security_api just becomes part of ddsc, and it should in my opinion, then I'd prefer you propagate the naming scheme as introduced in ddsrt etc and name the header files e.g. dds/ddssec/auth.h or something instead of dds/security/dds_security_api_authentication.h. + +* Reassess Jeroen's comment: +https://github.com/eclipse-cyclonedds/cyclonedds/pull/177#issuecomment-494040238 +> If the security_api just becomes part of ddsc, and it should in my opinion, then I'd prefer you propagate the naming scheme as introduced in ddsrt etc and name the header files e.g. dds/ddssec/auth.h or something instead of dds/security/dds_security_api_authentication.h. + + + + diff --git a/docs/dev/volatile_msg_secure.md b/docs/dev/volatile_msg_secure.md new file mode 100644 index 0000000..d784387 --- /dev/null +++ b/docs/dev/volatile_msg_secure.md @@ -0,0 +1,131 @@ +# ParticipantVolatileMessageSecure Handling + +## Short Introduction + +It is expected to have some knowledge of DDSI builtin (security) endpoints. + +```cpp +#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER 0xff0202c3 +#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER 0xff0202c4 +``` +These builtin endpoints have caused about the biggest code change in ddsi, regarding security. + +Chapters 7.4.4.3 and 7.4.4.4 in the DDS Security specification indicates the main issue why these builtin endpoints are different from all the others and somewhat more complex. + +> 7.4.4.3 Contents of the ParticipantVolatileMessageSecure +> The ParticipantVolatileMessageSecure is intended as a holder of secure information that +> is sent point-to-point from a DomainParticipant to another. +> +> [...] +> +> 7.4.4.4 Destination of the ParticipantVolatileMessageSecure +> +> If the destination_participant_guid member is not set to GUID_UNKNOWN, the message written is +> intended only for the BuiltinParticipantVolatileMessageSecureReader belonging to the +> DomainParticipant with a matching Participant Key. +> +> This is equivalent to saying that the BuiltinParticipantVolatileMessageSecureReader has an implied +> content filter with the logical expression: +> +> “destination_participant_guid == GUID_UNKNOWN +> || destination_participant_guid==BuiltinParticipantVolatileMessageSecureReader.participant.guid” +> +> Implementations of the specification can use this content filter or some other mechanism as long as the +> resulting behavior is equivalent to having this filter. +> +> [...] + +The "point-to-point" and "content filter" remarks makes everything more elaborate. + + +## Complexity + +It would be nice to be able to use the ```dds_set_topic_filter()``` functionality for these endpoints. However, that only works on the reader history cache (rhc), which is only available for ddsc entities and not for ddsi builtin entities. And it's the builtin entities that are being used. + +The ```dds_set_topic_filter()``` basically simulates that the sample was inserted into the rhc (but didn't insert it), which causes the rest of ddsi (regarding heartbeat, acknacks, gaps, etc) to work as normal while the sample just isn't provided to the reader. + +Unfortunately, the builtin volatile endpoints can not use that same simple sequence (just handle the sample but ignore it right at the end). Problem is, the sample is encoded. It can only decode samples that are intended for that reader. This would mean that it is best for the reader to only receive 'owned' samples that it can actually decode. + +This has all kinds of affects regarding the heartbeat, acknacks, gaps, etc. Basically, every writer/reader combination should have information regarding gaps and sequence numbers between them, while normally such information about proxies are combined. + + +## Implementation Overview + +This only depicts an overview. Some details will have been omitted. + + +### Writing + +The function ```write_crypto_exchange_message()``` takes care of generating the right sample information and pass it on to ```write_sample_p2p_wrlock_held()```. + +A proxy reader can now have a filter callback function (```proxy_reader::filter```). This indicates (on the writer side) if a sample will be accepted by the actual reader or not. This could be made more generic for proper 'writer side' content filter implementation. However, now it'll only be used by ParticipantVolatileMessageSecure and the filter is hardcoded to ```volatile_secure_data_filter()```. + +So, if ```write_sample_p2p_wrlock_held()``` is called with a proxy reader with a filter, it will get 'send/acked sequences' information between the writer and proxy reader. This is used to determine if gap information has to be send alongside the sample. + +Then, ```write_sample_p2p_wrlock_held()``` will enqueue the sample. + +Just before the submessage is added to the rtps message and send, it is encoded (todo). + + +### Reading + +First things first, the submessage is decoded when the rtps message is received (todo). + +It is received on a builtin reader, so the builtin queue is used and ```builtins_dqueue_handler()``` is called. That will forward the sample to the token exchange functionality, ignoring every sample that isn't related to the related participant (todo). + + +### Gaps on reader side + +The reader remembers the last_seq it knows from every connected proxy writer (```pwr_rd_match::last_seq```). +This is updated when handling heartbeats, gaps and regular messages and used to check if there are gaps. +Normally, the ```last_seq``` of a specific writer is used here. But when the reader knows that the writer uses a 'writer side content filter' (```proxy_writer::uses_filter```), it'll use the the ```last_seq``` that is related to the actual reader/writer match. +It is used to generate the AckNack (which contains gap information) response to the writer. + + +### Gaps on writer side + +The writer remembers which sample sequence it send the last to a specific reader through ```wr_prd_match::lst_seq```. +This is used to determine if a reader has received all relevant samples (through handling of acknack). +It is also used to determine the gap information that is added to samples to a specific reader when necessary. + + +### Heartbeats + +A writer is triggered to send heartbeats once in a while. Normally, that is broadcasted. But, for the volatile secure writer, it has to be send to each reader specifically. The heartbeat submessage that is send to each reader individually is encoded with a reader specific key. This key is generated from the shared secret which was determined during the authentication phase. + +When a writer should send heartbeats, ```handle_xevk_heartbeat()``` is called. For the volatile secure writer, the control is immediately submitted to ```send_heartbeat_to_all_readers()```. This will add heartbeat submessages to an rtps message for every reader it deems necessary. + + +### Reorder + +Normally received samples are placed in the reorder administration of the proxy_writer. However in this case the writer applies a content filter which is specific for each destinated reader. In that case the common reorder administration in the proxy_writer can not be used and the reader specific reorder administration must be used to handle the gap's which will be reader specific. + +
+
+
+=================================================
+Notes
+=================================================
+ +### Trying to put the security participant volatile endpoint implementation into context. + +The following elements are added to the data structures: + +* struct wr_prd_match::lst_seq : Highest seq send to this reader used when filter is applied +* struct pwr_rd_match::last_seq : Reader specific last received sequence number from the writer. +* struct proxy_writer::uses_filter : Indicates that a content-filter is active +* struct proxy_reader::filter : The filter to apply for this specific reader + +Functions added: + +* writer_hbcontrol_p2p : This function creates a heartbeat destined for a specific reader. The volatile secure writer will use an submessage encoding which uses a distinct key for each reader. Therefor a reader specific heartbeat is needed. +* nn_defrag_prune : When a volatile secure reader is deleted then the defragmentation administration could still contain messages destined for this reader. This function removes these messages from the defragmentation administration. +* volatile_secure_data_filter : The filter applied to the secure volatile messages which filters on the destination participant guid. +* write_sample_p2p_wrlock_held : This function writes a message to a particular reader. + +The use of the content-filter for the volatile secure writer implies that for each destination reader which message from the writer history cache is valid and had to be sent. +For messages that do not match this filter a GAP message should be sent to the reader. Each time a message is sent to a specific reader a possible gap message is added. +For the volatile secure writer the sequence number of the last message send to a particular reader is maintained in ```wr_prd_match::lst_seq'''. It is used to determine if a +HEARTBEAT has to send to this particular reader or that the reader has acknowledged all messages. At the reader side the sequence number of the last received message is +maintained in ```pwr_rd_match::last_seq'''. It is used to determine the contents of the ACKNACK message as response to a received HEARTBEAT. +When an ACKNACK (handle_AckNack) is received it is determined which samples should be resent related to the applied filter and for which sequence numbers a GAP message should be sent. diff --git a/docs/makernc.pl b/docs/makernc.pl index 041d71d..3b9cd24 100644 --- a/docs/makernc.pl +++ b/docs/makernc.pl @@ -486,6 +486,7 @@ sub read_config { 'DDSI_INCLUDE_SSL' => 1, 'DDSI_INCLUDE_NETWORK_PARTITIONS' => 1, 'DDSI_INCLUDE_SSM' => 1, + 'DDSI_INCLUDE_SECURITY' => 1, # excluded options 'DDSI_INCLUDE_NETWORK_CHANNELS' => 0, 'DDSI_INCLUDE_BANDWIDTH_LIMITING' => 0); @@ -625,7 +626,7 @@ sub read_config { # skip reference to internal name (either ABSOFF(field), # RELOFF(field,field) or , (the latter being used by # "verbosity") - $rest =~ s/(ABSOFF *\( *[A-Za-z_0-9.]+ *\)|RELOFF *\( *[A-Za-z_0-9.]+ *, *[A-Za-z_0-9]+ *\)|[0-9]+ *, *[0-9]+) *, *//; + $rest =~ s/(ABSOFF *\( *[A-Za-z_0-9.]+ *\)|RELOFF *\( *[A-Za-z_0-9.]+ *, *[A-Za-z_0-9. ]+\)|[0-9]+ *, *[0-9]+) *, *//; # skip init function $rest =~ s/([A-Za-z_0-9]+|0) *, *//; # type hint from conversion function diff --git a/docs/manual/_static/example_governance.xml b/docs/manual/_static/example_governance.xml new file mode 100644 index 0000000..b0cb32e --- /dev/null +++ b/docs/manual/_static/example_governance.xml @@ -0,0 +1,29 @@ + + + + + + + 0 + 230 + + + false + true + NONE + NONE + NONE + + + * + true + true + true + true + SIGN + ENCRYPT + + + + + diff --git a/docs/manual/_static/example_permissions.xml b/docs/manual/_static/example_permissions.xml new file mode 100644 index 0000000..4610555 --- /dev/null +++ b/docs/manual/_static/example_permissions.xml @@ -0,0 +1,39 @@ + + + + + emailAddress=alice@cycloneddssecurity.adlinktech.com,CN=Alice Example,O=Example Organization,OU=Organizational Unit Name,L=Locality Name,ST=OV,C=NL + + + 2020-01-01T01:00:00 + 2120-01-01T01:00:00 + + + + + 0 + 230 + + + + + * + + + * + + + + + * + + + * + + + + DENY + + + \ No newline at end of file diff --git a/docs/manual/_static/pictures/dds_security_configuration_overview.png b/docs/manual/_static/pictures/dds_security_configuration_overview.png new file mode 100644 index 0000000..24df753 Binary files /dev/null and b/docs/manual/_static/pictures/dds_security_configuration_overview.png differ diff --git a/docs/manual/_static/pictures/dds_security_overview.png b/docs/manual/_static/pictures/dds_security_overview.png new file mode 100644 index 0000000..9951bf9 Binary files /dev/null and b/docs/manual/_static/pictures/dds_security_overview.png differ diff --git a/docs/manual/_static/pictures/pki_overview.png b/docs/manual/_static/pictures/pki_overview.png new file mode 100644 index 0000000..138493d Binary files /dev/null and b/docs/manual/_static/pictures/pki_overview.png differ diff --git a/docs/manual/_static/pictures/rtps_message_structure.png b/docs/manual/_static/pictures/rtps_message_structure.png new file mode 100644 index 0000000..fb402a4 Binary files /dev/null and b/docs/manual/_static/pictures/rtps_message_structure.png differ diff --git a/docs/manual/_static/security_by_config.xml b/docs/manual/_static/security_by_config.xml new file mode 100644 index 0000000..947fe78 --- /dev/null +++ b/docs/manual/_static/security_by_config.xml @@ -0,0 +1,19 @@ + + + + + file:/path/to/example_id_ca_cert.pem + file:/path/to/example_alice_cert.pem + file:/path/to/example_alice_priv_key.pem + + + + + + + file:/path/to/example_perm_ca_cert.pem + file:/path/to/example_governance.p7s + file:/path/to/example_permissions.p7s + + + diff --git a/docs/manual/_static/security_by_qos.c b/docs/manual/_static/security_by_qos.c new file mode 100644 index 0000000..86eea84 --- /dev/null +++ b/docs/manual/_static/security_by_qos.c @@ -0,0 +1,21 @@ +dds_qos_t * qos = dds_create_qos(); + +dds_qset_prop(qos, "dds.sec.auth.library.path", "dds_security_auth"); +dds_qset_prop(qos, "dds.sec.auth.library.init", "init_authentication"); +dds_qset_prop(qos, "dds.sec.auth.library.finalize", "finalize_authentication"); +dds_qset_prop(qos, "dds.sec.auth.identity_ca", "file:/path/to/example_id_ca_cert.pem"); +dds_qset_prop(qos, "dds.sec.auth.private_key", "file:/path/to/example_alice_priv_key.pem"); +dds_qset_prop(qos, "dds.sec.auth.identity_certificate", "file:/path/to/example_alice_cert.pem"); + +dds_qset_prop(qos, "dds.sec.crypto.library.path", "dds_security_crypto"); +dds_qset_prop(qos, "dds.sec.crypto.library.init", "init_crypto"); +dds_qset_prop(qos, "dds.sec.crypto.library.finalize", "finalize_crypto"); + +dds_qset_prop(qos, "dds.sec.access.library.path", "dds_security_ac"); +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.access.permissions_ca", "file:/path/to/example_perm_ca_cert.pem"); +dds_qset_prop(qos, "dds.sec.access.governance", "file:/path/to/example_governance.p7s"); +dds_qset_prop(qos, "dds.sec.access.permissions", "file:/path/to/example_permissions.p7s"); + +dds_entity_t participant = dds_create_participant(0, qos, NULL); diff --git a/docs/manual/index.rst b/docs/manual/index.rst index 0d729a9..9def6b8 100644 --- a/docs/manual/index.rst +++ b/docs/manual/index.rst @@ -21,6 +21,7 @@ Welcome to Eclipse Cyclone DDS's documentation! GettingStartedGuide/index ddsc config + security Indices and tables ================== diff --git a/docs/manual/options.md b/docs/manual/options.md index e17d2d5..f8a7aa5 100644 --- a/docs/manual/options.md +++ b/docs/manual/options.md @@ -8,7 +8,7 @@ CycloneDDS configuration ## //CycloneDDS/Domain Attributes: [Id](#cycloneddsdomainid) -Children: [Compatibility](#cycloneddsdomaincompatibility), [Discovery](#cycloneddsdomaindiscovery), [General](#cycloneddsdomaingeneral), [Internal](#cycloneddsdomaininternal), [Partitioning](#cycloneddsdomainpartitioning), [SSL](#cycloneddsdomainssl), [Sizing](#cycloneddsdomainsizing), [TCP](#cycloneddsdomaintcp), [ThreadPool](#cycloneddsdomainthreadpool), [Threads](#cycloneddsdomainthreads), [Tracing](#cycloneddsdomaintracing) +Children: [Compatibility](#cycloneddsdomaincompatibility), [DDSSecurity](#cycloneddsdomainddssecurity), [Discovery](#cycloneddsdomaindiscovery), [General](#cycloneddsdomaingeneral), [Internal](#cycloneddsdomaininternal), [Partitioning](#cycloneddsdomainpartitioning), [SSL](#cycloneddsdomainssl), [Sizing](#cycloneddsdomainsizing), [TCP](#cycloneddsdomaintcp), [ThreadPool](#cycloneddsdomainthreadpool), [Threads](#cycloneddsdomainthreads), [Tracing](#cycloneddsdomaintracing) The General element specifying Domain related settings. @@ -100,8 +100,370 @@ The default setting is "lax". The default value is: "lax". +### //CycloneDDS/Domain/DDSSecurity +Children: [AccessControl](#cycloneddsdomainddssecurityaccesscontrol), [Authentication](#cycloneddsdomainddssecurityauthentication), [Cryptographic](#cycloneddsdomainddssecuritycryptographic) + + +This element is used to configure Cyclone DDS with the DDS Security +specification plugins and settings. + + +#### //CycloneDDS/Domain/DDSSecurity/AccessControl +Children: [Governance](#cycloneddsdomainddssecurityaccesscontrolgovernance), [Library](#cycloneddsdomainddssecurityaccesscontrollibrary), [Permissions](#cycloneddsdomainddssecurityaccesscontrolpermissions), [PermissionsCA](#cycloneddsdomainddssecurityaccesscontrolpermissionsca) + + +This element configures the Access Control plugin of the DDS Security +specification. + + +##### //CycloneDDS/Domain/DDSSecurity/AccessControl/Governance +Text + +URI to the shared Governance Document signed by the Permissions CA in +S/MIME format + +URI schemes: file, data
+ +Examples file URIs: + +file:governance.smime + +file:/home/myuser/governance.smime
+ + + + + + + +. . . + + + + + +... + +------F9A8A198D6F08E1285A292ADF14DD04F + +Content-Type: application/x-pkcs7-signature; name="smime.p7s" + +Content-Transfer-Encoding: base64 + +Content-Disposition: attachment; filename="smime.p7s" + +MIIDuAYJKoZIhv ...al5s= + +------F9A8A198D6F08E1285A292ADF14DD04F-]] + +The default value is: "". + + +##### //CycloneDDS/Domain/DDSSecurity/AccessControl/Library +Attributes: [finalizeFunction](#cycloneddsdomainddssecurityaccesscontrollibraryfinalizefunction), [initFunction](#cycloneddsdomainddssecurityaccesscontrollibraryinitfunction), [path](#cycloneddsdomainddssecurityaccesscontrollibrarypath) + + +This element specifies the library to be loaded as the DDS Security +Access Control plugin. + + +##### //CycloneDDS/Domain/DDSSecurity/AccessControl/Library[@finalizeFunction] +Text + +This element names the finalization function of Access Control plugin. +This function is called to let the plugin release its resources. + +The default value is: "finalize_access_control". + + +##### //CycloneDDS/Domain/DDSSecurity/AccessControl/Library[@initFunction] +Text + +This element names the initialization function of Access Control plugin. +This function is called after loading the plugin library for +instantiation purposes. Init function must return an object that +implements DDS Security Access Control interface. + +The default value is: "init_access_control". + + +##### //CycloneDDS/Domain/DDSSecurity/AccessControl/Library[@path] +Text + +This element points to the path of Access Control plugin library. + +It can be either absolute path excluding file extension ( +/usr/lib/dds_security_ac ) or single file without extension ( +dds_security_ac ). + +If single file is supplied, the library located by way of the current +working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for +Windows systems. + +The default value is: "dds_security_ac". + + +##### //CycloneDDS/Domain/DDSSecurity/AccessControl/Permissions +Text + +URI to the DomainParticipant permissions document signed by the +Permissions CA in S/MIME format + +The permissions document specifies the permissions to be applied to a +domain.
+ +Example file URIs: + +file:permissions_document.p7s + +file:/path_to/permissions_document.p7s + +Example data URI: + + + +The default value is: "". + + +##### //CycloneDDS/Domain/DDSSecurity/AccessControl/PermissionsCA +Text + +URI to a X509 certificate for the PermissionsCA in PEM format. + +Supported URI schemes: file, data + +The file and data schemas shall refer to a X.509 v3 certificate (see +X.509 v3 ITU-T Recommendation X.509 (2005) [39]) in PEM format.
+ +Examples:
+ +file:permissions_ca.pem + +file:/home/myuser/permissions_ca.pem
+ +data:,-----BEGIN CERTIFICATE----- + +MIIC3DCCAcQCCQCWE5x+Z ... PhovK0mp2ohhRLYI0ZiyYQ== + +-----END CERTIFICATE----- + +The default value is: "". + + +#### //CycloneDDS/Domain/DDSSecurity/Authentication +Children: [IdentityCA](#cycloneddsdomainddssecurityauthenticationidentityca), [IdentityCertificate](#cycloneddsdomainddssecurityauthenticationidentitycertificate), [IncludeOptionalFields](#cycloneddsdomainddssecurityauthenticationincludeoptionalfields), [Library](#cycloneddsdomainddssecurityauthenticationlibrary), [Password](#cycloneddsdomainddssecurityauthenticationpassword), [PrivateKey](#cycloneddsdomainddssecurityauthenticationprivatekey), [TrustedCADirectory](#cycloneddsdomainddssecurityauthenticationtrustedcadirectory) + + +This element configures the Authentication plugin of the DDS Security +specification. + + +##### //CycloneDDS/Domain/DDSSecurity/Authentication/IdentityCA +Text + +URI to the X509 certificate [39] of the Identity CA that is the signer of +Identity Certificate. + +Supported URI schemes: file, data + +The file and data schemas shall refer to a X.509 v3 certificate (see +X.509 v3 ITU-T Recommendation X.509 (2005) [39]) in PEM format. + +Examples: + +file:identity_ca.pem + +data:,-----BEGIN CERTIFICATE-----
+ +MIIC3DCCAcQCCQCWE5x+Z...PhovK0mp2ohhRLYI0ZiyYQ==
+ +-----END CERTIFICATE-----
+ + +##### //CycloneDDS/Domain/DDSSecurity/Authentication/IdentityCertificate +Text + +Identity certificate that will be used for identifying all participants +in the OSPL instance.
The content is URI to a X509 certificate signed +by the IdentityCA in PEM format containing the signed public key. + +Supported URI schemes: file, data + +Examples: + +file:participant1_identity_cert.pem + +data:,-----BEGIN CERTIFICATE-----
+ +MIIDjjCCAnYCCQDCEu9...6rmT87dhTo=
+ +-----END CERTIFICATE-----
+ + +##### //CycloneDDS/Domain/DDSSecurity/Authentication/IncludeOptionalFields +Boolean + +The authentication handshake tokens may contain optional fields to be +included for finding interoperability problems. + +If this parameter is set to true the optional fields are included in the +handshake token exchange. + +The default value is: "false". + + +##### //CycloneDDS/Domain/DDSSecurity/Authentication/Library +Attributes: [finalizeFunction](#cycloneddsdomainddssecurityauthenticationlibraryfinalizefunction), [initFunction](#cycloneddsdomainddssecurityauthenticationlibraryinitfunction), [path](#cycloneddsdomainddssecurityauthenticationlibrarypath) + + +This element specifies the library to be loaded as the DDS Security +Access Control plugin. + + +##### //CycloneDDS/Domain/DDSSecurity/Authentication/Library[@finalizeFunction] +Text + +This element names the finalization function of Authentication plugin. +This function is called to let the plugin release its resources. + +The default value is: "finalize_authentication". + + +##### //CycloneDDS/Domain/DDSSecurity/Authentication/Library[@initFunction] +Text + +This element names the initialization function of Authentication plugin. +This function is called after loading the plugin library for +instantiation purposes. Init function must return an object that +implements DDS Security Authentication interface. + +The default value is: "init_authentication". + + +##### //CycloneDDS/Domain/DDSSecurity/Authentication/Library[@path] +Text + +This element points to the path of Authentication plugin library. + +It can be either absolute path excluding file extension ( +/usr/lib/dds_security_auth ) or single file without extension ( +dds_security_auth ). + +If single file is supplied, the library located by way of the current +working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for +Windows systems. + +The default value is: "dds_security_auth". + + +##### //CycloneDDS/Domain/DDSSecurity/Authentication/Password +Text + +A password used to decrypt the private_key. + +The value of the password property shall be interpreted as the Base64 +encoding of the AES-128 key that shall be used to decrypt the private_key +using AES128-CBC. + +If the password property is not present, then the value supplied in the +private_key property must contain the unencrypted private key. + +The default value is: "". + + +##### //CycloneDDS/Domain/DDSSecurity/Authentication/PrivateKey +Text + +URI to access the private Private Key for all of the participants in the +OSPL federation. + +Supported URI schemes: file, data + +Examples: + +file:identity_ca_private_key.pem + +data:,-----BEGIN RSA PRIVATE KEY-----
+ +MIIEpAIBAAKCAQEA3HIh...AOBaaqSV37XBUJg==
+ +-----END RSA PRIVATE KEY-----
+ + +##### //CycloneDDS/Domain/DDSSecurity/Authentication/TrustedCADirectory +Text + +Trusted CA Directory which contains trusted CA certificates as separated +files. + +The default value is: "". + + +#### //CycloneDDS/Domain/DDSSecurity/Cryptographic +Children: [Library](#cycloneddsdomainddssecuritycryptographiclibrary) + + +This element configures the Cryptographic plugin of the DDS Security +specification. + + +##### //CycloneDDS/Domain/DDSSecurity/Cryptographic/Library +Attributes: [finalizeFunction](#cycloneddsdomainddssecuritycryptographiclibraryfinalizefunction), [initFunction](#cycloneddsdomainddssecuritycryptographiclibraryinitfunction), [path](#cycloneddsdomainddssecuritycryptographiclibrarypath) + + +This element specifies the library to be loaded as the DDS Security +Cryptographic plugin. + + +##### //CycloneDDS/Domain/DDSSecurity/Cryptographic/Library[@finalizeFunction] +Text + +This element names the finalization function of Cryptographic plugin. +This function is called to let the plugin release its resources. + +The default value is: "finalize_crypto". + + +##### //CycloneDDS/Domain/DDSSecurity/Cryptographic/Library[@initFunction] +Text + +This element names the initialization function of Cryptographic plugin. +This function is called after loading the plugin library for +instantiation purposes. Init function must return an object that +implements DDS Security Cryptographic interface. + +The default value is: "init_crypto". + + +##### //CycloneDDS/Domain/DDSSecurity/Cryptographic/Library[@path] +Text + +This element points to the path of Cryptographic plugin library. + +It can be either absolute path excluding file extension ( +/usr/lib/dds_security_crypto ) or single file without extension ( +dds_security_crypto ). + +If single file is supplied, the library located by way of the current +working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for +Windows systems. + +The default value is: "dds_security_crypto". + + ### //CycloneDDS/Domain/Discovery -Children: [DSGracePeriod](#cycloneddsdomaindiscoverydsgraceperiod), [DefaultMulticastAddress](#cycloneddsdomaindiscoverydefaultmulticastaddress), [EnableTopicDiscovery](#cycloneddsdomaindiscoveryenabletopicdiscovery), [ExternalDomainId](#cycloneddsdomaindiscoveryexternaldomainid), [MaxAutoParticipantIndex](#cycloneddsdomaindiscoverymaxautoparticipantindex), [ParticipantIndex](#cycloneddsdomaindiscoveryparticipantindex), [Peers](#cycloneddsdomaindiscoverypeers), [Ports](#cycloneddsdomaindiscoveryports), [SPDPInterval](#cycloneddsdomaindiscoveryspdpinterval), [SPDPMulticastAddress](#cycloneddsdomaindiscoveryspdpmulticastaddress), [Tag](#cycloneddsdomaindiscoverytag) +Children: [DSGracePeriod](#cycloneddsdomaindiscoverydsgraceperiod), [DefaultMulticastAddress](#cycloneddsdomaindiscoverydefaultmulticastaddress), [ExternalDomainId](#cycloneddsdomaindiscoveryexternaldomainid), [MaxAutoParticipantIndex](#cycloneddsdomaindiscoverymaxautoparticipantindex), [ParticipantIndex](#cycloneddsdomaindiscoveryparticipantindex), [Peers](#cycloneddsdomaindiscoverypeers), [Ports](#cycloneddsdomaindiscoveryports), [SPDPInterval](#cycloneddsdomaindiscoveryspdpinterval), [SPDPMulticastAddress](#cycloneddsdomaindiscoveryspdpmulticastaddress), [Tag](#cycloneddsdomaindiscoverytag) The Discovery element allows specifying various parameters related to the @@ -132,14 +494,6 @@ Discovery/SPDPMulticastAddress. The default value is: "auto". -#### //CycloneDDS/Domain/Discovery/EnableTopicDiscovery -Boolean - -Do not use. - -The default value is: "true". - - #### //CycloneDDS/Domain/Discovery/ExternalDomainId Text @@ -995,7 +1349,7 @@ is therefore recommended to set it to at least several seconds. Valid values are finite durations with an explicit unit or the keyword 'inf' for infinity. Recognised units: ns, us, ms, s, min, hr, day. -The default value is: "10s". +The default value is: "0s". #### //CycloneDDS/Domain/Internal/RediscoveryBlacklistDuration[@enforce] @@ -1646,6 +2000,8 @@ threads exist: * tev: general timed-event handling, retransmits and discovery; +* fsm: finite state machine thread for handling security handshake; + * xmit.CHAN: transmit thread for channel CHAN; * dq.CHAN: delivery thread for channel CHAN; diff --git a/docs/manual/security.rst b/docs/manual/security.rst new file mode 100644 index 0000000..725de07 --- /dev/null +++ b/docs/manual/security.rst @@ -0,0 +1,801 @@ +.. _`DDS Security`: + +############ +DDS Security +############ + +CycloneDDS is compliant with The Object Management Group (OMG) DDS Security specification. + +This specification defines the Security Model and Service Plugin Interface (SPI) architecture for +compliant DDS implementations. The DDS Security Model is enforced by the invocation of these SPIs +by the DDS implementation. + +.. image:: ./_static/pictures/dds_security_overview.png + :width: 1000 + +The three plugins that comprise the DDS Security Model in CycloneDDS are: + + +**Authentication Service Plugin** + +Provides the means to verify the identity of the application and/or user that invokes operations +on DDS. Includes facilities to perform mutual authentication between participants and establish +a shared secret. + +**AccessControl Service Plugin** + +Provides the means to enforce policy decisions on what DDS related operations an authenticated +user can perform. For example, which domains it can join, which Topics it can publish or +subscribe to, etc. + +**Cryptographic Service Plugin** + +Implements (or interfaces with libraries that implement) all cryptographic operations including +encryption, decryption, hashing, digital signatures, etc. This includes the means to derive keys +from a shared secret. + +---- + +CycloneDDS provides built-in implementations of these plugins. Authentication uses PKI +(Public Key Infrastructure) with a pre-configured shared Certificate Authority, RSA is used for +authentication and Diffie-Hellman is used for key exchange. AccessControl use Permissions document +signed by shared Certificate Authority. Cryptography uses AES-GCM (AES using Galois Counter Mode) +for encryption and AES-GMAC for message authentication. + +Security plugins are dynamically loaded where the locations are defined in CycloneDDS +configuration or Participant QoS settings. + + +******************************************************* +Brief information about PKI (public key infrastructure) +******************************************************* + +The comprehensive system required to provide public-key encryption and digital signature services +is known as a public-key infrastructure (PKI). The purpose of a PKI is to manage keys and +certificates. By managing keys and certificates through a PKI, an organization establishes and +maintains a trustworthy networking environment. + +Public Key Cryptography: Each user has a key pair, generated during the initial certificate +deployment process, that is comprised of a public key, which is shared, and a private key, which +is not shared. Data is encrypted with the user’s public key and decrypted with their private key. +Digital signatures, used for non-repudiation, authentication and data integrity, are also generated +using public key cryptography. + +**Identity Certificate** + +This is an electronic document used to prove the ownership of a public key. The certificate +includes information about the key, information about the identity of its owner (called the +subject), and the digital signature of an entity that has verified the certificate's contents +(called the issuer). If the signature is valid, and the software examining the certificate +trusts the issuer, then it can use that key to communicate securely with the certificate's +subject. + +**Certificate Authority** + +This issues user certificates and acts as the chief agent of trust. When issuing a certificate +to a user, the CA signs the certificate with its private key in order to validate it. During +electronic transactions the CA also confirms that certificates are still valid. Certificates +may be revoked for various reasons. For example, a user may leave the organization or they may +forget their secret passphrase, the certificate may expire or become corrupt. This process is +usually accomplished through the use of a Certificate Revocation List (CRL) which is a list of +the certificates that have been revoked. Only the certificates that have been revoked appear on +this list. + +**Subject of Identity Certificate** + +This is the identity to be secured. It contains information such as common name (CN), +organization (OU), state (ST) and country (C). + +**Subject Name** + +This is aka distinguished name and is the string representation of certificate subject. + +ie: emailAddress=alice\@adlink.ist,CN=Alice,OU=IST,O=ADLink,ST=OV,C=NL + + +************************* +PKI Usage in DDS Security +************************* + +.. image:: ./_static/pictures/pki_overview.png + :width: 1000 + +Alice and Bob are the DDS participants who have their private and public keys. Identitity +Certificate Authority (ID CA) has its own self-signed certificate (IdentityCA in the diagram). +ID CA gets Alice's subject information and public key and generates an IdentityCertificate for her. +Alice's certificate includes her public key and certificate of ID CA; so that her certificate can +be verified if it is really issued by ID CA. + +Access Control is configured with governance and permissions files. Governance file defines the +security behavior of domains and topics. Permissions file contains the permissions of the domain +participant, topics, readers and writers, binds them to identity certificate by subject name +(distinguished name). + +Governance files and Permissions files are signed by Permission CA. Signed documents also +contains Permissions CA certificate; so that they can be verified if they are really issued +by Permissions CA. + +Authenticated participants perform a handshake with each other and generate a shared key by +Diffie-Hellman key exchange. This shared key is used for encrypting/decrypting data with AES. + +During the handshake Alice checks Bob's certificate and Bob's Permissions file if they are really +issued by the ID CA certificate and Permissions CA Certificate that **she** has. Also Bob checks +Alice's certificate and Alice's Permissions file if they are really issued by the ID CA certificate +and Permissions CA that **he** has. +Permissions files can contain permissions for several identities; so subject name of identity +certificate exist in permissions file to establish a binding between identity and its permissions. + +There are several ways to set up the certificates and signed configuration files to be used with +Cyclone DDS Security. One of them is using OpenSSL, which is described in section +`Creating certificates using OpenSSL`_. + +************* +Configuration +************* + +.. image:: ./_static/pictures/dds_security_configuration_overview.png + :width: 1000 + + +The configuration of DDS Security is split up into two parts. + +- `Plugins Configuration`_ +- `Access Control Configuration`_ + + +Plugins Configuration +********************* + +CycloneDDS gets the security configuration from XML configuration elements or from +the participant QoS policies as stated in the DDS Security specification. + +This behavior allows applications to use DDS Security without recompiling the binaries. +Only supplying a new configuration with DDS Security enabled is enough to switch from a +non-secure to a secure deployment. The configuration is at domain level, which means +that all participants created for that domain receive the same DDS security settings. + +The configuration options for a domain are bundled in the ``DDSSecurity`` configuration +section in the CycloneDDS configuration. Every DDS Security plugin has its own configuration +sub-section. + +.. _`Authentication Properties`: + +========================= +Authentication Properties +========================= + +To enable authentication for a node, it has to be configured with an identity certificate +(``DDSSecurity/Authentication/IdentityCertificate``). This identity certificate is used to +authenticate all participants of that particular CycloneDDS domain. Associated with the +identity certificate is the corresponding private key +(``DDSSecurity/Authentication/PrivateKey``). The private key may either be a 2048-bit RSA +or a 256-bit Elliptic Curve Key with a prime256v1 curve. + +The certificate of identity CA, which is the issuer of the node's identity certificate, +is configured in ``DDSSecurity/Authentication/IdentityCA``. The public key of the +identity CA (as part of its certificate) shall either be a 2048-bit RSA key or a 256-bit +Elliptic Curve Key for the prime256v1 curve. The identity CA certificate can be a +self-signed certificate. + +The identity certificate, private key and the identity CA should be a X509 document in PEM +format. It may either be specified directly in the configuration file (as CDATA, prefixed +with ``data:,``) or the configuration file should contain a reference to a corresponding +file (prefixed with ``file:``). + +Optionally the private key could be protected by a password +(``DDSSecurity/Authentication/Password``). + +Furthermore the CycloneDDS configuration allows configuring a directory containing additional +identity CA's which are used to verify the identity certificates that are received from remote instances +(``DDSSecurity/Authentication/TrustedCADirectory``). This option allows multiple identity +CAs throughout the system. + +.. _`Access Control Properties`: + +========================= +Access Control Properties +========================= + +A governance document (``DDSSecurity/AccessControl/Governance``), a permissions document +(``DDSSecurity/AccessControl/Permissions``) and the permissions CA certificate +(``DDSSecurity/AccessControl/PermissionsCA``) are required for the access control plugin. +Similar to the authentication plugin properties, these values can be provided as CDATA or +by using a path to a file. + + +.. _`Cryptography Properties`: + +======================= +Cryptography Properties +======================= + +The cryptography plugin has no properties in the configuration. + + +.. _`Access Control Configuration`: + +Access Control Configuration +**************************** + +Access Control configuration consists of Governance document and Permissions document. +Both governance and permissions files must be signed by the Permissions CA in S/MIME format. +Participants use their own permissions CA to validate remote permissions. So, all permissions CA +Certificates must be the same for all participants. + +The signed document should use S/MIME version 3.2 format as defined in IETF RFC 5761 using +SignedData Content Type (section 2.4.2 of IETF RFC 5761) formatted as multipart/signed (section +3.4.3 of IETF RFC 5761). This corresponds to the mime-type application/pkcs7-signature. +Additionally the signer certificate should be be included within the signature. + + +=================== +Governance Document +=================== + +The Governance document defines the security behavior of domains and topics. It is an XML document +and its format is specified in OMG DDS Security Version 1.1 Section 9.4.1.2.3. + +This section describes the properties that can be specified in a permissions document. An example +of a governance document is provided in `Create a signed governance document`_. The options +that are specified in Governance document must match with the remote node to establishing +communication. + + +Protection Kinds +================ + +The domain governance document provides a means for the application to configure the kinds of +cryptographic transformation applied to the complete RTPS Message, certain RTPS SubMessages, and +the SerializedPayload RTPS submessage element that appears within the Data. + +.. image:: ./_static/pictures/rtps_message_structure.png + :width: 300 + +The configuration allows specification of five protection levels: NONE, SIGN, ENCRYPT, +SIGN_WITH_ORIGIN_AUTHENTICATION and ENCRYPT_WITH_ORIGIN_AUTHENTICATION. + +**NONE** + indicates no cryptographic transformation is applied. + +**SIGN** + indicates the cryptographic transformation shall be purely a message authentication code (MAC), + that is, no encryption is performed. + +**ENCRYPT** + indicates the cryptographic transformation shall be an encryption followed by a message + authentication code (MAC) computed on the ciphertext, also known as Encrypt-then-MAC. + +**SIGN_WITH_ORIGIN_AUTHENTICATION** + indicates the cryptographic transformation shall be purely a set of message authentication codes + (MAC), that is, no encryption is performed. This cryptographic transformation shall create a + first “common authenticationcode” similar to the case where Protection Kind is SIGN. In addition + the cryptographic transformation shall create additional authentication codes, each produced with + a different secret key. The additional MACs prove to the receiver that the sender originated the + message, preventing other receivers from impersonating the sender. + +**ENCRYPT_WITH_ORIGIN_AUTHENTICATION** + indicates the cryptographic transformation shall be an encryption followed by a message + authentication code (MAC) computed on the ciphertext, followed by additional authentication + codes, Each of the additional authentication codes shall use a different secret key. The + encryption and first (common) authentication code is similar to ones produced when the Protection + Kind is ENCRYPT. The additional authentication codes are similar to the ones produced when the + Protection Kind is SIGN_WITH_ORIGIN_AUTHENTICATION. + + +Participant attributes +====================== + +**Allow Unauthenticated Participants** + This is used for allowing communication with non-secure participants. If this option is enabled, + secure participant can communicate with non-secure participant by only non-protected topics. + +**Enable Join Access Control** + If this option is enabled, remote participant permissions are checked if its subject name is + allowed to create a topic anyhow. + +**Discovery Protection Kind** + Protection attribute for discovery communication when it is enabled for topic. Please see the + DDS Security specification document for available options. + +**Liveliness Protection Kind** + Protection attribute for liveliness communication when it is enabled for topic. Please see the + DDS Security specification document for available options. + +**RTPS Protection Kind** + Protection attribute for all messages on the wire. Please see the DDS Security specification + document for available options. If encryption is selected for RTPS, there is no need to encrypt + submessages (metadata_protection_kind) and payloads (data_protection_kind) which are defined in + topic settings. + + +Topic Attributes +================ + +**Enable Discovery protection:** + If enabled, discovery is protected according to Discovery Protection Kind attribute of + corresponding participant. + +**Enable Liveliness protection:** + If enabled, liveliness is protected according to Liveliness Protection Kind attribute of + corresponding participant. + +**Enable Read Access Control:** + If enabled, the permissions document is checked if the participant is allowed to create + a datareader for the related topic. + +**Enable Write Access Control:** + If enabled, the permissions document is checked if the participant is allowed to create + a datawriter for the related topic. + +**Metadata protection Kind:** + Protection attribute for submessages. + +**Data protection Kind:** + Protection attribute for data payload. + +There are different settings for different domain ranges. The domain rules are evaluated in the +same order as they appear in the document. A rule only applies to a particular DomainParticipant +if the domain Section matches the DDS domain_id to which the participant belongs. If multiple +rules match, the first rule that matches is the only one that applies. + +The topic access rules are evaluated in the same order as they appear within the + Section. If multiple rules match the first rule that matches is the only one +that applies. + +fnmatch pattern matching can be used for topic expressions including the following patterns + +.. _`fnmatch pattern matching`: + ++----------+----------------------------------+ +|Pattern |Meaning | ++==========+==================================+ +| \* | matches everything | ++----------+----------------------------------+ +| \? | matches any single character | ++----------+----------------------------------+ +| [seq] | matches any character in seq | ++----------+----------------------------------+ +| [!seq] | matches any character not in seq | ++----------+----------------------------------+ + + +==================== +Permissions Document +==================== + +The permissions document is an XML document containing the permissions of the domain participant +and binding them to the subject name of the DomainParticipant as defined in the identity +certificate. Its format is specified in OMG DDS Security Version 1.1 Section 9.4.1.3. + +This section describes the properties that can be specified in a permissions document. An example +of a permissions document is provided in `Creating a signed permissions document`_. + + +Validity period +=============== + +It is checked before creating participant. Validity period is also checked during handshake with +remote participant; expired remote permissions document prevents communications to be established. + + +Subject Name +============ + +The subject name must match with Identity Certificate subject. It is checked during create +participant and during handshake with remote participant. Use the following openssl command to get +subject name from identity certificate: + +``openssl x509 -noout -subject -nameopt RFC2253 -in `` + + +Rules +===== + +Participant permissions are defined by set of rules. The rules are applied in the same order +that appear in the document. If the criteria for the rule matches the domain_id join and/or publish +or subscribe operation that is being attempted, then the allow or deny decision is applied. +If the criteria for a rule does not match the operation being attempted, the evaluation +shall proceed to the next rule. If all rules have been examined without a match, then the +decision specified by the “default” rule is applied. The default rule, if present, must +appear after all allow and deny rules. If the default rule is not present, the +implied default decision is DENY. The matching criteria for each rule specify the domain_id, +topics (published and subscribed), the partitions (published and subscribed), and the data-tags +associated with the DataWriter and DataReader. + +For the grant to match there shall be a match of the topics, partitions, and data-tags criteria. +This is interpreted as an AND of each of the criteria. For a specific criterion to match +(e.g., ) it is enough that one of the topic expressions listed matches (i.e., an OR of +the expressions with the section). + +`fnmatch pattern matching`_ can be used for topic expressions and partition expressions. + + +Logging and tracing +******************* + +The security implementation uses the standard logging and tracing mechanism in CycloneDDS. +The following is written to log and trace: + +- Configuration errors such as plugin library files, certificate files, governance and permissions + files that can not be found on filesystem. +- Permission errors such as denied permission for creating writer of a topic. +- Attribute mismatch errors such as mismatches of security attributes between participants, topics, + readers and writers. +- Integrity errors such as Permissions file-Permissions CA and Identity Cert-Identity CA integrity. + +Local subscription, publication and topic permission errors are written as errors. +Remote participation, subscription and publication permission errors are written to log as +warning messages. + + +Data Communication And Handshake Process +**************************************** + +Authentication handshake between participants starts after participant discovery. If a reader and +a writer created during that period, their match will be delayed until after the handshake succeeds. +This means, during the handshake process, volatile data will be lost, just like there is no reader. + +After publication match, the encryption / decryption keys are exchanged between reader and writer. +Best-effort data that are sent during this exchange will be lost, however reliable data will be +resent. + + +DDS Secure Discovery +******************** + +Just like normal operation, Cyclone DDS discovers remote participants, topics, readers and writers. +However, when DDS Security is enabled, it is more complex and will take a longer time (due to the +handshaking that is required). The effort to perform discovery grows quadratically in the number of +nodes. This can become a problem if the system contains a number of slow platforms or is large. + + +Proprietary builtin endpoints +***************************** + +The DDS standard contains some builtin endpoints. A few are added by the DDS Security +specification. The behaviour of all these builtin endpoints are specified (and thus are be +handled by the plugins that implement the DDS Security specification), meaning that they +don't have to be present in the Governance or Permissions documents and the users don't +have to be bothered with them. + +A few of these builtin endpoints slave according to the within +the Governance document. In short, related submessages are protected according to the value +of . This protects meta information that is send during the +discovery phase. + + +******************* +DataTag Permissions +******************* + +Data Tags provide an extra (optional) level of identification. This can mean f.i. that +a certain reader is not allowed to read data from writer A but it is allowed to read from +writer B (all the same topic). + +This optional feature is not yet supported. + + +.. _`Example configuration`: + +********************* +Example configuration +********************* + +This sections show an example configuration for DDS Security in Cyclone DDS. First step is +creating the required CA and identity certificates. Then a governance and permissions document +is created to configure access control. Next an example configuration (XML) that +is using these assets is shown, and a code fragment that shows how to set the security +properties by using the participant QoS. + + +.. _`Creating certificates using OpenSSL`: + +Creating certificates using OpenSSL +*********************************** + +This section describes how to generate a set of CA and identity certificates using OpenSSL, +and how to use OpenSSL to sign the governance and access control configuration files. + +First step is generation of the CA for identity management (authentication). First we create the +private key for the CA by: + +.. code-block:: bash + + openssl genrsa -out example_id_ca_priv_key.pem 2048 + +Next we can generate the certificate for the identity CA (which is in this case a self-signed +certificate): + +.. code-block:: bash + + openssl req -x509 -key example_id_ca_priv_key.pem -out example_id_ca_cert.pem -days 3650 -subj "/C=NL/ST=OV/L=Locality Name/OU=Example OU/O=Example ID CA Organization/CN=Example ID CA/emailAddress=authority@cycloneddssecurity.adlinktech.com" + +We repeat these steps for generating the private key of the permissions CA (used for +signing the AccessControl configiguration files): + +.. code-block:: bash + + openssl genrsa -out example_perm_ca_priv_key.pem 2048 + +And the self-signed certificate for the permissions CA: + +.. code-block:: bash + + openssl req -x509 -key example_perm_ca_priv_key.pem -out example_perm_ca_cert.pem -days 3650 -subj "/C=NL/ST=OV/L=Locality Name/OU=Example OU/O=Example CA Organization/CN=Example Permissions CA/emailAddress=authority@cycloneddssecurity.adlinktech.com" + +============================== +Create an Identity Certificate +============================== + +Now that we have set up the CA for identity management, we can create an identity certificate +signed by this CA and the private key corresponding to this identity. Here we are creating +a private key and certificate for identity named Alice. These steps need to be repeated for each +identity in the system. + +Generating the private key for Alice's identity: + +.. code-block:: bash + + openssl genrsa -out example_alice_priv_key.pem 2048 + +Now we create a 'certificate signing request' (CSR) to request the identity CA to generate a certificate: + +.. code-block:: bash + + openssl req -new -key example_alice_priv_key.pem -out example_alice.csr -subj "/C=NL/ST=OV/L=Locality Name/OU=Organizational Unit Name/O=Example Organization/CN=Alice Example/emailAddress=alice@cycloneddssecurity.adlinktech.com" + +Next Alice's identity certificate is created: + +.. code-block:: bash + + openssl x509 -req -CA example_id_ca_cert.pem -CAkey example_id_ca_priv_key.pem -CAcreateserial -days 3650 -in example_alice.csr -out example_alice_cert.pem + + +Now the file 'example_alice_cert.pem' can be used as ``IdentityCertificate`` in the DDS Security +authentication configuration and 'example_alice_priv_key.pem' for the ``PrivateKey`` setting. The +certificate of the CA used for signing this identity, 'example_id_ca_cert.pem' in this example, +should be used for the ``IdentityCA`` configuration setting. + + +.. _`Create a signed governance document`: + +=================================== +Create a signed governance document +=================================== + +An example of a governance document that is using signing for submessage and encrypted payload: + +.. literalinclude:: _static/example_governance.xml + :linenos: + :language: xml + +As mentioned before, the governance document needs to be signed by the permissions CA +that was created above. This can be done by using this openssl command: + +.. code-block:: bash + + openssl smime -sign -in example_governance.xml -text -out example_governance.p7s -signer example_perm_ca_cert.pem -inkey example_perm_ca_priv_key.pem + + +.. _`Creating a signed permissions document`: + +====================================== +Creating a signed permissions document +====================================== + +The permissions document is an XML document that contains the permissions of the participant and +binds them to the subject name of the identity certificate (distinguished name) for the participant +as defined in the DDS:Auth:PKI-DH authentication plugin. + +An example of a permissions document: + +.. literalinclude:: _static/example_permissions.xml + :linenos: + :language: xml + +This document also needs to be signed by the permissions CA: + +.. code-block:: bash + + openssl smime -sign -in example_permissions.xml -text -out example_permissions.p7s -signer example_perm_ca_cert.pem -inkey example_perm_ca_priv_key.pem + + +Example DDS Security configuration +********************************** + +With the above steps we have all certificates and documents that are required when configuring +security. In the next two sections, both configuring security by properties and configuring +security by DDS configuration are covered. + +====================================== +Security properties in participant QoS +====================================== + +This code fragment shows how to set the security properties to a QoS object and use this QoS +when creating a participant: + +.. literalinclude:: _static/security_by_qos.c + :linenos: + :language: c + + +=========================================== +Configure security in Cyclone configuration +=========================================== + +As an alternative for using the QoS, security settings can also be applied using the CycloneDDS +configuration XML. In case both QoS and the configuration XML contain security settings, the values +from the QoS will be used and the security settings in the configuration XML are ignored. + +The following XML fragment shows how to set security settings through configuration: + +.. literalinclude:: _static/security_by_config.xml + :linenos: + :language: xml + +To use this configuration file for an application, set the CYCLONEDDS_URI environment +variable to this config file: + +.. code-block:: bash + + export CYCLONEDDS_URI=/path/to/secure_config.xml + +Bacause this example configuration uses the attribute ``id=any`` for the ``domain`` element, any participant +that is created (which implicitly creates a domain) in an application using this configuration gets +these security settings. + +*************************** +External Plugin Development +*************************** + +DDS Security consists of three plugins (authentication, cryptography and access control). +CycloneDDS comes with built-in security plugins that comply with OMG DDS Security specification. +The plugins are loaded in the run-time. However, you can also implement your own custom plugin by +implementing the given API according to OMG DDS Security specification. +You can implement all of the plugins or just one of them. + +The followings are the key points for implementing you own plugin: + + +Interface +********* + +Implement all plugin specific functions with exactly same prototype. Plugin specific function +interfaces are in dds_security_api_access_control.h, dds_security_api_authentication.h and +dds_security_api_cryptography.h header files accordingly. + + +Init and Finalize +***************** + +A plugin should have an init and a finalize functions. plugin_init and plugin_finalize +interfaces are given in dds_security_api.h header file and function should be same as in +configuration file. +Init function is called once, just after the plugin is loaded. Finalize function is +called once, just before the plugin is unloaded. + +Inter Plugin Communication +************************** + +There is a shared object (*DDS_Security_SharedSecretHandle*) within authentication and +cryptography plugins. If you want to implement only one of them and use the builtin for the +other one, you have to get or provide the shared object properly. +*DDS_Security_SharedSecretHandle* is the integer representation of +*DDS_Security_SharedSecretHandleImpl* struct object. Cryptography plugin gets the +*DDS_Security_SharedSecretHandle* from authentication plugin and casts to +*DDS_Security_SharedSecretHandleImpl* struct. Then all needed information can be retieved +through *DDS_Security_SharedSecretHandleImpl* struct: + +:: + + typedef struct DDS_Security_SharedSecretHandleImpl { + DDS_Security_octet* shared_secret; + DDS_Security_long shared_secret_size; + DDS_Security_octet challenge1[DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE]; + DDS_Security_octet challenge2[DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE]; + + } DDS_Security_SharedSecretHandleImpl; + + +Error Codes +*********** + +Most of the plugin functions have parameter for reporting exception. The following exception +codes should be used in the reported exception data according to the situation. +dds_security_api_err.h header file contains the code and message constants. + ++-------+----------------------------------------------------------------+ +| Code | Message | ++=======+================================================================+ +| 0 | (OK) | ++-------+----------------------------------------------------------------+ +| 100 | Can not generate random data | ++-------+----------------------------------------------------------------+ +| 110 | Identity empty | ++-------+----------------------------------------------------------------+ +| 111 | Participant Crypto Handle empty | ++-------+----------------------------------------------------------------+ +| 112 | Permission Handle empty | ++-------+----------------------------------------------------------------+ +| 113 | Invalid Crypto Handle | ++-------+----------------------------------------------------------------+ +| 114 | Invalid argument | ++-------+----------------------------------------------------------------+ +| 115 | Invalid Crypto token | ++-------+----------------------------------------------------------------+ +| 116 | Invalid parameter | ++-------+----------------------------------------------------------------+ +| 117 | File could not be found, opened or is empty, path: %s | ++-------+----------------------------------------------------------------+ +| 118 | Unknown or unexpected transformation kind | ++-------+----------------------------------------------------------------+ +| 119 | Message cannot be authenticated, incorrect signature | ++-------+----------------------------------------------------------------+ +| 120 | Can not open trusted CA directory | ++-------+----------------------------------------------------------------+ +| 121 | Identity CA is not trusted | ++-------+----------------------------------------------------------------+ +| 122 | Certificate start date is in the future | ++-------+----------------------------------------------------------------+ +| 123 | Certificate expired | ++-------+----------------------------------------------------------------+ +| 125 | Certificate authentication algorithm unknown | ++-------+----------------------------------------------------------------+ +| 126 | Failed to allocate internal structure | ++-------+----------------------------------------------------------------+ +| 127 | Failed to parse PKCS7 SMIME document | ++-------+----------------------------------------------------------------+ +| 128 | Property is missing: (%s) | ++-------+----------------------------------------------------------------+ +| 129 | Permissions document is invalid | ++-------+----------------------------------------------------------------+ +| 130 | Governance document is invalid | ++-------+----------------------------------------------------------------+ +| 131 | Operation is not permitted in this state | ++-------+----------------------------------------------------------------+ +| 132 | Remote permissions document is not available | ++-------+----------------------------------------------------------------+ +| 133 | Certificate is invalid | ++-------+----------------------------------------------------------------+ +| 134 | Certificate type is not supported | ++-------+----------------------------------------------------------------+ +| 135 | Governance property is required | ++-------+----------------------------------------------------------------+ +| 136 | Permissions CA property is required | ++-------+----------------------------------------------------------------+ +| 137 | Can not parse governance file | ++-------+----------------------------------------------------------------+ +| 138 | Can not parse permissions file | ++-------+----------------------------------------------------------------+ +| 139 | Could not find permissions for topic | ++-------+----------------------------------------------------------------+ +| 140 | Could not find domain %d in permissions | ++-------+----------------------------------------------------------------+ +| 141 | Could not find domain %d in governance | ++-------+----------------------------------------------------------------+ +| 142 | Could not find %s topic attributes for domain(%d) in governance| ++-------+----------------------------------------------------------------+ +| 143 | PluginClass in remote token is incompatible | ++-------+----------------------------------------------------------------+ +| 144 | MajorVersion in remote token is incompatible | ++-------+----------------------------------------------------------------+ +| 145 | Access denied by access control | ++-------+----------------------------------------------------------------+ +| 146 | Subject name is invalid | ++-------+----------------------------------------------------------------+ +| 147 | Permissions validity period expired for %s | ++-------+----------------------------------------------------------------+ +| 148 | Permissions validity period has not started yet for %s | ++-------+----------------------------------------------------------------+ +| 149 | Could not find valid grant in permissions | ++-------+----------------------------------------------------------------+ +| 150 | Unsupported URI type: %s | ++-------+----------------------------------------------------------------+ +| 151 | The payload is not aligned at 4 bytes | ++-------+----------------------------------------------------------------+ +| 152 | Cannot open trusted CA directory: maximum number exceeded | ++-------+----------------------------------------------------------------+ +| 200 | Undefined Error Message | ++-------+----------------------------------------------------------------+ + +.. EoF diff --git a/etc/cyclonedds.rnc b/etc/cyclonedds.rnc index 3992df2..0898f32 100644 --- a/etc/cyclonedds.rnc +++ b/etc/cyclonedds.rnc @@ -80,7 +80,318 @@ though there is no good reason not to. element StandardsConformance { ("lax"|"strict"|"pedantic") }? - }? + }* + & [ a:documentation [ xml:lang="en" """ +

This element is used to configure Cyclone DDS with the DDS Security +specification plugins and settings.

""" ] ] + element DDSSecurity { + [ a:documentation [ xml:lang="en" """ +

This element configures the Access Control plugin of the DDS Security +specification.

""" ] ] + element AccessControl { + [ a:documentation [ xml:lang="en" """ +

URI to the shared Governance Document signed by the Permissions CA in +S/MIME format

+ +

URI schemes: file, data


+ +

Examples file URIs:

+ +

file:governance.smime

+ +

file:/home/myuser/governance.smime


+ +

+ +

Content-Type: multipart/signed; +protocol="application/x-pkcs7-signature"; micalg="sha-256"; +boundary="----F9A8A198D6F08E1285A292ADF14DD04F"

+ +

This is an S/MIME signed message

+ +

------F9A8A198D6F08E1285A292ADF14DD04F

+ +

+ +

+ +

xsi:noNamespaceSchemaLocation="omg_shared_ca_governance.xsd">

+ +

+ +

. . .

+ +

+ +

+ +

...

+ +

------F9A8A198D6F08E1285A292ADF14DD04F

+ +

Content-Type: application/x-pkcs7-signature; name="smime.p7s"

+ +

Content-Transfer-Encoding: base64

+ +

Content-Disposition: attachment; filename="smime.p7s"

+ +

MIIDuAYJKoZIhv ...al5s=

+ +

------F9A8A198D6F08E1285A292ADF14DD04F-]]

The +default value is: "".

""" ] ] + element Governance { + text + }? + & [ a:documentation [ xml:lang="en" """ +

This element specifies the library to be loaded as the DDS Security +Access Control plugin.

""" ] ] + element Library { + [ a:documentation [ xml:lang="en" """ +

This element names the finalization function of Access Control plugin. +This function is called to let the plugin release its +resources.

The default value is: +"finalize_access_control".

""" ] ] + attribute finalizeFunction { + text + }? + & [ a:documentation [ xml:lang="en" """ +

This element names the initialization function of Access Control +plugin. This function is called after loading the plugin library for +instantiation purposes. Init function must return an object that +implements DDS Security Access Control interface.

The default value +is: "init_access_control".

""" ] ] + attribute initFunction { + text + }? + & [ a:documentation [ xml:lang="en" """ +

This element points to the path of Access Control plugin library.

+ +

It can be either absolute path excluding file extension ( +/usr/lib/dds_security_ac ) or single file without extension ( +dds_security_ac ).

+ +

If single file is supplied, the library located by way of the current +working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for +Windows systems.

The default value is: +"dds_security_ac".

""" ] ] + attribute path { + text + }? + }? + & [ a:documentation [ xml:lang="en" """ +

URI to the DomainParticipant permissions document signed by the +Permissions CA in S/MIME format

+ +

The permissions document specifies the permissions to be applied to a +domain.


+ +

Example file URIs:

+ +

file:permissions_document.p7s

+ +

file:/path_to/permissions_document.p7s

+ +

Example data URI:

+ +

The +default value is: "".

""" ] ] + element Permissions { + text + }? + & [ a:documentation [ xml:lang="en" """ +

URI to a X509 certificate for the PermissionsCA in PEM format.

+ +

Supported URI schemes: file, data

+ +

The file and data schemas shall refer to a X.509 v3 certificate (see +X.509 v3 ITU-T Recommendation X.509 (2005) [39]) in PEM format.


+ +

Examples:


+ +

file:permissions_ca.pem

+ +

file:/home/myuser/permissions_ca.pem


+ +

data:,-----BEGIN CERTIFICATE-----

+ +

MIIC3DCCAcQCCQCWE5x+Z ... PhovK0mp2ohhRLYI0ZiyYQ==

+ +

-----END CERTIFICATE-----

The default value is: +"".

""" ] ] + element PermissionsCA { + text + }? + }? + & [ a:documentation [ xml:lang="en" """ +

This element configures the Authentication plugin of the DDS Security +specification.

""" ] ] + element Authentication { + [ a:documentation [ xml:lang="en" """ +

URI to the X509 certificate [39] of the Identity CA that is the signer +of Identity Certificate.

+ +

Supported URI schemes: file, data

+ +

The file and data schemas shall refer to a X.509 v3 certificate (see +X.509 v3 ITU-T Recommendation X.509 (2005) [39]) in PEM format.

+ +

Examples:

+ +

file:identity_ca.pem

+ +

data:,-----BEGIN CERTIFICATE-----
+ +MIIC3DCCAcQCCQCWE5x+Z...PhovK0mp2ohhRLYI0ZiyYQ==
+ +-----END CERTIFICATE-----

""" ] ] + element IdentityCA { + text + } + & [ a:documentation [ xml:lang="en" """ +

Identity certificate that will be used for identifying all +participants in the OSPL instance.
The content is URI to a X509 +certificate signed by the IdentityCA in PEM format containing the signed +public key.

+ +

Supported URI schemes: file, data

+ +

Examples:

+ +

file:participant1_identity_cert.pem

+ +

data:,-----BEGIN CERTIFICATE-----
+ +MIIDjjCCAnYCCQDCEu9...6rmT87dhTo=
+ +-----END CERTIFICATE-----

""" ] ] + element IdentityCertificate { + text + } + & [ a:documentation [ xml:lang="en" """ +

The authentication handshake tokens may contain optional fields to be +included for finding interoperability problems. + +If this parameter is set to true the optional fields are included in the +handshake token exchange.

The default value is: +"false".

""" ] ] + element IncludeOptionalFields { + xsd:boolean + }? + & [ a:documentation [ xml:lang="en" """ +

This element specifies the library to be loaded as the DDS Security +Access Control plugin.

""" ] ] + element Library { + [ a:documentation [ xml:lang="en" """ +

This element names the finalization function of Authentication plugin. +This function is called to let the plugin release its +resources.

The default value is: +"finalize_authentication".

""" ] ] + attribute finalizeFunction { + text + }? + & [ a:documentation [ xml:lang="en" """ +

This element names the initialization function of Authentication +plugin. This function is called after loading the plugin library for +instantiation purposes. Init function must return an object that +implements DDS Security Authentication interface.

The default value +is: "init_authentication".

""" ] ] + attribute initFunction { + text + }? + & [ a:documentation [ xml:lang="en" """ +

This element points to the path of Authentication plugin library.

+ +

It can be either absolute path excluding file extension ( +/usr/lib/dds_security_auth ) or single file without extension ( +dds_security_auth ).

+ +

If single file is supplied, the library located by way of the current +working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for +Windows systems.

The default value is: +"dds_security_auth".

""" ] ] + attribute path { + text + }? + }? + & [ a:documentation [ xml:lang="en" """ +

A password used to decrypt the private_key.

+ +The value of the password property shall be interpreted as the Base64 +encoding of the AES-128 key that shall be used to decrypt the private_key +using AES128-CBC.

+ +If the password property is not present, then the value supplied in the +private_key property must contain the unencrypted private key.

The +default value is: "".

""" ] ] + element Password { + text + }? + & [ a:documentation [ xml:lang="en" """ +

URI to access the private Private Key for all of the participants in +the OSPL federation.

+ +

Supported URI schemes: file, data

+ +

Examples:

+ +

file:identity_ca_private_key.pem

+ +

data:,-----BEGIN RSA PRIVATE KEY-----
+ +MIIEpAIBAAKCAQEA3HIh...AOBaaqSV37XBUJg==
+ +-----END RSA PRIVATE KEY-----

""" ] ] + element PrivateKey { + text + } + & [ a:documentation [ xml:lang="en" """ +

Trusted CA Directory which contains trusted CA certificates as +separated files.

The default value is: "".

""" ] ] + element TrustedCADirectory { + text + }? + }? + & [ a:documentation [ xml:lang="en" """ +

This element configures the Cryptographic plugin of the DDS Security +specification.

""" ] ] + element Cryptographic { + [ a:documentation [ xml:lang="en" """ +

This element specifies the library to be loaded as the DDS Security +Cryptographic plugin.

""" ] ] + element Library { + [ a:documentation [ xml:lang="en" """ +

This element names the finalization function of Cryptographic plugin. +This function is called to let the plugin release its +resources.

The default value is: "finalize_crypto".

""" ] ] + attribute finalizeFunction { + text + }? + & [ a:documentation [ xml:lang="en" """ +

This element names the initialization function of Cryptographic +plugin. This function is called after loading the plugin library for +instantiation purposes. Init function must return an object that +implements DDS Security Cryptographic interface.

The default value +is: "init_crypto".

""" ] ] + attribute initFunction { + text + }? + & [ a:documentation [ xml:lang="en" """ +

This element points to the path of Cryptographic plugin library.

+ +

It can be either absolute path excluding file extension ( +/usr/lib/dds_security_crypto ) or single file without extension ( +dds_security_crypto ).

+ +

If single file is supplied, the library located by way of the current +working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for +Windows systems.

The default value is: +"dds_security_crypto".

""" ] ] + attribute path { + text + }? + }? + }? + }* & [ a:documentation [ xml:lang="en" """

The Discovery element allows specifying various parameters related to the discovery of peers.

""" ] ] @@ -106,11 +417,6 @@ Discovery/SPDPMulticastAddress.

The default value is: text }? & [ a:documentation [ xml:lang="en" """ -

Do not use.

The default value is: "true".

""" ] ] - element EnableTopicDiscovery { - xsd:boolean - }? - & [ a:documentation [ xml:lang="en" """

An override for the domain id, to be used in discovery and for determining the port number mapping. This allows creating multiple domains in a single process while making them appear as a single domain @@ -272,7 +578,7 @@ be discovered.

The default value is: "".

""" ] ] element Tag { text }? - }? + }* & [ a:documentation [ xml:lang="en" """

The General element specifies overall Cyclone DDS service settings.

""" ] ] @@ -807,7 +1113,7 @@ is therefore recommended to set it to at least several seconds.

Valid values are finite durations with an explicit unit or the keyword 'inf' for infinity. Recognised units: ns, us, ms, s, min, hr, -day.

The default value is: "10s".

""" ] ] +day.

The default value is: "0s".

""" ] ] element RediscoveryBlacklistDuration { [ a:documentation [ xml:lang="en" """

This attribute controls whether the configured time during which @@ -1024,7 +1330,7 @@ s, min, hr, day.

The default value is: "1 s".

""" ] ] element WriterLingerDuration { duration }? - }? + }* & [ a:documentation [ xml:lang="en" """

The Partitioning element specifies Cyclone DDS network partitions and how DCPS partition/topic combinations are mapped onto the network @@ -1114,7 +1420,7 @@ DCPSPartitionTopic attribute within this PartitionMapping element.

""" ] ] } }* }* - }? + }* & [ a:documentation [ xml:lang="en" """

The SSL element allows specifying various parameters related to using SSL/TLS for DDSI over TCP.

""" ] ] @@ -1174,7 +1480,7 @@ connecting client.

The default value is: "true".

""" ] ] element VerifyClient { xsd:boolean }? - }? + }* & [ a:documentation [ xml:lang="en" """

The Sizing element specifies a variety of configuration settings dealing with expected system sizes, buffer sizes, &c.

""" ] ] @@ -1205,7 +1511,7 @@ MiB".

""" ] ] element ReceiveBufferSize { memsize }? - }? + }* & [ a:documentation [ xml:lang="en" """

The TCP element allows specifying various parameters related to running DDSI over TCP.

""" ] ] @@ -1262,7 +1568,7 @@ s, min, hr, day.

The default value is: "2 s".

""" ] ] element WriteTimeout { duration }? - }? + }* & [ a:documentation [ xml:lang="en" """

The ThreadPool element allows specifying various parameters related to using a thread pool to send DDSI messages to multiple unicast addresses @@ -1286,7 +1592,7 @@ pool.

The default value is: "4".

""" ] ] element Threads { xsd:integer }? - }? + }* & [ a:documentation [ xml:lang="en" """

This element is used to set thread properties.

""" ] ] element Threads { @@ -1311,6 +1617,9 @@ for discovery;
  • tev: general timed-event handling, retransmits and discovery;
  • +
  • fsm: finite state machine thread for handling security +handshake;
  • +
  • xmit.CHAN: transmit thread for channel CHAN;
  • dq.CHAN: delivery thread for channel CHAN;
  • @@ -1355,7 +1664,7 @@ default.

    memsize }? }* - }? + }* & [ a:documentation [ xml:lang="en" """

    The Tracing element controls the amount and type of information that is written into the tracing log by the DDSI service. This is useful to @@ -1472,8 +1781,8 @@ verbosity levels are config, fine and element Verbosity { ("finest"|"finer"|"fine"|"config"|"info"|"warning"|"severe"|"none") }? - }? - }? + }* + }* } bandwidth = xsd:token { pattern = "0|(\d+(\.\d*)?([Ee][\-+]?\d+)?|\.\d+([Ee][\-+]?\d+)?) *([kMG]i?)?[Bb][p/]s" } duration = xsd:token { pattern = "0|(\d+(\.\d*)?([Ee][\-+]?\d+)?|\.\d+([Ee][\-+]?\d+)?) *([num]?s|min|hr|day)" } diff --git a/etc/cyclonedds.xsd b/etc/cyclonedds.xsd index f2962fe..8214bf1 100644 --- a/etc/cyclonedds.xsd +++ b/etc/cyclonedds.xsd @@ -7,7 +7,7 @@ CycloneDDS configuration - + @@ -17,17 +17,18 @@ CycloneDDS configuration <p>The General element specifying Domain related settings.</p> - - - - - - - - - - - + + + + + + + + + + + + <p>This element is used to set thread properties.</p> @@ -38,8 +39,8 @@ CycloneDDS configuration - - + + @@ -146,6 +147,383 @@ though there is no good reason not to.</li></ul> + + + +<p>This element is used to configure Cyclone DDS with the DDS Security +specification plugins and settings.</p> + + + + + + + + + + + + +<p>This element configures the Access Control plugin of the DDS Security +specification.</p> + + + + + + + +<p>This element specifies the library to be loaded as the DDS Security +Access Control plugin.</p> + + + + + +<p>This element names the finalization function of Access Control plugin. +This function is called to let the plugin release its +resources.</p><p>The default value is: +&quot;finalize_access_control&quot;.</p> + + + + + +<p>This element names the initialization function of Access Control +plugin. This function is called after loading the plugin library for +instantiation purposes. Init function must return an object that +implements DDS Security Access Control interface.</p><p>The default value +is: &quot;init_access_control&quot;.</p> + + + + + +<p>This element points to the path of Access Control plugin library.</p> + +<p>It can be either absolute path excluding file extension ( +/usr/lib/dds_security_ac ) or single file without extension ( +dds_security_ac ).</p> + +<p>If single file is supplied, the library located by way of the current +working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for +Windows systems.</p><p>The default value is: +&quot;dds_security_ac&quot;.</p> + + + + + + + + + + + + +<p>URI to the shared Governance Document signed by the Permissions CA in +S/MIME format</p> + +<p>URI schemes: file, data</p><br> + +<p>Examples file URIs:</p> + +<p><Governance>file:governance.smime</Governance></p> + +<p><Governance>file:/home/myuser/governance.smime</Governance></p><br> + +<p><Governance><![CDATA[data:,MIME-Version: 1.0</p> + +<p>Content-Type: multipart/signed; +protocol="application/x-pkcs7-signature"; micalg="sha-256"; +boundary="----F9A8A198D6F08E1285A292ADF14DD04F"</p> + +<p>This is an S/MIME signed message </p> + +<p>------F9A8A198D6F08E1285A292ADF14DD04F</p> + +<p><?xml version="1.0" encoding="UTF-8"?></p> + +<p><dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"</p> + +<p>xsi:noNamespaceSchemaLocation="omg_shared_ca_governance.xsd"></p> + +<p><domain_access_rules></p> + +<p> . . . </p> + +<p></domain_access_rules></p> + +<p></dds></p> + +<p>...</p> + +<p>------F9A8A198D6F08E1285A292ADF14DD04F</p> + +<p>Content-Type: application/x-pkcs7-signature; name="smime.p7s"</p> + +<p>Content-Transfer-Encoding: base64</p> + +<p>Content-Disposition: attachment; filename="smime.p7s"</p> + +<p>MIIDuAYJKoZIhv ...al5s=</p> + +<p>------F9A8A198D6F08E1285A292ADF14DD04F-]]</Governance></p><p>The +default value is: &quot;&quot;.</p> + + + + + +<p>URI to the DomainParticipant permissions document signed by the +Permissions CA in S/MIME format</p> + +<p>The permissions document specifies the permissions to be applied to a +domain.</p><br> + +<p>Example file URIs:</p> + +<p><Permissions>file:permissions_document.p7s</Permissions></p> + +<p><Permissions>file:/path_to/permissions_document.p7s</Permissions></p> + +<p>Example data URI:</p> + +<p><Permissions><![CDATA[data:,.........]]</Permissions></p><p>The +default value is: &quot;&quot;.</p> + + + + + +<p>URI to a X509 certificate for the PermissionsCA in PEM format.</p> + +<p>Supported URI schemes: file, data</p> + +<p>The file and data schemas shall refer to a X.509 v3 certificate (see +X.509 v3 ITU-T Recommendation X.509 (2005) [39]) in PEM format.</p><br> + +<p>Examples:</p><br> + +<p><PermissionsCA>file:permissions_ca.pem</PermissionsCA></p> + +<p><PermissionsCA>file:/home/myuser/permissions_ca.pem</PermissionsCA></p><br> + +<p><PermissionsCA>data:<strong>,</strong>-----BEGIN CERTIFICATE-----</p> + +<p>MIIC3DCCAcQCCQCWE5x+Z ... PhovK0mp2ohhRLYI0ZiyYQ==</p> + +<p>-----END CERTIFICATE-----</PermissionsCA></p><p>The default value is: +&quot;&quot;.</p> + + + + + +<p>This element configures the Authentication plugin of the DDS Security +specification.</p> + + + + + + + + + +<p>This element specifies the library to be loaded as the DDS Security +Access Control plugin.</p> + + + + + +<p>This element names the finalization function of Authentication plugin. +This function is called to let the plugin release its +resources.</p><p>The default value is: +&quot;finalize_authentication&quot;.</p> + + + + + +<p>This element names the initialization function of Authentication +plugin. This function is called after loading the plugin library for +instantiation purposes. Init function must return an object that +implements DDS Security Authentication interface.</p><p>The default value +is: &quot;init_authentication&quot;.</p> + + + + + +<p>This element points to the path of Authentication plugin library.</p> + +<p>It can be either absolute path excluding file extension ( +/usr/lib/dds_security_auth ) or single file without extension ( +dds_security_auth ).</p> + +<p>If single file is supplied, the library located by way of the current +working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for +Windows systems.</p><p>The default value is: +&quot;dds_security_auth&quot;.</p> + + + + + + + + + + + + + +<p>URI to the X509 certificate [39] of the Identity CA that is the signer +of Identity Certificate.</p> + +<p>Supported URI schemes: file, data</p> + +<p>The file and data schemas shall refer to a X.509 v3 certificate (see +X.509 v3 ITU-T Recommendation X.509 (2005) [39]) in PEM format.</p> + +<p>Examples:</p> + +<p><IdentityCA>file:identity_ca.pem</IdentityCA></p> + +<p><IdentityCA>data:,-----BEGIN CERTIFICATE-----<br> + +MIIC3DCCAcQCCQCWE5x+Z...PhovK0mp2ohhRLYI0ZiyYQ==<br> + +-----END CERTIFICATE-----</IdentityCA></p> + + + + + +<p>Identity certificate that will be used for identifying all +participants in the OSPL instance.<br>The content is URI to a X509 +certificate signed by the IdentityCA in PEM format containing the signed +public key.</p> + +<p>Supported URI schemes: file, data</p> + +<p>Examples:</p> + +<p><IdentityCertificate>file:participant1_identity_cert.pem</IdentityCertificate></p> + +<p><IdentityCertificate>data:,-----BEGIN CERTIFICATE-----<br> + +MIIDjjCCAnYCCQDCEu9...6rmT87dhTo=<br> + +-----END CERTIFICATE-----</IdentityCertificate></p> + + + + + +<p>The authentication handshake tokens may contain optional fields to be +included for finding interoperability problems. + +If this parameter is set to true the optional fields are included in the +handshake token exchange.</p><p>The default value is: +&quot;false&quot;.</p> + + + + + +<p>A password used to decrypt the private_key.</p> + +The value of the password property shall be interpreted as the Base64 +encoding of the AES-128 key that shall be used to decrypt the private_key +using AES128-CBC.</p> + +If the password property is not present, then the value supplied in the +private_key property must contain the unencrypted private key. </p><p>The +default value is: &quot;&quot;.</p> + + + + + +<p>URI to access the private Private Key for all of the participants in +the OSPL federation.</p> + +<p>Supported URI schemes: file, data</p> + +<p>Examples:</p> + +<p><PrivateKey>file:identity_ca_private_key.pem</PrivateKey></p> + +<p><PrivateKey>data:,-----BEGIN RSA PRIVATE KEY-----<br> + +MIIEpAIBAAKCAQEA3HIh...AOBaaqSV37XBUJg==<br> + +-----END RSA PRIVATE KEY-----</PrivateKey></p> + + + + + +<p>Trusted CA Directory which contains trusted CA certificates as +separated files.</p><p>The default value is: &quot;&quot;.</p> + + + + + +<p>This element configures the Cryptographic plugin of the DDS Security +specification.</p> + + + + + + +<p>This element specifies the library to be loaded as the DDS Security +Cryptographic plugin.</p> + + + + + +<p>This element names the finalization function of Cryptographic plugin. +This function is called to let the plugin release its +resources.</p><p>The default value is: &quot;finalize_crypto&quot;.</p> + + + + + +<p>This element names the initialization function of Cryptographic +plugin. This function is called after loading the plugin library for +instantiation purposes. Init function must return an object that +implements DDS Security Cryptographic interface.</p><p>The default value +is: &quot;init_crypto&quot;.</p> + + + + + +<p>This element points to the path of Cryptographic plugin library.</p> + +<p>It can be either absolute path excluding file extension ( +/usr/lib/dds_security_crypto ) or single file without extension ( +dds_security_crypto ).</p> + +<p>If single file is supplied, the library located by way of the current +working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for +Windows systems.</p><p>The default value is: +&quot;dds_security_crypto&quot;.</p> + + + + + + + @@ -156,7 +534,6 @@ the discovery of peers.</p> - @@ -190,12 +567,6 @@ Discovery/SPDPMulticastAddress.</p><p>The default value is: &quot;auto&quot;.</p> - - - -<p>Do not use.</p><p>The default value is: &quot;true&quot;.</p> - - @@ -1104,7 +1475,7 @@ is therefore recommended to set it to at least several seconds.</p> <p>Valid values are finite durations with an explicit unit or the keyword 'inf' for infinity. Recognised units: ns, us, ms, s, min, hr, -day.</p><p>The default value is: &quot;10s&quot;.</p> +day.</p><p>The default value is: &quot;0s&quot;.</p> @@ -1777,6 +2148,9 @@ for discovery;</li> <li><i>tev</i>: general timed-event handling, retransmits and discovery;</li> +<li><i>fsm</i>: finite state machine thread for handling security +handshake;</li> + <li><i>xmit.CHAN</i>: transmit thread for channel CHAN;</li> <li><i>dq.CHAN</i>: delivery thread for channel CHAN;</li> diff --git a/package.xml b/package.xml index dd32d8b..8c4a00f 100644 --- a/package.xml +++ b/package.xml @@ -2,7 +2,7 @@ cyclonedds - 0.6.0 + 0.7.0 Eclipse Cyclone DDS is a very performant and robust open-source DDS implementation. Cyclone DDS is developed completely in the open as an Eclipse IoT project. Eclipse Foundation, Inc. Eclipse Public License 2.0 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ca59544..9e5f5c7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,6 +16,69 @@ if(NOT ${PROJECT_NAME} STREQUAL "CycloneDDS") message(FATAL_ERROR "Top-level CMakeLists.txt was moved to the top-level directory. Please run cmake on ${dir} instead of ${CMAKE_CURRENT_LIST_DIR}") endif() +# Generate a header file listing compile-time options relevant to the API. Define to +# "1" if enabled so that the generated features.h ends up having either +# +# - #define DDS_HAS_SECURITY 1 +# or +# - /* #undef DDS_HAS_SECURITY */ +# +# which caters both for those who prefer #ifdef DDS_HAS_SECURITY and for those who prefer +# #if DDS_HAS_SECURITY. +if(ENABLE_SECURITY) + set(DDS_HAS_SECURITY "1") +endif() +if(ENABLE_LIFESPAN) + set(DDS_HAS_LIFESPAN "1") +endif() +if(ENABLE_DEADLINE_MISSED) + set(DDS_HAS_DEADLINE_MISSED "1") +endif() +configure_file(features.h.in "${CMAKE_CURRENT_BINARY_DIR}/core/include/dds/features.h") + +add_definitions(-DDDSI_INCLUDE_NETWORK_PARTITIONS -DDDSI_INCLUDE_SSM) + +# OpenSSL is huge, raising the RSS by 1MB or so, and moreover find_package(OpenSSL) causes +# trouble on some older CMake versions that otherwise work fine, so provide an option to avoid +# all OpenSSL related things. +# +# Historically the option was DDSC_ENABLE_OPENSSL so make some allowance for those who are +# currently relying on it. +option(ENABLE_SSL "Enable openssl support" ON) +option(DDSC_ENABLE_OPENSSL "Deprecated: please use ENABLE_SSL instead" ON) +if(NOT DDSC_ENABLE_OPENSSL) + message(ERROR "DDSC_ENABLE_OPENSSL is deprecated, please use ENABLE_SSL instead") + set(ENABLE_SSL OFF) +endif() + +if(ENABLE_SSL) + find_package(OpenSSL) + if(OPENSSL_FOUND) + add_definitions(-DDDSI_INCLUDE_SSL) + message(STATUS "Building with OpenSSL support") + else() + message(STATUS "Building without OpenSSL support") + endif() +endif() + +# Support the OMG DDS Security within ddsc adds quite a bit of code. +option(ENABLE_SECURITY "Enable OMG DDS Security support" ON) +if(NOT ENABLE_SECURITY) + message(STATUS "Building without OMG DDS Security support") +else() + add_definitions(-DDDSI_INCLUDE_SECURITY) +endif() + +option(ENABLE_LIFESPAN "Enable Lifespan QoS support" ON) +if(ENABLE_LIFESPAN) + add_definitions(-DDDSI_INCLUDE_LIFESPAN) +endif() + +option(ENABLE_DEADLINE_MISSED "Enable Deadline Missed QoS support" ON) +if(ENABLE_DEADLINE_MISSED) + add_definitions(-DDDSI_INCLUDE_DEADLINE_MISSED) +endif() + add_subdirectory(ddsrt) # some of the tests in the core rely on preprocessing IDL, so idlc has to @@ -23,6 +86,7 @@ add_subdirectory(ddsrt) if(BUILD_IDLC) add_subdirectory(idlc) endif() +add_subdirectory(security) add_subdirectory(core) add_subdirectory(tools) if(BUILD_TESTING AND HAVE_MULTI_PROCESS AND BUILD_IDLC) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ab95de9..b2fbfe6 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -25,44 +25,21 @@ else() add_library(ddsc) endif() -add_definitions(-DDDSI_INCLUDE_NETWORK_PARTITIONS -DDDSI_INCLUDE_SSM) - -option(ENABLE_LIFESPAN "Enable Lifespan QoS support" ON) -if(ENABLE_LIFESPAN) - add_definitions(-DDDSI_INCLUDE_LIFESPAN) -endif() - -option(ENABLE_DEADLINE_MISSED "Enable Deadline Missed QoS support" ON) -if(ENABLE_DEADLINE_MISSED) - add_definitions(-DDDSI_INCLUDE_DEADLINE_MISSED) -endif() - -# OpenSSL is huge, raising the RSS by 1MB or so, and moreover find_package(OpenSSL) causes -# trouble on some older CMake versions that otherwise work fine, so provide an option to avoid -# all OpenSSL related things. -# -# Historically the option was DDSC_ENABLE_OPENSSL so make some allowance for those who are -# currently relying on it. -option(ENABLE_SSL "Enable openssl support" ON) -option(DDSC_ENABLE_OPENSSL "Deprecated: please use ENABLE_SSL instead" ON) -if(NOT DDSC_ENABLE_OPENSSL) - message(ERROR "DDSC_ENABLE_OPENSSL is deprecated, please use ENABLE_SSL instead") - set(ENABLE_SSL OFF) -endif() -if(ENABLE_SSL) - find_package(OpenSSL) - if(OPENSSL_FOUND) - add_definitions(-DDDSI_INCLUDE_SSL) - target_link_libraries(ddsc PRIVATE OpenSSL::SSL) - if(CMAKE_GENERATOR MATCHES "Visual Studio") - set_target_properties(ddsc PROPERTIES LINK_FLAGS "/ignore:4099") - endif() - message(STATUS "Building with OpenSSL support") - else() - message(STATUS "Building without OpenSSL support") +if(ENABLE_SSL AND OPENSSL_FOUND) + target_link_libraries(ddsc PRIVATE OpenSSL::SSL) + if(CMAKE_GENERATOR MATCHES "Visual Studio") + set_target_properties(ddsc PROPERTIES LINK_FLAGS "/ignore:4099") endif() endif() +# Support the OMG DDS Security within ddsc adds quite a bit of code. +if(ENABLE_SECURITY) + target_link_libraries(ddsc PRIVATE security_core) + target_include_directories( + ddsc PUBLIC + $>) +endif() + include(ddsi/CMakeLists.txt) include(ddsc/CMakeLists.txt) diff --git a/src/core/ddsc/include/dds/dds.h b/src/core/ddsc/include/dds/dds.h index ce803d1..2a63fbb 100644 --- a/src/core/ddsc/include/dds/dds.h +++ b/src/core/ddsc/include/dds/dds.h @@ -25,6 +25,7 @@ #endif #include "dds/export.h" +#include "dds/features.h" /** * Handle to an entity. A valid entity handle will always have a positive @@ -89,6 +90,7 @@ typedef enum dds_status_id { DDS_PUBLICATION_MATCHED_STATUS_ID, DDS_SUBSCRIPTION_MATCHED_STATUS_ID } dds_status_id_t; +#define DDS_STATUS_ID_MAX (DDS_SUBSCRIPTION_MATCHED_STATUS_ID) /** Another topic exists with the same name but with different characteristics. */ #define DDS_INCONSISTENT_TOPIC_STATUS (1u << DDS_INCONSISTENT_TOPIC_STATUS_ID) @@ -762,8 +764,22 @@ dds_set_listener(dds_entity_t entity, const dds_listener_t * listener); * * @retval >0 * A valid participant handle. + * @retval DDS_RETCODE_NOT_ALLOWED_BY_SECURITY + * An invalid DDS Security configuration was specified (whether + * that be missing or incorrect entries, expired certificates, + * or anything else related to the security settings and + * implementation). + * @retval DDS_RETCODE_PRECONDITION_NOT_MET + * Some security properties specified in the QoS, but the Cyclone + * build does not include support for DDS Security. + * @retval DDS_RETCODE_OUT_OF_RESOURCES + * Some resource limit (maximum participants, memory, handles, + * &c.) prevented creation of the participant. * @retval DDS_RETCODE_ERROR - * An internal error has occurred. + * The "CYCLONEDDS_URI" environment variable lists non-existent + * or invalid configuration files, or contains invalid embedded + * configuration items; or an unspecified internal error has + * occurred. */ DDS_EXPORT dds_entity_t dds_create_participant( @@ -2741,6 +2757,53 @@ dds_take_mask_wl( uint32_t maxs, uint32_t mask); +#define DDS_HAS_READCDR 1 +/** + * @brief Access the collection of serialized data values (of same type) and + * sample info from the data reader, readcondition or querycondition. + * + * This call accesses the serialized data from the data reader, readcondition or + * querycondition and makes it available to the application. The serialized data + * is made available through \ref ddsi_serdata structures. Returned samples are + * marked as READ. + * + * Return value provides information about the number of samples read, which will + * be <= maxs. Based on the count, the buffer will contain serialized data to be + * read only when valid_data bit in sample info structure is set. + * The buffer required for data values, could be allocated explicitly or can + * use the memory from data reader to prevent copy. In the latter case, buffer and + * sample_info should be returned back, once it is no longer using the data. + * + * @param[in] reader_or_condition Reader, readcondition or querycondition entity. + * @param[out] buf An array of pointers to \ref ddsi_serdata structures that contain + * the serialized data. The pointers can be NULL. + * @param[in] maxs Maximum number of samples to read. + * @param[out] si Pointer to an array of \ref dds_sample_info_t returned for each data value. + * @param[in] mask Filter the data based on dds_sample_state_t|dds_view_state_t|dds_instance_state_t. + * + * @returns A dds_return_t with the number of samples read or an error code. + * + * @retval >=0 + * Number of samples read. + * @retval DDS_RETCODE_ERROR + * An internal error has occurred. + * @retval DDS_RETCODE_BAD_PARAMETER + * One of the given arguments is not valid. + * @retval DDS_RETCODE_ILLEGAL_OPERATION + * The operation is invoked on an inappropriate object. + * @retval DDS_RETCODE_ALREADY_DELETED + * The entity has already been deleted. + * @retval DDS_RETCODE_PRECONDITION_NOT_MET + * The precondition for this operation is not met. + */ +DDS_EXPORT dds_return_t +dds_readcdr( + dds_entity_t reader_or_condition, + struct ddsi_serdata **buf, + uint32_t maxs, + dds_sample_info_t *si, + uint32_t mask); + /** * @brief Access the collection of serialized data values (of same type) and * sample info from the data reader, readcondition or querycondition. diff --git a/src/core/ddsc/include/dds/ddsc/dds_public_impl.h b/src/core/ddsc/include/dds/ddsc/dds_public_impl.h index 730020c..46bfcbe 100644 --- a/src/core/ddsc/include/dds/ddsc/dds_public_impl.h +++ b/src/core/ddsc/include/dds/ddsc/dds_public_impl.h @@ -225,6 +225,13 @@ enum dds_stream_typecode_subtype { #define DDS_OP_FLAG_KEY 0x01 /* key field: applicable to {1,2,4,8}BY, STR, BST, ARR-of-{1,2,4,8}BY */ #define DDS_OP_FLAG_DEF 0x02 /* union has a default case (for DDS_OP_ADR | DDS_OP_TYPE_UNI) */ +/* For a union: (1) the discriminator may be a key field; (2) there may be a default value; + and (3) the discriminator can be an integral type (or enumerated - here treated as equivalent). + What it can't be is a floating-point type. So DEF and FP need never be set at the same time. + There are only a few flag bits, so saving one is not such a bad idea. */ +#define DDS_OP_FLAG_FP 0x02 /* floating-point: applicable to {4,8}BY and arrays, sequences of them */ +#define DDS_OP_FLAG_SGN 0x04 /* signed: applicable to {1,2,4,8}BY and arrays, sequences of them */ + /** * Description : Enable or disable write batching. Overrides default configuration * setting for write batching (Internal/WriteBatch). diff --git a/src/core/ddsc/include/dds/ddsc/dds_public_qos.h b/src/core/ddsc/include/dds/ddsc/dds_public_qos.h index eb0a670..4146960 100644 --- a/src/core/ddsc/include/dds/ddsc/dds_public_qos.h +++ b/src/core/ddsc/include/dds/ddsc/dds_public_qos.h @@ -23,6 +23,11 @@ #include "dds/export.h" #include "dds/ddsc/dds_public_qosdefs.h" +/* Whether or not the "property list" QoS setting is supported in this version. If it is, + the "dds.sec." properties are treated specially, preventing the accidental creation of + an non-secure participant by an implementation built without support for DDS Security. */ +#define DDS_HAS_PROPERTY_LIST_QOS 1 + #if defined (__cplusplus) extern "C" { #endif @@ -381,6 +386,72 @@ dds_qset_ignorelocal ( dds_qos_t * __restrict qos, dds_ignorelocal_kind_t ignore); +/** + * @brief Stores a property with the provided name and string value in a qos structure. + * + * In the case a property with the provided name already exists in the qos structure, + * the value for this entry is overwritten with the provided string value. If more than + * one property with the provided name exists, only the value of the first of these + * properties is updated. + * + * @param[in,out] qos - Pointer to a dds_qos_t structure that will store the property + * @param[in] name - Pointer to name of the property + * @param[in] value - Pointer to a (null-terminated) string that will be stored + */ +DDS_EXPORT void +dds_qset_prop ( + dds_qos_t * __restrict qos, + const char * name, + const char * value); + +/** + * @brief Removes the property with the provided name from a qos structure. + * + * In case more than one property exists with this name, only the first property + * is removed. + * + * @param[in,out] qos - Pointer to a dds_qos_t structure that contains the property + * @param[in] name - Pointer to name of the property + */ +DDS_EXPORT void +dds_qunset_prop ( + dds_qos_t * __restrict qos, + const char * name); + +/** + * @brief Stores the provided binary data as a property in a qos structure + * + * In the case a property with the provided name already exists in the qos structure, + * the value for this entry is overwritten with the provided data. If more than one + * property with the provided name exists, only the value of the first of these + * properties is updated. + * + * @param[in,out] qos - Pointer to a dds_qos_t structure that will store the property + * @param[in] name - Pointer to name of the property + * @param[in] value - Pointer to data to be stored in the property + * @param[in] sz - Size of the data + */ +DDS_EXPORT void +dds_qset_bprop ( + dds_qos_t * __restrict qos, + const char * name, + const void * value, + const size_t sz); + +/** + * @brief Removes the binary property with the provided name from a qos structure. + * + * In case more than one binary property exists with this name, only the first binary + * property is removed. + * + * @param[in,out] qos - Pointer to a dds_qos_t structure that contains the binary property + * @param[in] name - Pointer to name of the property + */ +DDS_EXPORT void +dds_qunset_bprop ( + dds_qos_t * __restrict qos, + const char * name); + /** * @brief Get the userdata from a qos structure * @@ -682,6 +753,74 @@ dds_qget_ignorelocal ( const dds_qos_t * __restrict qos, dds_ignorelocal_kind_t *ignore); +/** + * @brief Gets the names of the properties from a qos structure. + * + * @param[in,out] qos - Pointer to a dds_qos_t structure that contains properties + * @param[in,out] n - Pointer to number of property names that are returned (optional) + * @param[in,out] names - Pointer that will store the string(s) containing property name(s) (optional). This function will allocate the memory for the list of names and for the strings containing the names; the caller gets ownership of the allocated memory + * + * @returns - false iff any of the arguments is invalid or the qos is not present in the qos object + */ +DDS_EXPORT bool +dds_qget_propnames ( + const dds_qos_t * __restrict qos, + uint32_t * n, + char *** names); + +/** + * @brief Get the value of the property with the provided name from a qos structure. + * + * In case more than one property exists with this name, the value for the first + * property with this name will be returned. + * + * @param[in,out] qos - Pointer to a dds_qos_t structure that contains the property + * @param[in] name - Pointer to name of the property + * @param[in,out] value - Pointer to a string that will store the value of the property. The memory for storing the string value will be allocated by this function and the caller gets ownership of the allocated memory + * + * @returns - false iff any of the arguments is invalid, the qos is not present in the qos object or there was no property found with the provided name + */ +DDS_EXPORT bool +dds_qget_prop ( + const dds_qos_t * __restrict qos, + const char * name, + char ** value); + +/** + * @brief Gets the names of the binary properties from a qos structure. + * + * @param[in,out] qos - Pointer to a dds_qos_t structure that contains binary properties + * @param[in,out] n - Pointer to number of binary property names that are returned (optional) + * @param[in,out] names - Pointer that will store the string(s) containing binary property name(s) (optional). This function will allocate the memory for the list of names and for the strings containing the names; the caller gets ownership of the allocated memory + * + * @returns - false iff any of the arguments is invalid or the qos is not present in the qos object + */ +DDS_EXPORT bool +dds_qget_bpropnames ( + const dds_qos_t * __restrict qos, + uint32_t * n, + char *** names); + +/** + * @brief Get the value of the binary property with the provided name from a qos structure. + * + * In case more than one binary property exists with this name, the value for the first + * binary property with this name will be returned. + * + * @param[in,out] qos - Pointer to a dds_qos_t structure that contains the property + * @param[in] name - Pointer to name of the binary property + * @param[in,out] value - Pointer to a buffer that will store the value of the property. If sz = 0 then a NULL pointer. The memory for storing the value will be allocated by this function and the caller gets ownership of the allocated memory + * @param[in,out] sz - Pointer that will store the size of the returned buffer. + * + * @returns - false iff any of the arguments is invalid, the qos is not present in the qos object or there was no binary property found with the provided name + */ +DDS_EXPORT bool +dds_qget_bprop ( + const dds_qos_t * __restrict qos, + const char * name, + void ** value, + size_t * sz); + #if defined (__cplusplus) } #endif diff --git a/src/core/ddsc/include/dds/ddsc/dds_public_qosdefs.h b/src/core/ddsc/include/dds/ddsc/dds_public_qosdefs.h index 810d471..a150b94 100644 --- a/src/core/ddsc/include/dds/ddsc/dds_public_qosdefs.h +++ b/src/core/ddsc/include/dds/ddsc/dds_public_qosdefs.h @@ -50,7 +50,8 @@ typedef enum dds_qos_policy_id { DDS_GROUPDATA_QOS_POLICY_ID, DDS_TRANSPORTPRIORITY_QOS_POLICY_ID, DDS_LIFESPAN_QOS_POLICY_ID, - DDS_DURABILITYSERVICE_QOS_POLICY_ID + DDS_DURABILITYSERVICE_QOS_POLICY_ID, + DDS_PROPERTY_QOS_POLICY_ID, } dds_qos_policy_id_t; /* QoS structure is opaque */ diff --git a/src/core/ddsc/include/dds/ddsc/dds_rhc.h b/src/core/ddsc/include/dds/ddsc/dds_rhc.h index d0413e6..e3bf4d6 100644 --- a/src/core/ddsc/include/dds/ddsc/dds_rhc.h +++ b/src/core/ddsc/include/dds/ddsc/dds_rhc.h @@ -27,9 +27,8 @@ struct dds_reader; struct ddsi_tkmap; typedef dds_return_t (*dds_rhc_associate_t) (struct dds_rhc *rhc, struct dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap); -typedef int (*dds_rhc_read_t) (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond); -typedef int (*dds_rhc_take_t) (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond); -typedef int (*dds_rhc_takecdr_t) (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle); +typedef int32_t (*dds_rhc_read_take_t) (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond); +typedef int32_t (*dds_rhc_read_take_cdr_t) (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle); typedef bool (*dds_rhc_add_readcondition_t) (struct dds_rhc *rhc, struct dds_readcond *cond); typedef void (*dds_rhc_remove_readcondition_t) (struct dds_rhc *rhc, struct dds_readcond *cond); @@ -40,9 +39,10 @@ struct dds_rhc_ops { /* A copy of DDSI rhc ops comes first so we can use either interface without additional indirections */ struct ddsi_rhc_ops rhc_ops; - dds_rhc_read_t read; - dds_rhc_take_t take; - dds_rhc_takecdr_t takecdr; + dds_rhc_read_take_t read; + dds_rhc_read_take_t take; + dds_rhc_read_take_cdr_t readcdr; + dds_rhc_read_take_cdr_t takecdr; dds_rhc_add_readcondition_t add_readcondition; dds_rhc_remove_readcondition_t remove_readcondition; dds_rhc_lock_samples_t lock_samples; @@ -76,13 +76,16 @@ DDS_EXPORT inline void dds_rhc_set_qos (struct dds_rhc *rhc, const struct dds_qo DDS_EXPORT inline void dds_rhc_free (struct dds_rhc *rhc) { rhc->common.ops->rhc_ops.free (&rhc->common.rhc); } -DDS_EXPORT inline int dds_rhc_read (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond) { +DDS_EXPORT inline int32_t dds_rhc_read (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond) { return (rhc->common.ops->read) (rhc, lock, values, info_seq, max_samples, mask, handle, cond); } -DDS_EXPORT inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond) { +DDS_EXPORT inline int32_t dds_rhc_take (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond) { return rhc->common.ops->take (rhc, lock, values, info_seq, max_samples, mask, handle, cond); } -DDS_EXPORT inline int dds_rhc_takecdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) { +DDS_EXPORT inline int32_t dds_rhc_readcdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) { + return rhc->common.ops->readcdr (rhc, lock, values, info_seq, max_samples, sample_states, view_states, instance_states, handle); +} +DDS_EXPORT inline int32_t dds_rhc_takecdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) { return rhc->common.ops->takecdr (rhc, lock, values, info_seq, max_samples, sample_states, view_states, instance_states, handle); } DDS_EXPORT inline bool dds_rhc_add_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond) { diff --git a/src/core/ddsc/src/dds__qos.h b/src/core/ddsc/src/dds__qos.h index ef9553d..2009027 100644 --- a/src/core/ddsc/src/dds__qos.h +++ b/src/core/ddsc/src/dds__qos.h @@ -25,7 +25,7 @@ extern "C" { QP_DESTINATION_ORDER | QP_HISTORY | QP_RESOURCE_LIMITS) #define DDS_PARTICIPANT_QOS_MASK \ - (QP_USER_DATA | QP_ADLINK_ENTITY_FACTORY | QP_CYCLONE_IGNORELOCAL) + (QP_USER_DATA | QP_ADLINK_ENTITY_FACTORY | QP_CYCLONE_IGNORELOCAL | QP_PROPERTY_LIST) #define DDS_PUBLISHER_QOS_MASK \ (QP_PARTITION | QP_PRESENTATION | QP_GROUP_DATA | \ @@ -36,7 +36,7 @@ extern "C" { QP_OWNERSHIP | QP_LIVELINESS | QP_TIME_BASED_FILTER | \ QP_RELIABILITY | QP_DESTINATION_ORDER | QP_HISTORY | \ QP_RESOURCE_LIMITS | QP_ADLINK_READER_DATA_LIFECYCLE | \ - QP_CYCLONE_IGNORELOCAL) + QP_CYCLONE_IGNORELOCAL | QP_PROPERTY_LIST) #define DDS_SUBSCRIBER_QOS_MASK \ (QP_PARTITION | QP_PRESENTATION | QP_GROUP_DATA | \ @@ -48,7 +48,7 @@ extern "C" { QP_LIVELINESS | QP_RELIABILITY | QP_TRANSPORT_PRIORITY | \ QP_LIFESPAN | QP_DESTINATION_ORDER | QP_HISTORY | \ QP_RESOURCE_LIMITS | QP_ADLINK_WRITER_DATA_LIFECYCLE | \ - QP_CYCLONE_IGNORELOCAL) + QP_CYCLONE_IGNORELOCAL | QP_PROPERTY_LIST) #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__topic.h b/src/core/ddsc/src/dds__topic.h index c1c794d..732f4e5 100644 --- a/src/core/ddsc/src/dds__topic.h +++ b/src/core/ddsc/src/dds__topic.h @@ -39,6 +39,8 @@ DDS_EXPORT void dds_topic_set_filter_with_ctx DDS_EXPORT dds_topic_intern_filter_fn dds_topic_get_filter_with_ctx (dds_entity_t topic); +DDS_EXPORT dds_entity_t dds_create_topic_impl (dds_entity_t participant, struct ddsi_sertopic **sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist); + #if defined (__cplusplus) } #endif diff --git a/src/core/ddsc/src/dds__writer.h b/src/core/ddsc/src/dds__writer.h index 69ff7e1..111e93d 100644 --- a/src/core/ddsc/src/dds__writer.h +++ b/src/core/ddsc/src/dds__writer.h @@ -23,7 +23,7 @@ DEFINE_ENTITY_LOCK_UNLOCK(inline, dds_writer, DDS_KIND_WRITER) struct status_cb_data; void dds_writer_status_cb (void *entity, const struct status_cb_data * data); -dds_return_t dds__writer_wait_for_acks (struct dds_writer *wr, dds_time_t abstimeout); +DDS_EXPORT dds_return_t dds__writer_wait_for_acks (struct dds_writer *wr, ddsi_guid_t *rdguid, dds_time_t abstimeout); #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds_builtin.c b/src/core/ddsc/src/dds_builtin.c index 22a76a5..d224810 100644 --- a/src/core/ddsc/src/dds_builtin.c +++ b/src/core/ddsc/src/dds_builtin.c @@ -15,6 +15,7 @@ #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_config.h" +#include "dds/ddsi/q_bswap.h" #include "dds/ddsi/ddsi_domaingv.h" #include "dds/ddsi/ddsi_plist.h" #include "dds__init.h" @@ -24,6 +25,7 @@ #include "dds__builtin.h" #include "dds__entity.h" #include "dds__subscriber.h" +#include "dds__topic.h" #include "dds__write.h" #include "dds__writer.h" #include "dds__whc_builtintopic.h" @@ -76,7 +78,7 @@ dds_entity_t dds__get_builtin_topic (dds_entity_t entity, dds_entity_t topic) } dds_qos_t *qos = dds__create_builtin_qos (); - if ((tp = dds_create_topic_generic (par->m_entity.m_hdllink.hdl, &sertopic, qos, NULL, NULL)) > 0) + if ((tp = dds_create_topic_impl (par->m_entity.m_hdllink.hdl, &sertopic, qos, NULL, NULL)) > 0) { /* keep ownership for built-in sertopics because there are re-used, lifetime for these sertopics is bound to domain */ @@ -180,10 +182,13 @@ static struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry (const struct dd struct dds_domain *domain = vdomain; struct ddsi_tkmap_instance *tk; struct ddsi_serdata *sd; - struct nn_keyhash kh; - memcpy (&kh, guid, sizeof (kh)); - /* any random builtin topic will do (provided it has a GUID for a key), because what matters is the "class" of the topic, not the actual topic; also, this is called early in the initialisation of the entity with this GUID, which simply causes serdata_from_keyhash to create a key-only serdata because the key lookup fails. */ - sd = ddsi_serdata_from_keyhash (domain->builtin_participant_topic, &kh); + union { ddsi_guid_t guid; struct ddsi_keyhash keyhash; } x; + x.guid = nn_hton_guid (*guid); + /* any random builtin topic will do (provided it has a GUID for a key), because what matters is the "class" + of the topic, not the actual topic; also, this is called early in the initialisation of the entity with + this GUID, which simply causes serdata_from_keyhash to create a key-only serdata because the key lookup + fails. */ + sd = ddsi_serdata_from_keyhash (domain->builtin_participant_topic, &x.keyhash); tk = ddsi_tkmap_find (domain->gv.m_tkmap, sd, true); ddsi_serdata_unref (sd); return tk; @@ -195,7 +200,7 @@ struct ddsi_serdata *dds__builtin_make_sample (const struct entity_common *e, dd struct dds_domain *dom = e->gv->builtin_topic_interface->arg; struct ddsi_sertopic *topic = NULL; struct ddsi_serdata *serdata; - struct nn_keyhash keyhash; + union { ddsi_guid_t guid; struct ddsi_keyhash keyhash; } x; switch (e->kind) { case EK_PARTICIPANT: @@ -212,8 +217,8 @@ struct ddsi_serdata *dds__builtin_make_sample (const struct entity_common *e, dd break; } assert (topic != NULL); - memcpy (&keyhash, &e->guid, sizeof (keyhash)); - serdata = ddsi_serdata_from_keyhash (topic, &keyhash); + x.guid = nn_hton_guid (e->guid); + serdata = ddsi_serdata_from_keyhash (topic, &x.keyhash); serdata->timestamp = timestamp; serdata->statusinfo = alive ? 0 : NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER; return serdata; diff --git a/src/core/ddsc/src/dds_listener.c b/src/core/ddsc/src/dds_listener.c index eee9ef6..ae71ec9 100644 --- a/src/core/ddsc/src/dds_listener.c +++ b/src/core/ddsc/src/dds_listener.c @@ -90,8 +90,7 @@ void dds_listener_copy(dds_listener_t * __restrict dst, const dds_listener_t * _ static bool dds_combine_listener_merge (uint32_t inherited, void (*dst)(void), void (*src)(void)) { (void)inherited; - (void)src; - return dst == 0; + return dst == 0 && src != 0; } static bool dds_combine_listener_override_inherited (uint32_t inherited, void (*dst)(void), void (*src)(void)) diff --git a/src/core/ddsc/src/dds_matched.c b/src/core/ddsc/src/dds_matched.c index d2cc6a9..f10ab4c 100644 --- a/src/core/ddsc/src/dds_matched.c +++ b/src/core/ddsc/src/dds_matched.c @@ -144,8 +144,7 @@ static dds_builtintopic_endpoint_t *make_builtintopic_endpoint (const ddsi_guid_ dds_builtintopic_endpoint_t *dds_get_matched_subscription_data (dds_entity_t writer, dds_instance_handle_t ih) { dds_writer *wr; - dds_return_t rc; - if ((rc = dds_writer_lock (writer, &wr)) != DDS_RETCODE_OK) + if (dds_writer_lock (writer, &wr)) return NULL; else { @@ -187,8 +186,7 @@ dds_builtintopic_endpoint_t *dds_get_matched_subscription_data (dds_entity_t wri dds_builtintopic_endpoint_t *dds_get_matched_publication_data (dds_entity_t reader, dds_instance_handle_t ih) { dds_reader *rd; - dds_return_t rc; - if ((rc = dds_reader_lock (reader, &rd)) != DDS_RETCODE_OK) + if (dds_reader_lock (reader, &rd)) return NULL; else { diff --git a/src/core/ddsc/src/dds_participant.c b/src/core/ddsc/src/dds_participant.c index 3cbb48d..5d84fb8 100644 --- a/src/core/ddsc/src/dds_participant.c +++ b/src/core/ddsc/src/dds_participant.c @@ -96,7 +96,7 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_ dds_participant * pp; ddsi_plist_t plist; dds_qos_t *new_qos = NULL; - char *config = ""; + const char *config = ""; /* Make sure DDS instance is initialized. */ if ((ret = dds_init ()) < 0) diff --git a/src/core/ddsc/src/dds_publisher.c b/src/core/ddsc/src/dds_publisher.c index 00ea520..ca17999 100644 --- a/src/core/ddsc/src/dds_publisher.c +++ b/src/core/ddsc/src/dds_publisher.c @@ -114,7 +114,7 @@ dds_return_t dds_wait_for_acks (dds_entity_t publisher_or_writer, dds_duration_t return DDS_RETCODE_UNSUPPORTED; case DDS_KIND_WRITER: - ret = dds__writer_wait_for_acks ((struct dds_writer *) p_or_w_ent, abstimeout); + ret = dds__writer_wait_for_acks ((struct dds_writer *) p_or_w_ent, NULL, abstimeout); dds_entity_unpin (p_or_w_ent); return ret; diff --git a/src/core/ddsc/src/dds_qos.c b/src/core/ddsc/src/dds_qos.c index b53fa7e..2a52c7b 100644 --- a/src/core/ddsc/src/dds_qos.c +++ b/src/core/ddsc/src/dds_qos.c @@ -335,6 +335,112 @@ void dds_qset_ignorelocal (dds_qos_t * __restrict qos, dds_ignorelocal_kind_t ig qos->present |= QP_CYCLONE_IGNORELOCAL; } +static void dds_qprop_init (dds_qos_t * qos) +{ + if (!(qos->present & QP_PROPERTY_LIST)) + { + qos->property.value.n = 0; + qos->property.value.props = NULL; + qos->property.binary_value.n = 0; + qos->property.binary_value.props = NULL; + qos->present |= QP_PROPERTY_LIST; + } +} + +#define DDS_QPROP_GET_INDEX(prop_type_, prop_field_) \ +static bool dds_q##prop_type_##_get_index (const dds_qos_t * qos, const char * name, uint32_t * index) \ +{ \ + if (qos == NULL || name == NULL || index == NULL || !(qos->present & QP_PROPERTY_LIST)) \ + return false; \ + for (uint32_t i = 0; i < qos->property.prop_field_.n; i++) \ + { \ + if (strcmp (qos->property.prop_field_.props[i].name, name) == 0) \ + { \ + *index = i; \ + return true; \ + } \ + } \ + return false; \ +} +DDS_QPROP_GET_INDEX (prop, value) +DDS_QPROP_GET_INDEX (bprop, binary_value) + +#define DDS_QUNSET_PROP(prop_type_, prop_field_, value_field_) \ +void dds_qunset_##prop_type_ (dds_qos_t * __restrict qos, const char * name) \ +{ \ + uint32_t i; \ + if (qos == NULL || !(qos->present & QP_PROPERTY_LIST) || qos->property.prop_field_.n == 0 || name == NULL) \ + return; \ + if (dds_q##prop_type_##_get_index (qos, name, &i)) \ + { \ + dds_free (qos->property.prop_field_.props[i].name); \ + dds_free (qos->property.prop_field_.props[i].value_field_); \ + if (qos->property.prop_field_.n > 1) \ + { \ + if (i < (qos->property.prop_field_.n - 1)) \ + memmove (qos->property.prop_field_.props + i, qos->property.prop_field_.props + i + 1, \ + (qos->property.prop_field_.n - i - 1) * sizeof (*qos->property.prop_field_.props)); \ + qos->property.prop_field_.props = dds_realloc (qos->property.prop_field_.props, \ + (qos->property.prop_field_.n - 1) * sizeof (*qos->property.prop_field_.props)); \ + } \ + else \ + { \ + dds_free (qos->property.prop_field_.props); \ + qos->property.prop_field_.props = NULL; \ + } \ + qos->property.prop_field_.n--; \ + } \ +} +DDS_QUNSET_PROP (prop, value, value) +DDS_QUNSET_PROP (bprop, binary_value, value.value) + +void dds_qset_prop (dds_qos_t * __restrict qos, const char * name, const char * value) +{ + uint32_t i; + if (qos == NULL || name == NULL || value == NULL) + return; + + dds_qprop_init (qos); + if (dds_qprop_get_index (qos, name, &i)) + { + assert (&qos->property.value.props[i] != NULL); /* for Clang static analyzer */ + dds_free (qos->property.value.props[i].value); + qos->property.value.props[i].value = dds_string_dup (value); + } + else + { + qos->property.value.props = dds_realloc (qos->property.value.props, + (qos->property.value.n + 1) * sizeof (*qos->property.value.props)); + qos->property.value.props[qos->property.value.n].propagate = 0; + qos->property.value.props[qos->property.value.n].name = dds_string_dup (name); + qos->property.value.props[qos->property.value.n].value = dds_string_dup (value); + qos->property.value.n++; + } +} + +void dds_qset_bprop (dds_qos_t * __restrict qos, const char * name, const void * value, const size_t sz) +{ + uint32_t i; + if (qos == NULL || name == NULL || (value == NULL && sz > 0)) + return; + + dds_qprop_init (qos); + if (dds_qbprop_get_index (qos, name, &i)) + { + assert (&qos->property.binary_value.props[i].value != NULL); /* for Clang static analyzer */ + dds_qos_data_copy_in (&qos->property.binary_value.props[i].value, value, sz, true); + } + else + { + qos->property.binary_value.props = dds_realloc (qos->property.binary_value.props, + (qos->property.binary_value.n + 1) * sizeof (*qos->property.binary_value.props)); + qos->property.binary_value.props[qos->property.binary_value.n].propagate = 0; + qos->property.binary_value.props[qos->property.binary_value.n].name = dds_string_dup (name); + dds_qos_data_copy_in (&qos->property.binary_value.props[qos->property.binary_value.n].value, value, sz, false); + qos->property.binary_value.n++; + } +} + bool dds_qget_userdata (const dds_qos_t * __restrict qos, void **value, size_t *sz) { if (qos == NULL || !(qos->present & QP_USER_DATA)) @@ -565,3 +671,66 @@ bool dds_qget_ignorelocal (const dds_qos_t * __restrict qos, dds_ignorelocal_kin *ignore = qos->ignorelocal.value; return true; } + +#define DDS_QGET_PROPNAMES(prop_type_, prop_field_) \ +bool dds_qget_##prop_type_##names (const dds_qos_t * __restrict qos, uint32_t * n, char *** names) \ +{ \ + bool props; \ + if (qos == NULL || (n == NULL && names == NULL)) \ + return false; \ + props = (qos->present & QP_PROPERTY_LIST) && qos->property.prop_field_.n > 0; \ + if (n != NULL) \ + *n = props ? qos->property.prop_field_.n : 0; \ + if (names != NULL) \ + { \ + if (!props) \ + *names = NULL; \ + else \ + { \ + *names = dds_alloc (sizeof (char *) * qos->property.prop_field_.n); \ + for (uint32_t i = 0; i < qos->property.prop_field_.n; i++) \ + (*names)[i] = dds_string_dup (qos->property.prop_field_.props[i].name); \ + } \ + } \ + return props; \ +} +DDS_QGET_PROPNAMES (prop, value) +DDS_QGET_PROPNAMES (bprop, binary_value) + +bool dds_qget_prop (const dds_qos_t * __restrict qos, const char * name, char ** value) +{ + uint32_t i; + bool found; + + if (qos == NULL || name == NULL) + return false; + + found = dds_qprop_get_index (qos, name, &i); + if (value != NULL) + *value = found ? dds_string_dup (qos->property.value.props[i].value) : NULL; + return found; +} + +bool dds_qget_bprop (const dds_qos_t * __restrict qos, const char * name, void ** value, size_t * sz) +{ + uint32_t i; + bool found; + + if (qos == NULL || name == NULL || (sz == NULL && value != NULL)) + return false; + + found = dds_qbprop_get_index (qos, name, &i); + if (found) + { + if (value != NULL || sz != NULL) + dds_qos_data_copy_out (&qos->property.binary_value.props[i].value, value, sz); + } + else + { + if (value != NULL) + *value = NULL; + if (sz != NULL) + *sz = 0; + } + return found; +} diff --git a/src/core/ddsc/src/dds_read.c b/src/core/ddsc/src/dds_read.c index 701f50d..a5c932d 100644 --- a/src/core/ddsc/src/dds_read.c +++ b/src/core/ddsc/src/dds_read.c @@ -40,7 +40,7 @@ static dds_return_t dds_read_impl (bool take, dds_entity_t reader_or_condition, #define NC_FREE_BUF 2u #define NC_RESET_BUF 4u - if (buf == NULL || si == NULL || maxs == 0 || bufsz == 0 || bufsz < maxs) + if (buf == NULL || si == NULL || maxs == 0 || bufsz == 0 || bufsz < maxs || maxs > INT32_MAX) return DDS_RETCODE_BAD_PARAMETER; if ((ret = dds_entity_pin (reader_or_condition, &entity)) < 0) { @@ -61,14 +61,6 @@ static dds_return_t dds_read_impl (bool take, dds_entity_t reader_or_condition, thread_state_awake (ts1, &entity->m_domain->gv); - if (hand != DDS_HANDLE_NIL) - { - if (ddsi_tkmap_find_by_id (entity->m_domain->gv.m_tkmap, hand) == NULL) { - ret = DDS_RETCODE_PRECONDITION_NOT_MET; - goto fail_awake_pinned; - } - } - /* Allocate samples if not provided (assuming all or none provided) */ if (buf[0] == NULL) { @@ -142,8 +134,6 @@ static dds_return_t dds_read_impl (bool take, dds_entity_t reader_or_condition, #undef NC_FREE_BUF #undef NC_RESET_BUF -fail_awake_pinned: - thread_state_asleep (ts1); fail_pinned: dds_entity_unpin (entity); fail: @@ -157,12 +147,8 @@ static dds_return_t dds_readcdr_impl (bool take, dds_entity_t reader_or_conditio struct dds_reader *rd; struct dds_entity *entity; - assert (take); - assert (buf); - assert (si); - assert (hand == DDS_HANDLE_NIL); - assert (maxs > 0); - (void)take; + if (buf == NULL || si == NULL || maxs == 0 || maxs > INT32_MAX) + return DDS_RETCODE_BAD_PARAMETER; if ((ret = dds_entity_pin (reader_or_condition, &entity)) < 0) { return ret; @@ -185,7 +171,11 @@ static dds_return_t dds_readcdr_impl (bool take, dds_entity_t reader_or_conditio assert (dds_entity_kind (rd->m_entity.m_parent) == DDS_KIND_SUBSCRIBER); dds_entity_status_reset (rd->m_entity.m_parent, DDS_DATA_ON_READERS_STATUS); - ret = dds_rhc_takecdr (rd->m_rhc, lock, buf, si, maxs, mask & DDS_ANY_SAMPLE_STATE, mask & DDS_ANY_VIEW_STATE, mask & DDS_ANY_INSTANCE_STATE, hand); + if (take) + ret = dds_rhc_takecdr (rd->m_rhc, lock, buf, si, maxs, mask & DDS_ANY_SAMPLE_STATE, mask & DDS_ANY_VIEW_STATE, mask & DDS_ANY_INSTANCE_STATE, hand); + else + ret = dds_rhc_readcdr (rd->m_rhc, lock, buf, si, maxs, mask & DDS_ANY_SAMPLE_STATE, mask & DDS_ANY_VIEW_STATE, mask & DDS_ANY_INSTANCE_STATE, hand); + dds_entity_unpin (entity); thread_state_asleep (ts1); return ret; @@ -239,6 +229,18 @@ dds_return_t dds_read_mask_wl (dds_entity_t rd_or_cnd, void **buf, dds_sample_in return dds_read_impl (false, rd_or_cnd, buf, maxs, maxs, si, mask, DDS_HANDLE_NIL, lock, false); } +dds_return_t dds_readcdr (dds_entity_t rd_or_cnd, struct ddsi_serdata **buf, uint32_t maxs, dds_sample_info_t *si, uint32_t mask) +{ + bool lock = true; + if (maxs == DDS_READ_WITHOUT_LOCK) + { + lock = false; + /* FIXME: Fix the interface. */ + maxs = 100; + } + return dds_readcdr_impl (false, rd_or_cnd, buf, maxs, si, mask, DDS_HANDLE_NIL, lock); +} + dds_return_t dds_read_instance (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs, dds_instance_handle_t handle) { bool lock = true; diff --git a/src/core/ddsc/src/dds_reader.c b/src/core/ddsc/src/dds_reader.c index 3af861b..5af47a0 100644 --- a/src/core/ddsc/src/dds_reader.c +++ b/src/core/ddsc/src/dds_reader.c @@ -30,6 +30,7 @@ #include "dds__builtin.h" #include "dds/ddsi/ddsi_sertopic.h" #include "dds/ddsi/ddsi_entity_index.h" +#include "dds/ddsi/ddsi_security_omg.h" DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_reader) @@ -430,6 +431,7 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe /* Merge qos from topic and subscriber, dds_copy_qos only fails when it is passed a null argument, but that isn't the case here */ + struct ddsi_domaingv *gv = &sub->m_entity.m_domain->gv; rqos = dds_create_qos (); if (qos) ddsi_xqos_mergein_missing (rqos, qos, DDS_READER_QOS_MASK); @@ -437,25 +439,42 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe ddsi_xqos_mergein_missing (rqos, sub->m_entity.m_qos, ~(uint64_t)0); if (tp->m_ktopic->qos) ddsi_xqos_mergein_missing (rqos, tp->m_ktopic->qos, ~(uint64_t)0); - ddsi_xqos_mergein_missing (rqos, &sub->m_entity.m_domain->gv.default_xqos_rd, ~(uint64_t)0); + ddsi_xqos_mergein_missing (rqos, &gv->default_xqos_rd, ~(uint64_t)0); - if ((rc = ddsi_xqos_valid (&sub->m_entity.m_domain->gv.logconfig, rqos)) < 0 || - (rc = validate_reader_qos(rqos)) != DDS_RETCODE_OK) - { - dds_delete_qos (rqos); + if ((rc = ddsi_xqos_valid (&gv->logconfig, rqos)) < 0 || (rc = validate_reader_qos(rqos)) != DDS_RETCODE_OK) goto err_bad_qos; - } /* Additional checks required for built-in topics: we don't want to run into a resource limit on a built-in topic, it is a needless complication */ if (pseudo_topic && !dds__validate_builtin_reader_qos (tp->m_entity.m_domain, pseudo_topic, rqos)) { - dds_delete_qos (rqos); rc = DDS_RETCODE_INCONSISTENT_POLICY; goto err_bad_qos; } + thread_state_awake (lookup_thread_state (), gv); + const struct ddsi_guid * ppguid = dds_entity_participant_guid (&sub->m_entity); + struct participant * pp = entidx_lookup_participant_guid (gv->entity_index, ppguid); + + /* When deleting a participant, the child handles (that include the subscriber) + are removed before removing the DDSI participant. So at this point, within + the subscriber lock, we can assert that the participant exists. */ + assert (pp != NULL); + +#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 reader permissions */ + if (!q_omg_security_check_create_reader (pp, gv->config.domainId, tp->m_stopic->name, rqos)) + { + rc = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; + goto err_not_allowed; + } + } +#endif + /* Create reader and associated read cache (if not provided by caller) */ struct dds_reader * const rd = dds_alloc (sizeof (*rd)); const dds_entity_t reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, false, rqos, listener, DDS_READER_STATUS_MASK); @@ -474,8 +493,7 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe it; and then invoke those listeners that are in the pending set */ dds_entity_init_complete (&rd->m_entity); - thread_state_awake (lookup_thread_state (), &sub->m_entity.m_domain->gv); - rc = new_reader (&rd->m_rd, &rd->m_entity.m_domain->gv, &rd->m_entity.m_guid, NULL, dds_entity_participant_guid (&sub->m_entity), tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd); + rc = new_reader (&rd->m_rd, &rd->m_entity.m_guid, NULL, pp, tp->m_stopic, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd); assert (rc == DDS_RETCODE_OK); /* FIXME: can be out-of-resources at the very least */ thread_state_asleep (lookup_thread_state ()); @@ -487,7 +505,12 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe dds_subscriber_unlock (sub); return reader; +#ifdef DDSI_INCLUDE_SECURITY +err_not_allowed: + thread_state_asleep (lookup_thread_state ()); +#endif err_bad_qos: + dds_delete_qos (rqos); dds_topic_allow_set_qos (tp); err_pp_mismatch: dds_topic_unpin (tp); @@ -632,3 +655,4 @@ DDS_GET_STATUS (reader, sample_rejected, SAMPLE_REJECTED, DDS_GET_STATUS (reader, sample_lost, SAMPLE_LOST, total_count_change) DDS_GET_STATUS (reader, requested_deadline_missed, REQUESTED_DEADLINE_MISSED, total_count_change) DDS_GET_STATUS (reader, requested_incompatible_qos, REQUESTED_INCOMPATIBLE_QOS, total_count_change) + diff --git a/src/core/ddsc/src/dds_rhc.c b/src/core/ddsc/src/dds_rhc.c index f159422..7db2ff0 100644 --- a/src/core/ddsc/src/dds_rhc.c +++ b/src/core/ddsc/src/dds_rhc.c @@ -22,6 +22,7 @@ extern inline void dds_rhc_set_qos (struct dds_rhc *rhc, const struct dds_qos *q extern inline void dds_rhc_free (struct dds_rhc *rhc); extern inline int dds_rhc_read (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond); extern inline int dds_rhc_take (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, struct dds_readcond *cond); +extern inline int dds_rhc_readcdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle); extern inline int dds_rhc_takecdr (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle); extern inline bool dds_rhc_add_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond); extern inline void dds_rhc_remove_readcondition (struct dds_rhc *rhc, struct dds_readcond *cond); diff --git a/src/core/ddsc/src/dds_rhc_default.c b/src/core/ddsc/src/dds_rhc_default.c index 50313ed..4a56d32 100644 --- a/src/core/ddsc/src/dds_rhc_default.c +++ b/src/core/ddsc/src/dds_rhc_default.c @@ -267,9 +267,11 @@ struct rhc_instance { unsigned isnew : 1; /* NEW or NOT_NEW view state */ unsigned a_sample_free : 1; /* whether or not a_sample is in use */ unsigned isdisposed : 1; /* DISPOSED or NOT_DISPOSED (if not disposed, wrcount determines ALIVE/NOT_ALIVE_NO_WRITERS) */ + unsigned autodispose : 1; /* wrcount > 0 => at least one registered writer has had auto-dispose set on some update */ unsigned wr_iid_islive : 1; /* whether wr_iid is of a live writer */ unsigned inv_exists : 1; /* whether or not state change occurred since last sample (i.e., must return invalid sample) */ unsigned inv_isread : 1; /* whether or not that state change has been read before */ + unsigned deadline_reg : 1; /* whether or not registered for a deadline (== isdisposed, except store() defers updates) */ uint32_t disposed_gen; /* bloody generation counters - worst invention of mankind */ uint32_t no_writers_gen; /* __/ */ int32_t strength; /* "current" ownership strength */ @@ -337,7 +339,7 @@ struct dds_rhc_default { }; struct trigger_info_cmn { - unsigned qminst; + uint32_t qminst; bool has_read; bool has_not_read; }; @@ -363,81 +365,14 @@ struct trigger_info_post { struct trigger_info_cmn c; }; -static void dds_rhc_default_free (struct dds_rhc_default *rhc); -static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk); -static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo); -static void dds_rhc_default_relinquish_ownership (struct dds_rhc_default * __restrict rhc, const uint64_t wr_iid); -static void dds_rhc_default_set_qos (struct dds_rhc_default *rhc, const struct dds_qos *qos); -static int dds_rhc_default_read (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond); -static int dds_rhc_default_take (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond); -static int dds_rhc_default_takecdr (struct dds_rhc_default *rhc, bool lock, struct ddsi_serdata ** values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle); -static bool dds_rhc_default_add_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond); -static void dds_rhc_default_remove_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond); -static uint32_t dds_rhc_default_lock_samples (struct dds_rhc_default *rhc); +static const struct dds_rhc_ops dds_rhc_default_ops; -static void dds_rhc_default_free_wrap (struct ddsi_rhc *rhc) { - dds_rhc_default_free ((struct dds_rhc_default *) rhc); -} -static bool dds_rhc_default_store_wrap (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) { - return dds_rhc_default_store ((struct dds_rhc_default *) rhc, wrinfo, sample, tk); -} -static void dds_rhc_default_unregister_wr_wrap (struct ddsi_rhc * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo) { - dds_rhc_default_unregister_wr ((struct dds_rhc_default *) rhc, wrinfo); -} -static void dds_rhc_default_relinquish_ownership_wrap (struct ddsi_rhc * __restrict rhc, const uint64_t wr_iid) { - dds_rhc_default_relinquish_ownership ((struct dds_rhc_default *) rhc, wr_iid); -} -static void dds_rhc_default_set_qos_wrap (struct ddsi_rhc *rhc, const struct dds_qos *qos) { - dds_rhc_default_set_qos ((struct dds_rhc_default *) rhc, qos); -} -static int dds_rhc_default_read_wrap (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond) { - return dds_rhc_default_read ((struct dds_rhc_default *) rhc, lock, values, info_seq, max_samples, mask, handle, cond); -} -static int dds_rhc_default_take_wrap (struct dds_rhc *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond) { - return dds_rhc_default_take ((struct dds_rhc_default *) rhc, lock, values, info_seq, max_samples, mask, handle, cond); -} -static int dds_rhc_default_takecdr_wrap (struct dds_rhc *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) { - return dds_rhc_default_takecdr ((struct dds_rhc_default *) rhc, lock, values, info_seq, max_samples, sample_states, view_states, instance_states, handle); -} -static bool dds_rhc_default_add_readcondition_wrap (struct dds_rhc *rhc, dds_readcond *cond) { - return dds_rhc_default_add_readcondition ((struct dds_rhc_default *) rhc, cond); -} -static void dds_rhc_default_remove_readcondition_wrap (struct dds_rhc *rhc, dds_readcond *cond) { - dds_rhc_default_remove_readcondition ((struct dds_rhc_default *) rhc, cond); -} -static uint32_t dds_rhc_default_lock_samples_wrap (struct dds_rhc *rhc) { - return dds_rhc_default_lock_samples ((struct dds_rhc_default *) rhc); -} -static dds_return_t dds_rhc_default_associate (struct dds_rhc *rhc, dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap) -{ - /* ignored out of laziness */ - (void) rhc; (void) reader; (void) topic; (void) tkmap; - return DDS_RETCODE_OK; -} - -static const struct dds_rhc_ops dds_rhc_default_ops = { - .rhc_ops = { - .store = dds_rhc_default_store_wrap, - .unregister_wr = dds_rhc_default_unregister_wr_wrap, - .relinquish_ownership = dds_rhc_default_relinquish_ownership_wrap, - .set_qos = dds_rhc_default_set_qos_wrap, - .free = dds_rhc_default_free_wrap - }, - .read = dds_rhc_default_read_wrap, - .take = dds_rhc_default_take_wrap, - .takecdr = dds_rhc_default_takecdr_wrap, - .add_readcondition = dds_rhc_default_add_readcondition_wrap, - .remove_readcondition = dds_rhc_default_remove_readcondition_wrap, - .lock_samples = dds_rhc_default_lock_samples_wrap, - .associate = dds_rhc_default_associate -}; - -static unsigned qmask_of_sample (const struct rhc_sample *s) +static uint32_t qmask_of_sample (const struct rhc_sample *s) { return s->isread ? DDS_READ_SAMPLE_STATE : DDS_NOT_READ_SAMPLE_STATE; } -static unsigned qmask_of_invsample (const struct rhc_instance *i) +static uint32_t qmask_of_invsample (const struct rhc_instance *i) { return i->inv_isread ? DDS_READ_SAMPLE_STATE : DDS_NOT_READ_SAMPLE_STATE; } @@ -467,23 +402,24 @@ static bool inst_has_unread (const struct rhc_instance *i) return inst_nread (i) < inst_nsamples (i); } -static void topicless_to_clean_invsample (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, void *sample, void **bufptr, void *buflim) +static bool topicless_to_clean_invsample (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, void *sample, void **bufptr, void *buflim) { /* ddsi_serdata_topicless_to_sample just deals with the key value, without paying any attention to attributes; but that makes life harder for the user: the attributes of an invalid sample would be garbage, but would nonetheless have to be freed in the end. Zero'ing it explicitly solves that problem. */ ddsi_sertopic_free_sample (topic, sample, DDS_FREE_CONTENTS); ddsi_sertopic_zero_sample (topic, sample); - ddsi_serdata_topicless_to_sample (topic, d, sample, bufptr, buflim); + return ddsi_serdata_topicless_to_sample (topic, d, sample, bufptr, buflim); } -static unsigned qmask_of_inst (const struct rhc_instance *inst); +static uint32_t qmask_of_inst (const struct rhc_instance *inst); static void free_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, struct rhc_sample *s); static void get_trigger_info_cmn (struct trigger_info_cmn *info, struct rhc_instance *inst); static void get_trigger_info_pre (struct trigger_info_pre *info, struct rhc_instance *inst); static void init_trigger_info_qcond (struct trigger_info_qcond *qc); -static void drop_instance_noupdate_no_writers (struct dds_rhc_default *rhc, struct rhc_instance *inst); +static void drop_instance_noupdate_no_writers (struct dds_rhc_default * __restrict rhc, struct rhc_instance * __restrict * __restrict instptr); static bool update_conditions_locked (struct dds_rhc_default *rhc, bool called_from_insert, const struct trigger_info_pre *pre, const struct trigger_info_post *post, const struct trigger_info_qcond *trig_qc, const struct rhc_instance *inst, struct dds_entity *triggers[], size_t *ntriggers); +static void account_for_nonempty_to_empty_transition (struct dds_rhc_default * __restrict rhc, struct rhc_instance * __restrict * __restrict instptr, const char *__restrict traceprefix); #ifndef NDEBUG static int rhc_check_counts_locked (struct dds_rhc_default *rhc, bool check_conds, bool check_qcmask); #endif @@ -579,18 +515,7 @@ static void drop_expired_samples (struct dds_rhc_default *rhc, struct rhc_sample get_trigger_info_cmn (&post.c, inst); update_conditions_locked (rhc, false, &pre, &post, &trig_qc, inst, NULL, &ntriggers); if (inst_is_empty (inst)) - { - remove_inst_from_nonempty_list (rhc, inst); - if (inst->isdisposed) - rhc->n_not_alive_disposed--; - if (inst->wrcount == 0) - { - TRACE ("; iid %"PRIx64" #0,empty,drop", inst->iid); - if (!inst->isdisposed) - rhc->n_not_alive_no_writers--; - drop_instance_noupdate_no_writers (rhc, inst); - } - } + account_for_nonempty_to_empty_transition(rhc, &inst, "; "); TRACE (")\n"); } @@ -670,8 +595,16 @@ struct dds_rhc *dds_rhc_default_new (dds_reader *reader, const struct ddsi_serto return dds_rhc_default_new_xchecks (reader, &reader->m_entity.m_domain->gv, topic, (reader->m_entity.m_domain->gv.config.enabled_xchecks & DDS_XCHECK_RHC) != 0); } -static void dds_rhc_default_set_qos (struct dds_rhc_default * rhc, const dds_qos_t * qos) +static dds_return_t dds_rhc_default_associate (struct dds_rhc *rhc, dds_reader *reader, const struct ddsi_sertopic *topic, struct ddsi_tkmap *tkmap) { + /* ignored out of laziness */ + (void) rhc; (void) reader; (void) topic; (void) tkmap; + return DDS_RETCODE_OK; +} + +static void dds_rhc_default_set_qos (struct ddsi_rhc *rhc_common, const dds_qos_t * qos) +{ + struct dds_rhc_default * const rhc = (struct dds_rhc_default *) rhc_common; /* Set read related QoS */ rhc->max_samples = qos->resource_limits.max_samples; @@ -762,9 +695,14 @@ static void inst_clear_invsample_if_exists (struct dds_rhc_default *rhc, struct inst_clear_invsample (rhc, inst, trig_qc); } -static void inst_set_invsample (struct dds_rhc_default *rhc, struct rhc_instance *inst, struct trigger_info_qcond *trig_qc, bool *nda) +static void inst_set_invsample (struct dds_rhc_default *rhc, struct rhc_instance *inst, struct trigger_info_qcond *trig_qc, bool * __restrict nda) { - if (!inst->inv_exists || inst->inv_isread) + if (inst->inv_exists && !inst->inv_isread) + { + /* FIXME: should this indeed trigger a "notify data available" event?*/ + *nda = true; + } + else { /* Obviously optimisable, but that is perhaps not worth the bother */ inst_clear_invsample_if_exists (rhc, inst, trig_qc); @@ -782,7 +720,7 @@ static void free_empty_instance (struct rhc_instance *inst, struct dds_rhc_defau assert (inst_is_empty (inst)); ddsi_tkmap_instance_unref (rhc->tkmap, inst->tk); #ifdef DDSI_INCLUDE_DEADLINE_MISSED - if (!inst->isdisposed) + if (inst->deadline_reg) deadline_unregister_instance_locked (&rhc->deadline, &inst->deadline); #endif ddsrt_free (inst); @@ -817,8 +755,9 @@ static void free_instance_rhc_free (struct rhc_instance *inst, struct dds_rhc_de free_empty_instance(inst, rhc); } -static uint32_t dds_rhc_default_lock_samples (struct dds_rhc_default *rhc) +static uint32_t dds_rhc_default_lock_samples (struct dds_rhc *rhc_common) { + struct dds_rhc_default * const rhc = (struct dds_rhc_default *) rhc_common; uint32_t no; ddsrt_mutex_lock (&rhc->lock); no = rhc->n_vsamples + rhc->n_invsamples; @@ -834,8 +773,9 @@ static void free_instance_rhc_free_wrap (void *vnode, void *varg) free_instance_rhc_free (vnode, varg); } -static void dds_rhc_default_free (struct dds_rhc_default *rhc) +static void dds_rhc_default_free (struct ddsi_rhc *rhc_common) { + struct dds_rhc_default *rhc = (struct dds_rhc_default *) rhc_common; #ifdef DDSI_INCLUDE_LIFESPAN dds_rhc_default_sample_expired_cb (rhc, DDSRT_MTIME_NEVER); lifespan_fini (&rhc->lifespan); @@ -902,7 +842,7 @@ static bool trigger_info_differs (const struct dds_rhc_default *rhc, const struc trig_qc->dec_sample_read != trig_qc->inc_sample_read); } -static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct ddsi_writer_info *wrinfo, const struct ddsi_serdata *sample, status_cb_data_t *cb_data, struct trigger_info_qcond *trig_qc) +static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct ddsi_writer_info *wrinfo, const struct ddsi_serdata *sample, status_cb_data_t *cb_data, struct trigger_info_qcond *trig_qc, bool * __restrict nda) { struct rhc_sample *s; @@ -985,11 +925,6 @@ static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, s->lifespan.t_expire = wrinfo->lifespan_exp; lifespan_register_sample_locked (&rhc->lifespan, &s->lifespan); #endif -#ifdef DDSI_INCLUDE_DEADLINE_MISSED - /* Only renew the deadline missed counter in case the sample is actually stored in the rhc */ - if (!inst->isdisposed) - deadline_renew_instance_locked (&rhc->deadline, &inst->deadline); -#endif s->conds = 0; if (rhc->nqconds != 0) @@ -1001,6 +936,7 @@ static bool add_sample (struct dds_rhc_default *rhc, struct rhc_instance *inst, trig_qc->inc_conds_sample = s->conds; inst->latest = s; + *nda = true; return true; } @@ -1080,8 +1016,9 @@ static void update_inst (struct rhc_instance *inst, const struct ddsi_writer_inf inst->strength = wrinfo->ownership_strength; } -static void drop_instance_noupdate_no_writers (struct dds_rhc_default *rhc, struct rhc_instance *inst) +static void drop_instance_noupdate_no_writers (struct dds_rhc_default *__restrict rhc, struct rhc_instance * __restrict * __restrict instptr) { + struct rhc_instance *inst = *instptr; int ret; assert (inst_is_empty (inst)); @@ -1094,9 +1031,10 @@ static void drop_instance_noupdate_no_writers (struct dds_rhc_default *rhc, stru (void) ret; free_empty_instance (inst, rhc); + *instptr = NULL; } -static void dds_rhc_register (struct dds_rhc_default *rhc, struct rhc_instance *inst, uint64_t wr_iid, bool iid_update) +static void dds_rhc_register (struct dds_rhc_default *rhc, struct rhc_instance *inst, uint64_t wr_iid, bool autodispose, bool sample_accepted, bool * __restrict nda) { const uint64_t inst_wr_iid = inst->wr_iid_islive ? inst->wr_iid : 0; @@ -1117,26 +1055,30 @@ static void dds_rhc_register (struct dds_rhc_default *rhc, struct rhc_instance * else. */ TRACE ("cached"); assert (inst->wrcount > 0); - return; } - - if (inst->wrcount == 0) + else if (inst->wrcount == 0) { /* Currently no writers at all */ assert (!inst->wr_iid_islive); - /* to avoid wr_iid update when register is called for sample rejected */ - if (iid_update) - { - inst->wr_iid = wr_iid; + /* When registering a writer based on a rejected sample and causing + the instance to transition from not-alive to alive, we do want + to generate an invalid sample with the id of the newly registered + (or re-registered) writer, but we don't want inst_accepts_sample + to be affected (it was "too old" in the ordering). wr_iid_islive + determines whether wr_iid is meaningful, so setting wr_iid while + leaving wr_iid_islive false gets us the desired behaviour. */ + inst->wr_iid = wr_iid; + if (sample_accepted) inst->wr_iid_islive = 1; - } inst->wrcount++; inst->no_writers_gen++; + inst->autodispose = autodispose; TRACE ("new1"); if (!inst_is_empty (inst) && !inst->isdisposed) rhc->n_not_alive_no_writers--; + *nda = true; } else if (inst_wr_iid == 0 && inst->wrcount == 1) { @@ -1158,6 +1100,8 @@ static void dds_rhc_register (struct dds_rhc_default *rhc, struct rhc_instance * if (lwregs_add (&rhc->registrations, inst->iid, wr_iid)) { inst->wrcount++; + if (autodispose) + inst->autodispose = 1; TRACE ("new2iidnull"); } else @@ -1168,7 +1112,7 @@ static void dds_rhc_register (struct dds_rhc_default *rhc, struct rhc_instance * TRACE ("restore"); } /* to avoid wr_iid update when register is called for sample rejected */ - if (iid_update) + if (sample_accepted) { inst->wr_iid = wr_iid; inst->wr_iid_islive = 1; @@ -1194,6 +1138,8 @@ static void dds_rhc_register (struct dds_rhc_default *rhc, struct rhc_instance * registers a previously unknown writer or not */ TRACE ("new3"); inst->wrcount++; + if (autodispose) + inst->autodispose = 1; } else { @@ -1202,7 +1148,7 @@ static void dds_rhc_register (struct dds_rhc_default *rhc, struct rhc_instance * assert (inst->wrcount >= 2); /* the most recent writer gets the fast path */ /* to avoid wr_iid update when register is called for sample rejected */ - if (iid_update) + if (sample_accepted) { inst->wr_iid = wr_iid; inst->wr_iid_islive = 1; @@ -1220,7 +1166,26 @@ static void account_for_empty_to_nonempty_transition (struct dds_rhc_default *rh rhc->n_not_alive_no_writers++; } -static int rhc_unregister_isreg_w_sideeffects (struct dds_rhc_default *rhc, const struct rhc_instance *inst, uint64_t wr_iid) +static void account_for_nonempty_to_empty_transition (struct dds_rhc_default *__restrict rhc, struct rhc_instance * __restrict * __restrict instptr, const char * __restrict traceprefix) +{ + struct rhc_instance *inst = *instptr; + assert (inst_is_empty (inst)); + remove_inst_from_nonempty_list (rhc, inst); + if (inst->isdisposed) + rhc->n_not_alive_disposed--; + if (inst->wrcount == 0) + { + TRACE ("%siid %"PRIx64" #0,empty,drop\n", traceprefix, inst->iid); + if (!inst->isdisposed) + { + /* disposed has priority over no writers (why not just 2 bits?) */ + rhc->n_not_alive_no_writers--; + } + drop_instance_noupdate_no_writers (rhc, instptr); + } +} + +static int rhc_unregister_delete_registration (struct dds_rhc_default *rhc, const struct rhc_instance *inst, uint64_t wr_iid) { /* Returns 1 if last registration just disappeared */ if (inst->wrcount == 0) @@ -1264,9 +1229,11 @@ static int rhc_unregister_isreg_w_sideeffects (struct dds_rhc_default *rhc, cons } } -static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct ddsi_writer_info * __restrict wrinfo, ddsrt_wctime_t tstamp, struct trigger_info_qcond *trig_qc, bool *nda) +static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct ddsi_writer_info * __restrict wrinfo, ddsrt_wctime_t tstamp, struct trigger_info_qcond *trig_qc, bool * __restrict nda) { assert (inst->wrcount > 0); + if (wrinfo->auto_dispose) + inst->autodispose = 1; if (--inst->wrcount > 0) { @@ -1288,20 +1255,28 @@ static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_in if (!inst_is_empty (inst)) { /* Instance still has content - do not drop until application - takes the last sample. Set the invalid sample if the latest - sample has been read already, so that the application can - read the change to not-alive. (If the latest sample is still - unread, we don't bother, even though it means the application - won't see the timestamp for the unregister event. It shouldn't - care.) */ - if (inst->latest == NULL || inst->latest->isread) - { - inst_set_invsample (rhc, inst, trig_qc, nda); - update_inst (inst, wrinfo, false, tstamp); - } + takes the last sample. Set the invalid sample if the latest + sample has been read already, so that the application can + read the change to not-alive. (If the latest sample is still + unread, we don't bother, even though it means the application + won't see the timestamp for the unregister event. It shouldn't + care.) */ if (!inst->isdisposed) { - rhc->n_not_alive_no_writers++; + if (inst->latest == NULL || inst->latest->isread) + { + inst_set_invsample (rhc, inst, trig_qc, nda); + update_inst (inst, wrinfo, false, tstamp); + } + if (!inst->autodispose) + rhc->n_not_alive_no_writers++; + else + { + TRACE (",autodispose"); + inst->isdisposed = 1; + rhc->n_not_alive_disposed++; + } + *nda = true; } inst->wr_iid_islive = 0; return 0; @@ -1309,8 +1284,7 @@ static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_in else if (inst->isdisposed) { /* No content left, no registrations left, so drop */ - TRACE (",#0,empty,disposed,drop"); - drop_instance_noupdate_no_writers (rhc, inst); + TRACE (",#0,empty,nowriters,disposed"); return 1; } else @@ -1320,35 +1294,34 @@ static int rhc_unregister_updateinst (struct dds_rhc_default *rhc, struct rhc_in assert (inst_is_empty (inst)); inst_set_invsample (rhc, inst, trig_qc, nda); update_inst (inst, wrinfo, false, tstamp); + if (inst->autodispose) + { + TRACE (",autodispose"); + inst->isdisposed = 1; + } account_for_empty_to_nonempty_transition (rhc, inst); inst->wr_iid_islive = 0; + *nda = true; return 0; } } } -static bool dds_rhc_unregister (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct ddsi_writer_info * __restrict wrinfo, ddsrt_wctime_t tstamp, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc) +static void dds_rhc_unregister (struct dds_rhc_default *rhc, struct rhc_instance *inst, const struct ddsi_writer_info * __restrict wrinfo, ddsrt_wctime_t tstamp, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc, bool * __restrict nda) { - bool notify_data_available = false; - - /* 'post' always gets set; instance may have been freed upon return. */ + /* 'post' always gets set */ TRACE (" unregister:"); - if (!rhc_unregister_isreg_w_sideeffects (rhc, inst, wrinfo->iid)) - { + if (!rhc_unregister_delete_registration (rhc, inst, wrinfo->iid)) { /* other registrations remain */ get_trigger_info_cmn (&post->c, inst); - } - else if (rhc_unregister_updateinst (rhc, inst, wrinfo, tstamp, trig_qc, ¬ify_data_available)) - { + } else if (rhc_unregister_updateinst (rhc, inst, wrinfo, tstamp, trig_qc, nda)) { /* instance dropped */ init_trigger_info_cmn_nonmatch (&post->c); - } - else - { + } else { /* no writers remain, but instance not empty */ get_trigger_info_cmn (&post->c, inst); } - return notify_data_available; + TRACE (" nda=%d\n", *nda); } static struct rhc_instance *alloc_new_instance (struct dds_rhc_default *rhc, const struct ddsi_writer_info *wrinfo, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk) @@ -1360,8 +1333,10 @@ static struct rhc_instance *alloc_new_instance (struct dds_rhc_default *rhc, con memset (inst, 0, sizeof (*inst)); inst->iid = tk->m_iid; inst->tk = tk; - inst->wrcount = (serdata->statusinfo & NN_STATUSINFO_UNREGISTER) ? 0 : 1; + inst->wrcount = 1; inst->isdisposed = (serdata->statusinfo & NN_STATUSINFO_DISPOSE) != 0; + inst->autodispose = wrinfo->auto_dispose; + inst->deadline_reg = 0; inst->isnew = 1; inst->a_sample_free = 1; inst->conds = 0; @@ -1381,16 +1356,10 @@ static struct rhc_instance *alloc_new_instance (struct dds_rhc_default *rhc, con inst->conds |= c->m_query.m_qcmask; } } - -#ifdef DDSI_INCLUDE_DEADLINE_MISSED - if (!inst->isdisposed) - deadline_register_instance_locked (&rhc->deadline, &inst->deadline, ddsrt_time_monotonic ()); -#endif - return inst; } -static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst, struct dds_rhc_default *rhc, const struct ddsi_writer_info *wrinfo, struct ddsi_serdata *sample, struct ddsi_tkmap_instance *tk, const bool has_data, status_cb_data_t *cb_data, struct trigger_info_post *post, struct trigger_info_qcond *trig_qc) +static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst, struct dds_rhc_default *rhc, const struct ddsi_writer_info *wrinfo, struct ddsi_serdata *sample, struct ddsi_tkmap_instance *tk, const bool has_data, status_cb_data_t *cb_data, struct trigger_info_qcond *trig_qc, bool * __restrict nda) { struct rhc_instance *inst; int ret; @@ -1428,7 +1397,7 @@ static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst inst = alloc_new_instance (rhc, wrinfo, sample, tk); if (has_data) { - if (!add_sample (rhc, inst, wrinfo, sample, cb_data, trig_qc)) + if (!add_sample (rhc, inst, wrinfo, sample, cb_data, trig_qc, nda)) { free_empty_instance (inst, rhc); return RHC_REJECTED; @@ -1436,10 +1405,8 @@ static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst } else { - if (inst->isdisposed) { - bool nda_dummy = false; - inst_set_invsample (rhc, inst, trig_qc, &nda_dummy); - } + if (inst->isdisposed) + inst_set_invsample (rhc, inst, trig_qc, nda); } account_for_empty_to_nonempty_transition (rhc, inst); @@ -1448,21 +1415,96 @@ static rhc_store_result_t rhc_store_new_instance (struct rhc_instance **out_inst (void) ret; rhc->n_instances++; rhc->n_new++; - get_trigger_info_cmn (&post->c, inst); *out_inst = inst; return RHC_STORED; } +static void postprocess_instance_update (struct dds_rhc_default * __restrict rhc, struct rhc_instance * __restrict * __restrict instptr, const struct trigger_info_pre *pre, const struct trigger_info_post *post, struct trigger_info_qcond *trig_qc, dds_entity *triggers[], size_t *ntriggers) +{ + { + struct rhc_instance *inst = *instptr; + +#ifdef DDSI_INCLUDE_DEADLINE_MISSED + if (inst->isdisposed) + { + if (inst->deadline_reg) + { + inst->deadline_reg = 0; + deadline_unregister_instance_locked (&rhc->deadline, &inst->deadline); + } + } + else + { + if (inst->deadline_reg) + deadline_renew_instance_locked (&rhc->deadline, &inst->deadline); + else + { + deadline_register_instance_locked (&rhc->deadline, &inst->deadline, ddsrt_time_monotonic ()); + inst->deadline_reg = 1; + } + } +#endif + + if (inst_is_empty (inst) && inst->wrcount == 0) + { + drop_instance_noupdate_no_writers (rhc, instptr); + } + } + + if (trigger_info_differs (rhc, pre, post, trig_qc)) + update_conditions_locked (rhc, true, pre, post, trig_qc, *instptr, triggers, ntriggers); + + assert (rhc_check_counts_locked (rhc, true, true)); +} + +static void update_viewstate_and_disposedness (struct dds_rhc_default * __restrict rhc, struct rhc_instance * __restrict inst, bool has_data, bool not_alive, bool is_dispose, bool * __restrict nda) +{ + /* Sample arriving for a NOT_ALIVE instance => view state NEW */ + if (has_data && not_alive) + { + TRACE (" notalive->alive"); + inst->isnew = 1; + *nda = true; + } + + /* Desired effect on instance state and disposed_gen: + op DISPOSED NOT_DISPOSED + W ND;gen++ ND + D D D + WD D;gen++ D + Simplest way is to toggle istate when it is currently DISPOSED + and the operation is WD. */ + if (has_data && inst->isdisposed) + { + TRACE (" disposed->notdisposed"); + inst->disposed_gen++; + if (!is_dispose) + inst->isdisposed = 0; + *nda = true; + } + if (is_dispose) + { + bool wasdisposed = inst->isdisposed; + if (!inst->isdisposed) + { + inst->isdisposed = 1; + *nda = true; + } + TRACE (" dispose(%d)", !wasdisposed); + } +} + /* dds_rhc_store: DDSI up call into read cache to store new sample. Returns whether sample delivered (true unless a reliable sample rejected). */ -static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) +static bool dds_rhc_default_store (struct ddsi_rhc * __restrict rhc_common, const struct ddsi_writer_info * __restrict wrinfo, struct ddsi_serdata * __restrict sample, struct ddsi_tkmap_instance * __restrict tk) { + struct dds_rhc_default * const __restrict rhc = (struct dds_rhc_default * __restrict) rhc_common; const uint64_t wr_iid = wrinfo->iid; - const unsigned statusinfo = sample->statusinfo; + const uint32_t statusinfo = sample->statusinfo; const bool has_data = (sample->kind == SDK_DATA); const int is_dispose = (statusinfo & NN_STATUSINFO_DISPOSE) != 0; struct rhc_instance dummy_instance; @@ -1472,22 +1514,25 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons struct trigger_info_qcond trig_qc; rhc_store_result_t stored; status_cb_data_t cb_data; /* Callback data for reader status callback */ - bool delivered = true; - bool notify_data_available = false; + bool notify_data_available; + dds_entity *triggers[MAX_FAST_TRIGGERS]; + size_t ntriggers; - TRACE ("rhc_store(%"PRIx64",%"PRIx64" si %x has_data %d:", tk->m_iid, wr_iid, statusinfo, has_data); + TRACE ("rhc_store %"PRIx64",%"PRIx64" si %x has_data %d:", tk->m_iid, wr_iid, statusinfo, has_data); if (!has_data && statusinfo == 0) { /* Write with nothing but a key -- I guess that would be a register, which we do implicitly. (Currently DDSI2 won't allow it through anyway.) */ - TRACE (" ignore explicit register)\n"); - return delivered; + TRACE (" ignore explicit register\n"); + return true; } + notify_data_available = false; dummy_instance.iid = tk->m_iid; stored = RHC_FILTERED; cb_data.raw_status_id = -1; + ntriggers = 0; init_trigger_info_qcond (&trig_qc); @@ -1502,19 +1547,17 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons */ if (!has_data && !is_dispose) { - TRACE (" disp/unreg on unknown instance"); + TRACE (" unreg on unknown instance\n"); goto error_or_nochange; } else { - TRACE (" new instance"); - stored = rhc_store_new_instance (&inst, rhc, wrinfo, sample, tk, has_data, &cb_data, &post, &trig_qc); + TRACE (" new instance\n"); + stored = rhc_store_new_instance (&inst, rhc, wrinfo, sample, tk, has_data, &cb_data, &trig_qc, ¬ify_data_available); if (stored != RHC_STORED) - { goto error_or_nochange; - } + init_trigger_info_cmn_nonmatch (&pre.c); - notify_data_available = true; } } else if (!inst_accepts_sample (rhc, inst, wrinfo, sample, has_data)) @@ -1524,29 +1567,29 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons will raise a SAMPLE_REJECTED, and indicate that the system should kill itself.) Not letting instances go to ALIVE or NEW based on a rejected sample - (no one knows, it seemed) */ - TRACE (" instance rejects sample"); + TRACE (" instance rejects sample\n"); get_trigger_info_pre (&pre, inst); if (has_data || is_dispose) { - dds_rhc_register (rhc, inst, wr_iid, false); + dds_rhc_register (rhc, inst, wr_iid, wrinfo->auto_dispose, false, ¬ify_data_available); + if (notify_data_available) + { + if (inst->latest == NULL || inst->latest->isread) + { + const bool was_empty = inst_is_empty (inst); + inst_set_invsample (rhc, inst, &trig_qc, ¬ify_data_available); + if (was_empty) + account_for_empty_to_nonempty_transition (rhc, inst); + } + } } - if (statusinfo & NN_STATUSINFO_UNREGISTER) - { - if (dds_rhc_unregister (rhc, inst, wrinfo, sample->timestamp, &post, &trig_qc)) - notify_data_available = true; - } - else - { - get_trigger_info_cmn (&post.c, inst); - } - /* notify sample lost */ + /* notify sample lost */ cb_data.raw_status_id = (int) DDS_SAMPLE_LOST_STATUS_ID; cb_data.extra = 0; cb_data.handle = 0; cb_data.add = true; - goto error_or_nochange; } else { @@ -1565,7 +1608,6 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons const bool old_isdisposed = inst->isdisposed; const bool old_isnew = inst->isnew; const bool was_empty = inst_is_empty (inst); - int inst_became_disposed = 0; /* Not just an unregister, so a write and/or a dispose (possibly combined with an unregister). Write & dispose create a @@ -1575,80 +1617,29 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons (i.e., out-of-memory), abort the operation and hope that the caller can still notify the application. */ - dds_rhc_register (rhc, inst, wr_iid, true); + dds_rhc_register (rhc, inst, wr_iid, wrinfo->auto_dispose, true, ¬ify_data_available); + update_viewstate_and_disposedness (rhc, inst, has_data, not_alive, is_dispose, ¬ify_data_available); - /* Sample arriving for a NOT_ALIVE instance => view state NEW */ - if (has_data && not_alive) - { - TRACE (" notalive->alive"); - inst->isnew = 1; - } - - /* Desired effect on instance state and disposed_gen: - op DISPOSED NOT_DISPOSED - W ND;gen++ ND - D D D - WD D;gen++ D - Simplest way is to toggle istate when it is currently DISPOSED - and the operation is WD. */ - if (has_data && inst->isdisposed) - { - TRACE (" disposed->notdisposed"); - inst->isdisposed = 0; - inst->disposed_gen++; -#ifdef DDSI_INCLUDE_DEADLINE_MISSED - if (!is_dispose) - deadline_register_instance_locked (&rhc->deadline, &inst->deadline, ddsrt_time_monotonic ()); -#endif - } - if (is_dispose) - { - inst->isdisposed = 1; - inst_became_disposed = !old_isdisposed; -#ifdef DDSI_INCLUDE_DEADLINE_MISSED - if (inst_became_disposed) - deadline_unregister_instance_locked (&rhc->deadline, &inst->deadline); -#endif - TRACE (" dispose(%d)", inst_became_disposed); - } - - /* Only need to add a sample to the history if the input actually - is a sample. */ + /* Only need to add a sample to the history if the input actually is a sample. */ if (has_data) { TRACE (" add_sample"); - if (!add_sample (rhc, inst, wrinfo, sample, &cb_data, &trig_qc)) + if (!add_sample (rhc, inst, wrinfo, sample, &cb_data, &trig_qc, ¬ify_data_available)) { - TRACE ("(reject)"); + TRACE ("(reject)\n"); stored = RHC_REJECTED; /* FIXME: fix the bad rejection handling, probably put back in a proper rollback, until then a band-aid like this will have to do: */ inst->isnew = old_isnew; if (old_isdisposed) - { inst->disposed_gen--; - if (!inst->isdisposed) - { - inst->isdisposed = 1; -#ifdef DDSI_INCLUDE_DEADLINE_MISSED - deadline_unregister_instance_locked (&rhc->deadline, &inst->deadline); -#endif - } - } - else if (inst->isdisposed) - { - inst->isdisposed = 0; -#ifdef DDSI_INCLUDE_DEADLINE_MISSED - deadline_register_instance_locked (&rhc->deadline, &inst->deadline, ddsrt_time_monotonic ()); -#endif - } + inst->isdisposed = old_isdisposed; goto error_or_nochange; } - notify_data_available = true; } /* If instance became disposed, add an invalid sample if there are no samples left */ - if (inst_became_disposed && inst->latest == NULL) + if ((bool) inst->isdisposed > old_isdisposed && (inst->latest == NULL || inst->latest->isread)) inst_set_invsample (rhc, inst, &trig_qc, ¬ify_data_available); update_inst (inst, wrinfo, true, sample->timestamp); @@ -1658,7 +1649,7 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons guaranteed that we end up with a non-empty instance: for example, if the instance was disposed & empty, nothing changes. */ - if (inst->latest || inst_became_disposed) + if (inst->latest || (bool) inst->isdisposed > old_isdisposed) { if (was_empty) account_for_empty_to_nonempty_transition (rhc, inst); @@ -1672,40 +1663,35 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons } } + TRACE(" nda=%d\n", notify_data_available); assert (rhc_check_counts_locked (rhc, false, false)); - - if (statusinfo & NN_STATUSINFO_UNREGISTER) - { - /* Either a pure unregister, or the instance rejected the sample - because of time stamps, content filter, or something else. If - the writer unregisters the instance, I think we should ignore - the acceptance filters and process it anyway. - - It is a bit unclear what - - write_w_timestamp(x,1) ; unregister_w_timestamp(x,0) - - actually means if BY_SOURCE ordering is selected: does that - mean an application reading "x" after the write and reading it - again after the unregister will see a change in the - no_writers_generation field? */ - dds_rhc_unregister (rhc, inst, wrinfo, sample->timestamp, &post, &trig_qc); - } - else - { - get_trigger_info_cmn (&post.c, inst); - } } - TRACE (")\n"); + if (statusinfo & NN_STATUSINFO_UNREGISTER) + { + /* Either a pure unregister, or the instance rejected the sample + because of time stamps, content filter, or something else. If + the writer unregisters the instance, I think we should ignore + the acceptance filters and process it anyway. - dds_entity *triggers[MAX_FAST_TRIGGERS]; - size_t ntriggers = 0; - if (trigger_info_differs (rhc, &pre, &post, &trig_qc)) - update_conditions_locked (rhc, true, &pre, &post, &trig_qc, inst, triggers, &ntriggers); + It is a bit unclear what - assert (rhc_check_counts_locked (rhc, true, true)); + write_w_timestamp(x,1) ; unregister_w_timestamp(x,0) + actually means if BY_SOURCE ordering is selected: does that + mean an application reading "x" after the write and reading it + again after the unregister will see a change in the + no_writers_generation field? */ + dds_rhc_unregister (rhc, inst, wrinfo, sample->timestamp, &post, &trig_qc, ¬ify_data_available); + } + else + { + get_trigger_info_cmn (&post.c, inst); + } + + postprocess_instance_update (rhc, &inst, &pre, &post, &trig_qc, triggers, &ntriggers); + +error_or_nochange: ddsrt_mutex_unlock (&rhc->lock); if (rhc->reader) @@ -1714,28 +1700,13 @@ static bool dds_rhc_default_store (struct dds_rhc_default * __restrict rhc, cons dds_reader_data_available_cb (rhc->reader); for (size_t i = 0; i < ntriggers; i++) dds_entity_status_signal (triggers[i], 0); + if (cb_data.raw_status_id >= 0) + dds_reader_status_cb (&rhc->reader->m_entity, &cb_data); } - - return delivered; - -error_or_nochange: - - if (rhc->reliable && (stored == RHC_REJECTED)) - { - delivered = false; - } - - ddsrt_mutex_unlock (&rhc->lock); - TRACE (")\n"); - - /* Make any reader status callback */ - - if (cb_data.raw_status_id >= 0 && rhc->reader) - dds_reader_status_cb (&rhc->reader->m_entity, &cb_data); - return delivered; + return !(rhc->reliable && stored == RHC_REJECTED); } -static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict rhc, const struct ddsi_writer_info * __restrict wrinfo) +static void dds_rhc_default_unregister_wr (struct ddsi_rhc * __restrict rhc_common, const struct ddsi_writer_info * __restrict wrinfo) { /* Only to be called when writer with ID WR_IID has died. @@ -1752,76 +1723,40 @@ static void dds_rhc_default_unregister_wr (struct dds_rhc_default * __restrict r need to get two IIDs: the one visible to the application in the built-in topics and in get_instance_handle, and one used internally for tracking registrations and unregistrations. */ + struct dds_rhc_default * __restrict const rhc = (struct dds_rhc_default * __restrict) rhc_common; bool notify_data_available = false; struct rhc_instance *inst; struct ddsrt_hh_iter iter; const uint64_t wr_iid = wrinfo->iid; - const int auto_dispose = wrinfo->auto_dispose; - size_t ntriggers = SIZE_MAX; ddsrt_mutex_lock (&rhc->lock); - TRACE ("rhc_unregister_wr_iid(%"PRIx64",%d:\n", wr_iid, auto_dispose); + TRACE ("rhc_unregister_wr_iid %"PRIx64",%d:\n", wr_iid, wrinfo->auto_dispose); for (inst = ddsrt_hh_iter_first (rhc->instances, &iter); inst; inst = ddsrt_hh_iter_next (&iter)) { if ((inst->wr_iid_islive && inst->wr_iid == wr_iid) || lwregs_contains (&rhc->registrations, inst->iid, wr_iid)) { + assert (inst->wrcount > 0); struct trigger_info_pre pre; struct trigger_info_post post; struct trigger_info_qcond trig_qc; get_trigger_info_pre (&pre, inst); init_trigger_info_qcond (&trig_qc); - TRACE (" %"PRIx64":", inst->iid); - - assert (inst->wrcount > 0); - if (auto_dispose && !inst->isdisposed) - { - inst->isdisposed = 1; -#ifdef DDSI_INCLUDE_DEADLINE_MISSED - deadline_unregister_instance_locked (&rhc->deadline, &inst->deadline); -#endif - - /* Set invalid sample for disposing it (unregister may also set it for unregistering) */ - if (inst->latest) - { - assert (!inst->inv_exists); - rhc->n_not_alive_disposed++; - } - else - { - const bool was_empty = inst_is_empty (inst); - inst_set_invsample (rhc, inst, &trig_qc, ¬ify_data_available); - if (was_empty) - account_for_empty_to_nonempty_transition (rhc, inst); - else - rhc->n_not_alive_disposed++; - } - } - - (void) dds_rhc_unregister (rhc, inst, wrinfo, inst->tstamp, &post, &trig_qc); - + dds_rhc_unregister (rhc, inst, wrinfo, inst->tstamp, &post, &trig_qc, ¬ify_data_available); + postprocess_instance_update (rhc, &inst, &pre, &post, &trig_qc, NULL, &ntriggers); TRACE ("\n"); - - notify_data_available = true; - if (trigger_info_differs (rhc, &pre, &post, &trig_qc)) - update_conditions_locked (rhc, true, &pre, &post, &trig_qc, inst, NULL, &ntriggers); - assert (rhc_check_counts_locked (rhc, true, false)); } } - TRACE (")\n"); - ddsrt_mutex_unlock (&rhc->lock); - if (rhc->reader) - { - if (notify_data_available) - dds_reader_data_available_cb (rhc->reader); - } + if (rhc->reader && notify_data_available) + dds_reader_data_available_cb (rhc->reader); } -static void dds_rhc_default_relinquish_ownership (struct dds_rhc_default * __restrict rhc, const uint64_t wr_iid) +static void dds_rhc_default_relinquish_ownership (struct ddsi_rhc * __restrict rhc_common, const uint64_t wr_iid) { + struct dds_rhc_default * __restrict const rhc = (struct dds_rhc_default * __restrict) rhc_common; struct rhc_instance *inst; struct ddsrt_hh_iter iter; ddsrt_mutex_lock (&rhc->lock); @@ -1845,9 +1780,9 @@ static void dds_rhc_default_relinquish_ownership (struct dds_rhc_default * __res instance: ANY, ALIVE, NOT_ALIVE, NOT_ALIVE_NO_WRITERS, NOT_ALIVE_DISPOSED */ -static unsigned qmask_of_inst (const struct rhc_instance *inst) +static uint32_t qmask_of_inst (const struct rhc_instance *inst) { - unsigned qm = inst->isnew ? DDS_NEW_VIEW_STATE : DDS_NOT_NEW_VIEW_STATE; + uint32_t qm = inst->isnew ? DDS_NEW_VIEW_STATE : DDS_NOT_NEW_VIEW_STATE; if (inst->isdisposed) qm |= DDS_NOT_ALIVE_DISPOSED_INSTANCE_STATE; @@ -1905,9 +1840,9 @@ static uint32_t qmask_from_dcpsquery (uint32_t sample_states, uint32_t view_stat return qminv; } -static unsigned qmask_from_mask_n_cond (uint32_t mask, dds_readcond* cond) +static uint32_t qmask_from_mask_n_cond (uint32_t mask, dds_readcond* cond) { - unsigned qminv; + uint32_t qminv; if (mask == NO_STATE_MASK_SET) { if (cond) { /* No mask set, use the one from the condition. */ @@ -1962,12 +1897,11 @@ static void patch_generations (dds_sample_info_t *si, uint32_t last_of_inst) { if (last_of_inst > 0) { - const unsigned ref = + const uint32_t ref = si[last_of_inst].disposed_generation_count + si[last_of_inst].no_writers_generation_count; - uint32_t i; assert (si[last_of_inst].sample_rank == 0); assert (si[last_of_inst].generation_rank == 0); - for (i = 0; i < last_of_inst; i++) + for (uint32_t i = 0; i < last_of_inst; i++) { si[i].sample_rank = last_of_inst - i; si[i].generation_rank = ref - (si[i].disposed_generation_count + si[i].no_writers_generation_count); @@ -2014,418 +1948,321 @@ static bool take_sample_update_conditions (struct dds_rhc_default *rhc, struct t return false; } -static int dds_rhc_read_w_qminv (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, unsigned qminv, dds_instance_handle_t handle, dds_readcond *cond) -{ - uint32_t n = 0; +typedef bool (*read_take_to_sample_t) (const struct ddsi_serdata * __restrict d, void *__restrict *__restrict sample, void * __restrict * __restrict bufptr, void * __restrict buflim); +typedef bool (*read_take_to_invsample_t) (const struct ddsi_sertopic * __restrict topic, const struct ddsi_serdata * __restrict d, void *__restrict * __restrict sample, void * __restrict * __restrict bufptr, void * __restrict buflim); +static bool read_take_to_sample (const struct ddsi_serdata * __restrict d, void * __restrict * __restrict sample, void * __restrict * __restrict bufptr, void * __restrict buflim) +{ + return ddsi_serdata_to_sample (d, *sample, (void **) bufptr, buflim); +} + +static bool read_take_to_invsample (const struct ddsi_sertopic * __restrict topic, const struct ddsi_serdata * __restrict d, void * __restrict * __restrict sample, void * __restrict * __restrict bufptr, void * __restrict buflim) +{ + return topicless_to_clean_invsample (topic, d, *sample, (void **) bufptr, buflim); +} + +static bool read_take_to_sample_ref (const struct ddsi_serdata * __restrict d, void * __restrict * __restrict sample, void * __restrict * __restrict bufptr, void * __restrict buflim) +{ + (void) bufptr; (void) buflim; + *sample = ddsi_serdata_ref (d); + return true; +} + +static bool read_take_to_invsample_ref (const struct ddsi_sertopic * __restrict topic, const struct ddsi_serdata * __restrict d, void * __restrict * __restrict sample, void * __restrict * __restrict bufptr, void * __restrict buflim) +{ + (void) topic; (void) bufptr; (void) buflim; + *sample = ddsi_serdata_ref (d); + return true; +} + +static int32_t read_w_qminv_inst (struct dds_rhc_default * const __restrict rhc, struct rhc_instance * const __restrict inst, void * __restrict * __restrict values, dds_sample_info_t * __restrict info_seq, const int32_t max_samples, const uint32_t qminv, const dds_querycond_mask_t qcmask, read_take_to_sample_t to_sample, read_take_to_invsample_t to_invsample) +{ + assert (max_samples > 0); + if (inst_is_empty (inst) || (qmask_of_inst (inst) & qminv) != 0) + { + /* no samples present, or the instance/view state doesn't match */ + return 0; + } + + struct trigger_info_pre pre; + struct trigger_info_post post; + struct trigger_info_qcond trig_qc; + const uint32_t nread = inst_nread (inst); + int32_t n = 0; + get_trigger_info_pre (&pre, inst); + init_trigger_info_qcond (&trig_qc); + + /* any valid samples precede a possible invalid sample */ + if (inst->latest) + { + struct rhc_sample *sample = inst->latest->next, * const end1 = sample; + do { + if ((qmask_of_sample (sample) & qminv) == 0 && (qcmask == 0 || (sample->conds & qcmask))) + { + /* sample state matches too */ + set_sample_info (info_seq + n, inst, sample); + to_sample (sample->sample, values + n, 0, 0); + if (!sample->isread) + { + read_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, sample->conds, false); + sample->isread = true; + inst->nvread++; + rhc->n_vread++; + } + ++n; + } + sample = sample->next; + } while (n < max_samples && sample != end1); + } + + /* add an invalid sample if it exists, matches and there is room in the result */ + if (inst->inv_exists && n < max_samples && (qmask_of_invsample (inst) & qminv) == 0 && (qcmask == 0 || (inst->conds & qcmask))) + { + set_sample_info_invsample (info_seq + n, inst); + to_invsample (rhc->topic, inst->tk->m_sample, values + n, 0, 0); + if (!inst->inv_isread) + { + read_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, inst->conds, false); + inst->inv_isread = 1; + rhc->n_invread++; + } + ++n; + } + + /* set generation counts in sample info now that we can compute them; update instance state */ + bool inst_became_old = false; + if (n > 0) + { + patch_generations (info_seq, (uint32_t) n - 1); + if (inst->isnew) + { + inst_became_old = true; + inst->isnew = 0; + rhc->n_new--; + } + } + if (nread != inst_nread (inst) || inst_became_old) + { + size_t ntriggers = SIZE_MAX; + get_trigger_info_cmn (&post.c, inst); + assert (trig_qc.dec_conds_invsample == 0); + assert (trig_qc.dec_conds_sample == 0); + assert (trig_qc.inc_conds_invsample == 0); + assert (trig_qc.inc_conds_sample == 0); + update_conditions_locked (rhc, false, &pre, &post, &trig_qc, inst, NULL, &ntriggers); + } + return n; +} + +static int32_t take_w_qminv_inst (struct dds_rhc_default * const __restrict rhc, struct rhc_instance * __restrict * __restrict instptr, void * __restrict * __restrict values, dds_sample_info_t * __restrict info_seq, const int32_t max_samples, const uint32_t qminv, const dds_querycond_mask_t qcmask, size_t * __restrict ntriggers, read_take_to_sample_t to_sample, read_take_to_invsample_t to_invsample) +{ + struct rhc_instance *inst = *instptr; + assert (max_samples > 0); + if (inst_is_empty (inst) || (qmask_of_inst (inst) & qminv) != 0) + { + /* no samples present, or the instance/view state doesn't match */ + return 0; + } + + struct trigger_info_pre pre; + struct trigger_info_post post; + struct trigger_info_qcond trig_qc; + int32_t n = 0; + get_trigger_info_pre (&pre, inst); + init_trigger_info_qcond (&trig_qc); + + if (inst->latest) + { + struct rhc_sample *psample = inst->latest; + struct rhc_sample *sample = psample->next; + uint32_t nvsamples = inst->nvsamples; + while (nvsamples--) + { + struct rhc_sample * const sample1 = sample->next; + if ((qmask_of_sample (sample) & qminv) != 0 || (qcmask != 0 && !(sample->conds & qcmask))) + { + /* sample mask doesn't match, or content predicate doesn't match */ + psample = sample; + } + else + { + take_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, sample->conds, sample->isread); + set_sample_info (info_seq + n, inst, sample); + to_sample (sample->sample, values + n, 0, 0); + rhc->n_vsamples--; + if (sample->isread) + { + inst->nvread--; + rhc->n_vread--; + } + if (--inst->nvsamples == 0) + inst->latest = NULL; + else + { + if (inst->latest == sample) + inst->latest = psample; + psample->next = sample1; + } + free_sample (rhc, inst, sample); + if (++n == max_samples) + break; + } + sample = sample1; + } + } + + if (inst->inv_exists && n < max_samples && (qmask_of_invsample (inst) & qminv) == 0 && (qcmask == 0 || (inst->conds & qcmask) != 0)) + { + struct trigger_info_qcond dummy_trig_qc; +#ifndef NDEBUG + init_trigger_info_qcond (&dummy_trig_qc); +#endif + take_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, inst->conds, inst->inv_isread); + set_sample_info_invsample (info_seq + n, inst); + to_invsample (rhc->topic, inst->tk->m_sample, values + n, 0, 0); + inst_clear_invsample (rhc, inst, &dummy_trig_qc); + ++n; + } + + if (n > 0) + { + patch_generations (info_seq, (uint32_t) n - 1); + if (inst->isnew) + { + inst->isnew = 0; + rhc->n_new--; + } + /* if nsamples = 0, it won't match anything, so no need to do anything here for drop_instance_noupdate_no_writers */ + get_trigger_info_cmn (&post.c, inst); + assert (trig_qc.dec_conds_invsample == 0); + assert (trig_qc.dec_conds_sample == 0); + assert (trig_qc.inc_conds_invsample == 0); + assert (trig_qc.inc_conds_sample == 0); + update_conditions_locked (rhc, false, &pre, &post, &trig_qc, inst, NULL, ntriggers); + } + + if (inst_is_empty (inst)) + account_for_nonempty_to_empty_transition (rhc, instptr, "take: "); + return n; +} + +static int32_t read_w_qminv (struct dds_rhc_default * __restrict rhc, bool lock, void * __restrict * __restrict values, dds_sample_info_t * __restrict info_seq, int32_t max_samples, uint32_t qminv, dds_instance_handle_t handle, dds_readcond * __restrict cond, read_take_to_sample_t to_sample, read_take_to_invsample_t to_invsample) +{ + int32_t n = 0; + assert (max_samples > 0); if (lock) { ddsrt_mutex_lock (&rhc->lock); } - TRACE ("read_w_qminv(%p,%p,%p,%"PRIu32",%x,%p) - inst %"PRIu32" nonempty %"PRIu32" disp %"PRIu32" nowr %"PRIu32" new %"PRIu32" samples %"PRIu32"+%"PRIu32" read %"PRIu32"+%"PRIu32"\n", - (void *) rhc, (void *) values, (void *) info_seq, max_samples, qminv, (void *) cond, + TRACE ("read_w_qminv(%p,%p,%p,%"PRId32",%x,%"PRIx64",%p) - inst %"PRIu32" nonempty %"PRIu32" disp %"PRIu32" nowr %"PRIu32" new %"PRIu32" samples %"PRIu32"+%"PRIu32" read %"PRIu32"+%"PRIu32"\n", + (void *) rhc, (void *) values, (void *) info_seq, max_samples, qminv, handle, (void *) cond, rhc->n_instances, rhc->n_nonempty_instances, rhc->n_not_alive_disposed, rhc->n_not_alive_no_writers, rhc->n_new, rhc->n_vsamples, rhc->n_invsamples, rhc->n_vread, rhc->n_invread); - if (!ddsrt_circlist_isempty (&rhc->nonempty_instances)) + const dds_querycond_mask_t qcmask = (cond && cond->m_query.m_filter) ? cond->m_query.m_qcmask : 0; + if (handle) + { + struct rhc_instance template, *inst; + template.iid = handle; + if ((inst = ddsrt_hh_lookup (rhc->instances, &template)) != NULL) + n = read_w_qminv_inst (rhc, inst, values, info_seq, max_samples, qminv, qcmask, to_sample, to_invsample); + else + n = DDS_RETCODE_PRECONDITION_NOT_MET; + } + else if (!ddsrt_circlist_isempty (&rhc->nonempty_instances)) { - const dds_querycond_mask_t qcmask = (cond && cond->m_query.m_filter) ? cond->m_query.m_qcmask : 0; struct rhc_instance * inst = oldest_nonempty_instance (rhc); struct rhc_instance * const end = inst; - do - { - if (handle == DDS_HANDLE_NIL || inst->iid == handle) - { - if (!inst_is_empty (inst) && (qmask_of_inst (inst) & qminv) == 0) - { - /* samples present & instance, view state matches */ - struct trigger_info_pre pre; - struct trigger_info_post post; - struct trigger_info_qcond trig_qc; - const unsigned nread = inst_nread (inst); - const uint32_t n_first = n; - get_trigger_info_pre (&pre, inst); - init_trigger_info_qcond (&trig_qc); - - if (inst->latest) - { - struct rhc_sample *sample = inst->latest->next, * const end1 = sample; - do - { - if ((qmask_of_sample (sample) & qminv) == 0 && (qcmask == 0 || (sample->conds & qcmask))) - { - /* sample state matches too */ - set_sample_info (info_seq + n, inst, sample); - ddsi_serdata_to_sample (sample->sample, values[n], 0, 0); - if (!sample->isread) - { - TRACE ("s"); - read_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, sample->conds, false); - sample->isread = true; - inst->nvread++; - rhc->n_vread++; - } - if (++n == max_samples) - { - break; - } - } - sample = sample->next; - } - while (sample != end1); - } - - if (inst->inv_exists && n < max_samples && (qmask_of_invsample (inst) & qminv) == 0 && (qcmask == 0 || (inst->conds & qcmask))) - { - set_sample_info_invsample (info_seq + n, inst); - topicless_to_clean_invsample (rhc->topic, inst->tk->m_sample, values[n], 0, 0); - if (!inst->inv_isread) - { - TRACE ("i"); - read_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, inst->conds, false); - inst->inv_isread = 1; - rhc->n_invread++; - } - ++n; - } - - bool inst_became_old = false; - if (n > n_first && inst->isnew) - { - inst_became_old = true; - inst->isnew = 0; - rhc->n_new--; - } - if (nread != inst_nread (inst) || inst_became_old) - { - size_t ntriggers = SIZE_MAX; - get_trigger_info_cmn (&post.c, inst); - assert (trig_qc.dec_conds_invsample == 0); - assert (trig_qc.dec_conds_sample == 0); - assert (trig_qc.inc_conds_invsample == 0); - assert (trig_qc.inc_conds_sample == 0); - update_conditions_locked (rhc, false, &pre, &post, &trig_qc, inst, NULL, &ntriggers); - } - - if (n > n_first) { - patch_generations (info_seq + n_first, n - n_first - 1); - } - } - if (inst->iid == handle) - { - break; - } - } + do { + n += read_w_qminv_inst(rhc, inst, values + n, info_seq + n, max_samples - n, qminv, qcmask, to_sample, to_invsample); inst = next_nonempty_instance (inst); - } - while (inst != end && n < max_samples); + } while (inst != end && n < max_samples); } TRACE ("read: returning %"PRIu32"\n", n); assert (rhc_check_counts_locked (rhc, true, false)); + + // FIXME: conditional "lock" plus unconditional "unlock" is inexcusably bad design + // It appears to have been introduced at some point so another language binding could lock + // the RHC using dds_rhc_default_lock_samples to find out the number of samples present, + // then allocate stuff and call read/take with lock=true. All that needs fixing. ddsrt_mutex_unlock (&rhc->lock); - assert (n <= INT_MAX); - return (int)n; + return n; } -static int dds_rhc_take_w_qminv (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, unsigned qminv, dds_instance_handle_t handle, dds_readcond *cond) +static int32_t take_w_qminv (struct dds_rhc_default * __restrict rhc, bool lock, void * __restrict * __restrict values, dds_sample_info_t * __restrict info_seq, int32_t max_samples, uint32_t qminv, dds_instance_handle_t handle, dds_readcond * __restrict cond, read_take_to_sample_t to_sample, read_take_to_invsample_t to_invsample) { - uint64_t iid; - uint32_t n = 0; + int32_t n = 0; size_t ntriggers = SIZE_MAX; - + assert (max_samples > 0); if (lock) { ddsrt_mutex_lock (&rhc->lock); } - TRACE ("take_w_qminv(%p,%p,%p,%"PRIu32",%x) - inst %"PRIu32" nonempty %"PRIu32" disp %"PRIu32" nowr %"PRIu32" new %"PRIu32" samples %"PRIu32"+%"PRIu32" read %"PRIu32"+%"PRIu32"\n", - (void*) rhc, (void*) values, (void*) info_seq, max_samples, qminv, + TRACE ("take_w_qminv(%p,%p,%p,%"PRId32",%x,%"PRIx64",%p) - inst %"PRIu32" nonempty %"PRIu32" disp %"PRIu32" nowr %"PRIu32" new %"PRIu32" samples %"PRIu32"+%"PRIu32" read %"PRIu32"+%"PRIu32"\n", + (void*) rhc, (void*) values, (void*) info_seq, max_samples, qminv, handle, (void *) cond, rhc->n_instances, rhc->n_nonempty_instances, rhc->n_not_alive_disposed, rhc->n_not_alive_no_writers, rhc->n_new, rhc->n_vsamples, rhc->n_invsamples, rhc->n_vread, rhc->n_invread); - if (!ddsrt_circlist_isempty (&rhc->nonempty_instances)) + const dds_querycond_mask_t qcmask = (cond && cond->m_query.m_filter) ? cond->m_query.m_qcmask : 0; + if (handle) + { + struct rhc_instance template, *inst; + template.iid = handle; + if ((inst = ddsrt_hh_lookup (rhc->instances, &template)) != NULL) + n = take_w_qminv_inst (rhc, &inst, values, info_seq, max_samples, qminv, qcmask, &ntriggers, to_sample, to_invsample); + else + n = DDS_RETCODE_PRECONDITION_NOT_MET; + } + else if (!ddsrt_circlist_isempty (&rhc->nonempty_instances)) { - const dds_querycond_mask_t qcmask = (cond && cond->m_query.m_filter) ? cond->m_query.m_qcmask : 0; struct rhc_instance *inst = oldest_nonempty_instance (rhc); - unsigned n_insts = rhc->n_nonempty_instances; + uint32_t n_insts = rhc->n_nonempty_instances; while (n_insts-- > 0 && n < max_samples) { struct rhc_instance * const inst1 = next_nonempty_instance (inst); - iid = inst->iid; - if (handle == DDS_HANDLE_NIL || iid == handle) - { - if (!inst_is_empty (inst) && (qmask_of_inst (inst) & qminv) == 0) - { - struct trigger_info_pre pre; - struct trigger_info_post post; - struct trigger_info_qcond trig_qc; - unsigned nvsamples = inst->nvsamples; - const uint32_t n_first = n; - get_trigger_info_pre (&pre, inst); - init_trigger_info_qcond (&trig_qc); - - if (inst->latest) - { - struct rhc_sample *psample = inst->latest; - struct rhc_sample *sample = psample->next; - while (nvsamples--) - { - struct rhc_sample * const sample1 = sample->next; - - if ((qmask_of_sample (sample) & qminv) != 0 || (qcmask != 0 && !(sample->conds & qcmask))) - { - /* sample mask doesn't match, or content predicate doesn't match */ - psample = sample; - } - else - { - take_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, sample->conds, sample->isread); - - set_sample_info (info_seq + n, inst, sample); - ddsi_serdata_to_sample (sample->sample, values[n], 0, 0); - rhc->n_vsamples--; - if (sample->isread) - { - inst->nvread--; - rhc->n_vread--; - } - - if (--inst->nvsamples > 0) - { - if (inst->latest == sample) - inst->latest = psample; - psample->next = sample1; - } - else - { - inst->latest = NULL; - } - - free_sample (rhc, inst, sample); - - if (++n == max_samples) - { - break; - } - } - sample = sample1; - } - } - - if (inst->inv_exists && n < max_samples && (qmask_of_invsample (inst) & qminv) == 0 && (qcmask == 0 || (inst->conds & qcmask) != 0)) - { - struct trigger_info_qcond dummy_trig_qc; -#ifndef NDEBUG - init_trigger_info_qcond (&dummy_trig_qc); -#endif - take_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, inst->conds, inst->inv_isread); - set_sample_info_invsample (info_seq + n, inst); - topicless_to_clean_invsample (rhc->topic, inst->tk->m_sample, values[n], 0, 0); - inst_clear_invsample (rhc, inst, &dummy_trig_qc); - ++n; - } - - if (n > n_first && inst->isnew) - { - inst->isnew = 0; - rhc->n_new--; - } - - if (n > n_first) - { - /* if nsamples = 0, it won't match anything, so no need to do - anything here for drop_instance_noupdate_no_writers */ - get_trigger_info_cmn (&post.c, inst); - assert (trig_qc.dec_conds_invsample == 0); - assert (trig_qc.dec_conds_sample == 0); - assert (trig_qc.inc_conds_invsample == 0); - assert (trig_qc.inc_conds_sample == 0); - update_conditions_locked (rhc, false, &pre, &post, &trig_qc, inst, NULL, &ntriggers); - } - - if (inst_is_empty (inst)) - { - remove_inst_from_nonempty_list (rhc, inst); - - if (inst->isdisposed) - { - rhc->n_not_alive_disposed--; - } - if (inst->wrcount == 0) - { - TRACE ("take: iid %"PRIx64" #0,empty,drop\n", iid); - if (!inst->isdisposed) - { - /* disposed has priority over no writers (why not just 2 bits?) */ - rhc->n_not_alive_no_writers--; - } - drop_instance_noupdate_no_writers (rhc, inst); - } - } - - if (n > n_first) - patch_generations (info_seq + n_first, n - n_first - 1); - } - if (iid == handle) - { - break; - } - } + n += take_w_qminv_inst (rhc, &inst, values + n, info_seq + n, max_samples - n, qminv, qcmask, &ntriggers, to_sample, to_invsample); inst = inst1; } } TRACE ("take: returning %"PRIu32"\n", n); assert (rhc_check_counts_locked (rhc, true, false)); + + // FIXME: conditional "lock" plus unconditional "unlock" is inexcusably bad design + // It appears to have been introduced at some point so another language binding could lock + // the RHC using dds_rhc_default_lock_samples to find out the number of samples present, + // then allocate stuff and call read/take with lock=true. All that needs fixing. ddsrt_mutex_unlock (&rhc->lock); - assert (n <= INT_MAX); - return (int)n; + return n; } -static int dds_rhc_takecdr_w_qminv (struct dds_rhc_default *rhc, bool lock, struct ddsi_serdata ** values, dds_sample_info_t *info_seq, uint32_t max_samples, unsigned qminv, dds_instance_handle_t handle, dds_readcond *cond) +static int32_t dds_rhc_read_w_qminv (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t qminv, dds_instance_handle_t handle, dds_readcond *cond) { - uint64_t iid; - uint32_t n = 0; - (void)cond; + assert (max_samples <= INT32_MAX); + return read_w_qminv (rhc, lock, values, info_seq, (int32_t) max_samples, qminv, handle, cond, read_take_to_sample, read_take_to_invsample); +} - if (lock) - { - ddsrt_mutex_lock (&rhc->lock); - } +static int32_t dds_rhc_take_w_qminv (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t qminv, dds_instance_handle_t handle, dds_readcond *cond) +{ + assert (max_samples <= INT32_MAX); + return take_w_qminv (rhc, lock, values, info_seq, (int32_t) max_samples, qminv, handle, cond, read_take_to_sample, read_take_to_invsample); +} - TRACE ("take_w_qminv(%p,%p,%p,%"PRIu32",%x) - inst %"PRIu32" nonempty %"PRIu32" disp %"PRIu32" nowr %"PRIu32" new %"PRIu32" samples %"PRIu32"+%"PRIu32" read %"PRIu32"+%"PRIu32"\n", - (void*) rhc, (void*) values, (void*) info_seq, max_samples, qminv, - rhc->n_instances, rhc->n_nonempty_instances, rhc->n_not_alive_disposed, - rhc->n_not_alive_no_writers, rhc->n_new, rhc->n_vsamples, - rhc->n_invsamples, rhc->n_vread, rhc->n_invread); +static int32_t dds_rhc_readcdr_w_qminv (struct dds_rhc_default *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t qminv, dds_instance_handle_t handle, dds_readcond *cond) +{ + DDSRT_STATIC_ASSERT (sizeof (void *) == sizeof (struct ddsi_serdata *)); + assert (max_samples <= INT32_MAX); + return read_w_qminv (rhc, lock, (void **) values, info_seq, (int32_t) max_samples, qminv, handle, cond, read_take_to_sample_ref, read_take_to_invsample_ref); +} - if (!ddsrt_circlist_isempty (&rhc->nonempty_instances)) - { - const dds_querycond_mask_t qcmask = (cond && cond->m_query.m_filter) ? cond->m_query.m_qcmask : 0; - struct rhc_instance *inst = oldest_nonempty_instance (rhc); - unsigned n_insts = rhc->n_nonempty_instances; - while (n_insts-- > 0 && n < max_samples) - { - struct rhc_instance * const inst1 = next_nonempty_instance (inst); - iid = inst->iid; - if (handle == DDS_HANDLE_NIL || iid == handle) - { - if (!inst_is_empty (inst) && (qmask_of_inst (inst) & qminv) == 0) - { - struct trigger_info_pre pre; - struct trigger_info_post post; - struct trigger_info_qcond trig_qc; - unsigned nvsamples = inst->nvsamples; - const uint32_t n_first = n; - get_trigger_info_pre (&pre, inst); - init_trigger_info_qcond (&trig_qc); - - if (inst->latest) - { - struct rhc_sample *psample = inst->latest; - struct rhc_sample *sample = psample->next; - while (nvsamples--) - { - struct rhc_sample * const sample1 = sample->next; - - if ((qmask_of_sample (sample) & qminv) != 0 || (qcmask && !(sample->conds & qcmask))) - { - psample = sample; - } - else - { - take_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, sample->conds, sample->isread); - set_sample_info (info_seq + n, inst, sample); - values[n] = ddsi_serdata_ref(sample->sample); - rhc->n_vsamples--; - if (sample->isread) - { - inst->nvread--; - rhc->n_vread--; - } - - if (--inst->nvsamples > 0) - psample->next = sample1; - else - inst->latest = NULL; - - free_sample (rhc, inst, sample); - - if (++n == max_samples) - { - break; - } - } - sample = sample1; - } - } - - if (inst->inv_exists && n < max_samples && (qmask_of_invsample (inst) & qminv) == 0 && (qcmask == 0 || (inst->conds & qcmask) != 0)) - { - struct trigger_info_qcond dummy_trig_qc; -#ifndef NDEBUG - init_trigger_info_qcond (&dummy_trig_qc); -#endif - take_sample_update_conditions (rhc, &pre, &post, &trig_qc, inst, inst->conds, inst->inv_isread); - set_sample_info_invsample (info_seq + n, inst); - values[n] = ddsi_serdata_ref(inst->tk->m_sample); - inst_clear_invsample (rhc, inst, &dummy_trig_qc); - ++n; - } - - if (n > n_first && inst->isnew) - { - inst->isnew = 0; - rhc->n_new--; - } - - if (n > n_first) - { - /* if nsamples = 0, it won't match anything, so no need to do - anything here for drop_instance_noupdate_no_writers */ - size_t ntriggers = SIZE_MAX; - get_trigger_info_cmn (&post.c, inst); - update_conditions_locked (rhc, false, &pre, &post, &trig_qc, inst, NULL, &ntriggers); - } - - if (inst_is_empty (inst)) - { - remove_inst_from_nonempty_list (rhc, inst); - - if (inst->isdisposed) - { - rhc->n_not_alive_disposed--; - } - if (inst->wrcount == 0) - { - TRACE ("take: iid %"PRIx64" #0,empty,drop\n", iid); - if (!inst->isdisposed) - { - /* disposed has priority over no writers (why not just 2 bits?) */ - rhc->n_not_alive_no_writers--; - } - drop_instance_noupdate_no_writers (rhc, inst); - } - } - - if (n > n_first) - patch_generations (info_seq + n_first, n - n_first - 1); - } - if (iid == handle) - { - break; - } - } - inst = inst1; - } - } - TRACE ("take: returning %"PRIu32"\n", n); - assert (rhc_check_counts_locked (rhc, true, false)); - ddsrt_mutex_unlock (&rhc->lock); - assert (n <= INT_MAX); - return (int)n; +static int32_t dds_rhc_takecdr_w_qminv (struct dds_rhc_default *rhc, bool lock, struct ddsi_serdata **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t qminv, dds_instance_handle_t handle, dds_readcond *cond) +{ + DDSRT_STATIC_ASSERT (sizeof (void *) == sizeof (struct ddsi_serdata *)); + assert (max_samples <= INT32_MAX); + return take_w_qminv (rhc, lock, (void **) values, info_seq, (int32_t) max_samples, qminv, handle, cond, read_take_to_sample_ref, read_take_to_invsample_ref); } /************************* @@ -2471,12 +2308,13 @@ static bool cond_is_sample_state_dependent (const struct dds_readcond *cond) } } -static bool dds_rhc_default_add_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond) +static bool dds_rhc_default_add_readcondition (struct dds_rhc *rhc_common, dds_readcond *cond) { /* On the assumption that a readcondition will be attached to a waitset for nearly all of its life, we keep track of all readconditions on a reader in one set, without distinguishing between those attached to a waitset or not. */ + struct dds_rhc_default * const rhc = (struct dds_rhc_default *) rhc_common; struct ddsrt_hh_iter it; assert ((dds_entity_kind (&cond->m_entity) == DDS_KIND_COND_READ && cond->m_query.m_filter == 0) || @@ -2576,8 +2414,9 @@ static bool dds_rhc_default_add_readcondition (struct dds_rhc_default *rhc, dds_ return true; } -static void dds_rhc_default_remove_readcondition (struct dds_rhc_default *rhc, dds_readcond *cond) +static void dds_rhc_default_remove_readcondition (struct dds_rhc *rhc_common, dds_readcond *cond) { + struct dds_rhc_default * const rhc = (struct dds_rhc_default *) rhc_common; dds_readcond **ptr; ddsrt_mutex_lock (&rhc->lock); ptr = &rhc->conds; @@ -2610,7 +2449,9 @@ static bool update_conditions_locked (struct dds_rhc_default *rhc, bool called_f TRACE ("update_conditions_locked(%p %p) - inst %"PRIu32" nonempty %"PRIu32" disp %"PRIu32" nowr %"PRIu32" new %"PRIu32" samples %"PRIu32" read %"PRIu32"\n", (void *) rhc, (void *) inst, rhc->n_instances, rhc->n_nonempty_instances, rhc->n_not_alive_disposed, rhc->n_not_alive_no_writers, rhc->n_new, rhc->n_vsamples, rhc->n_vread); - TRACE (" read -[%d,%d]+[%d,%d] qcmask -[%"PRIx32",%"PRIx32"]+[%"PRIx32",%"PRIx32"]\n", + TRACE (" pre (%"PRIx32",%d,%d) post (%"PRIx32",%d,%d) read -[%d,%d]+[%d,%d] qcmask -[%"PRIx32",%"PRIx32"]+[%"PRIx32",%"PRIx32"]\n", + pre->c.qminst, pre->c.has_read, pre->c.has_not_read, + post->c.qminst, post->c.has_read, post->c.has_not_read, trig_qc->dec_invsample_read, trig_qc->dec_sample_read, trig_qc->inc_invsample_read, trig_qc->inc_sample_read, trig_qc->dec_conds_invsample, trig_qc->dec_conds_sample, trig_qc->inc_conds_invsample, trig_qc->inc_conds_sample); @@ -2746,15 +2587,18 @@ static bool update_conditions_locked (struct dds_rhc_default *rhc, bool called_f or there was a match and now there is not: so also scan all samples for matches. The only difference is in whether the number of matches should be added or subtracted. */ int32_t mcurrent = 0; - if (inst->inv_exists) - mcurrent += (qmask_of_invsample (inst) & iter->m_qminv) == 0 && (inst->conds & qcmask) != 0; - if (inst->latest) + if (inst) { - struct rhc_sample *sample = inst->latest->next, * const end = sample; - do { - mcurrent += (qmask_of_sample (sample) & iter->m_qminv) == 0 && (sample->conds & qcmask) != 0; - sample = sample->next; - } while (sample != end); + if (inst->inv_exists) + mcurrent += (qmask_of_invsample (inst) & iter->m_qminv) == 0 && (inst->conds & qcmask) != 0; + if (inst->latest) + { + struct rhc_sample *sample = inst->latest->next, * const end = sample; + do { + mcurrent += (qmask_of_sample (sample) & iter->m_qminv) == 0 && (sample->conds & qcmask) != 0; + sample = sample->next; + } while (sample != end); + } } if (mdelta == 0 && mcurrent == 0) TRACE ("no change @ %"PRIu32" (2)", ddsrt_atomic_ld32 (&iter->m_entity.m_status.m_trigger)); @@ -2805,21 +2649,31 @@ static bool update_conditions_locked (struct dds_rhc_default *rhc, bool called_f ****** READ/TAKE ****** *************************/ -static int dds_rhc_default_read (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond) +static int32_t dds_rhc_default_read (struct dds_rhc *rhc_common, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond) { - unsigned qminv = qmask_from_mask_n_cond (mask, cond); - return dds_rhc_read_w_qminv (rhc, lock, values, info_seq, max_samples, qminv, handle, cond); + struct dds_rhc_default * const rhc = (struct dds_rhc_default *) rhc_common; + uint32_t qminv = qmask_from_mask_n_cond (mask, cond); + return dds_rhc_read_w_qminv (rhc, lock, values, info_seq, max_samples, qminv, handle, cond); } -static int dds_rhc_default_take (struct dds_rhc_default *rhc, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond) +static int32_t dds_rhc_default_take (struct dds_rhc *rhc_common, bool lock, void **values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t mask, dds_instance_handle_t handle, dds_readcond *cond) { - unsigned qminv = qmask_from_mask_n_cond(mask, cond); - return dds_rhc_take_w_qminv (rhc, lock, values, info_seq, max_samples, qminv, handle, cond); + struct dds_rhc_default * const rhc = (struct dds_rhc_default *) rhc_common; + uint32_t qminv = qmask_from_mask_n_cond(mask, cond); + return dds_rhc_take_w_qminv (rhc, lock, values, info_seq, max_samples, qminv, handle, cond); } -static int dds_rhc_default_takecdr (struct dds_rhc_default *rhc, bool lock, struct ddsi_serdata ** values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) +static int32_t dds_rhc_default_readcdr (struct dds_rhc *rhc_common, bool lock, struct ddsi_serdata ** values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) { - unsigned qminv = qmask_from_dcpsquery (sample_states, view_states, instance_states); + struct dds_rhc_default * const rhc = (struct dds_rhc_default *) rhc_common; + uint32_t qminv = qmask_from_dcpsquery (sample_states, view_states, instance_states); + return dds_rhc_readcdr_w_qminv (rhc, lock, values, info_seq, max_samples, qminv, handle, NULL); +} + +static int32_t dds_rhc_default_takecdr (struct dds_rhc *rhc_common, bool lock, struct ddsi_serdata ** values, dds_sample_info_t *info_seq, uint32_t max_samples, uint32_t sample_states, uint32_t view_states, uint32_t instance_states, dds_instance_handle_t handle) +{ + struct dds_rhc_default * const rhc = (struct dds_rhc_default *) rhc_common; + uint32_t qminv = qmask_from_dcpsquery (sample_states, view_states, instance_states); return dds_rhc_takecdr_w_qminv (rhc, lock, values, info_seq, max_samples, qminv, handle, NULL); } @@ -2835,11 +2689,11 @@ static int rhc_check_counts_locked (struct dds_rhc_default *rhc, bool check_cond return 1; const uint32_t ncheck = rhc->nconds < CHECK_MAX_CONDS ? rhc->nconds : CHECK_MAX_CONDS; - unsigned n_instances = 0, n_nonempty_instances = 0; - unsigned n_not_alive_disposed = 0, n_not_alive_no_writers = 0, n_new = 0; - unsigned n_vsamples = 0, n_vread = 0; - unsigned n_invsamples = 0, n_invread = 0; - unsigned cond_match_count[CHECK_MAX_CONDS]; + uint32_t n_instances = 0, n_nonempty_instances = 0; + uint32_t n_not_alive_disposed = 0, n_not_alive_no_writers = 0, n_new = 0; + uint32_t n_vsamples = 0, n_vread = 0; + uint32_t n_invsamples = 0, n_invread = 0; + uint32_t cond_match_count[CHECK_MAX_CONDS]; dds_querycond_mask_t enabled_qcmask = 0; struct rhc_instance *inst; struct ddsrt_hh_iter iter; @@ -2860,7 +2714,7 @@ static int rhc_check_counts_locked (struct dds_rhc_default *rhc, bool check_cond for (inst = ddsrt_hh_iter_first (rhc->instances, &iter); inst; inst = ddsrt_hh_iter_next (&iter)) { - unsigned n_vsamples_in_instance = 0, n_read_vsamples_in_instance = 0; + uint32_t n_vsamples_in_instance = 0, n_read_vsamples_in_instance = 0; bool a_sample_free = true; n_instances++; @@ -2996,3 +2850,21 @@ static int rhc_check_counts_locked (struct dds_rhc_default *rhc, bool check_cond } #undef CHECK_MAX_CONDS #endif + +static const struct dds_rhc_ops dds_rhc_default_ops = { + .rhc_ops = { + .store = dds_rhc_default_store, + .unregister_wr = dds_rhc_default_unregister_wr, + .relinquish_ownership = dds_rhc_default_relinquish_ownership, + .set_qos = dds_rhc_default_set_qos, + .free = dds_rhc_default_free + }, + .read = dds_rhc_default_read, + .take = dds_rhc_default_take, + .readcdr = dds_rhc_default_readcdr, + .takecdr = dds_rhc_default_takecdr, + .add_readcondition = dds_rhc_default_add_readcondition, + .remove_readcondition = dds_rhc_default_remove_readcondition, + .lock_samples = dds_rhc_default_lock_samples, + .associate = dds_rhc_default_associate +}; diff --git a/src/core/ddsc/src/dds_serdata_builtintopic.c b/src/core/ddsc/src/dds_serdata_builtintopic.c index 8712d40..cc07285 100644 --- a/src/core/ddsc/src/dds_serdata_builtintopic.c +++ b/src/core/ddsc/src/dds_serdata_builtintopic.c @@ -126,14 +126,16 @@ static void from_entity_pwr (struct ddsi_serdata_builtintopic *d, const struct p assert (d->xqos.present & QP_TYPE_NAME); } -static struct ddsi_serdata *ddsi_serdata_builtin_from_keyhash (const struct ddsi_sertopic *tpcmn, const nn_keyhash_t *keyhash) +static struct ddsi_serdata *ddsi_serdata_builtin_from_keyhash (const struct ddsi_sertopic *tpcmn, const ddsi_keyhash_t *keyhash) { /* FIXME: not quite elegant to manage the creation of a serdata for a built-in topic via this function, but I also find it quite unelegant to let from_sample read straight from the underlying internal entity, and to_sample convert to the external format ... I could claim the internal entity is the "serialised form", but that forces wrapping it in a fragchain in one way or another, which, though possible, is also a bit lacking in elegance. */ const struct ddsi_sertopic_builtintopic *tp = (const struct ddsi_sertopic_builtintopic *)tpcmn; - /* keyhash must in host format (which the GUIDs always are internally) */ - struct entity_common *entity = entidx_lookup_guid_untyped (tp->c.gv->entity_index, (const ddsi_guid_t *) keyhash->value); - struct ddsi_serdata_builtintopic *d = serdata_builtin_new(tp, entity ? SDK_DATA : SDK_KEY); - memcpy (&d->key, keyhash->value, sizeof (d->key)); + union { ddsi_guid_t guid; ddsi_keyhash_t keyhash; } x; + x.keyhash = *keyhash; + x.guid = nn_ntoh_guid (x.guid); + struct entity_common *entity = entidx_lookup_guid_untyped (tp->c.gv->entity_index, &x.guid); + struct ddsi_serdata_builtintopic *d = serdata_builtin_new (tp, entity ? SDK_DATA : SDK_KEY); + d->key = x.guid; if (entity) { ddsrt_mutex_lock (&entity->qos_lock); @@ -169,6 +171,41 @@ static struct ddsi_serdata *ddsi_serdata_builtin_from_keyhash (const struct ddsi return fix_serdata_builtin(d, tp->c.serdata_basehash); } +static struct ddsi_serdata *ddsi_serdata_builtin_from_sample (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, const void *sample) +{ + const struct ddsi_sertopic_builtintopic *tp = (const struct ddsi_sertopic_builtintopic *)tpcmn; + union { + dds_guid_t extguid; + ddsi_keyhash_t keyhash; + } x; + + /* no-one should be trying to convert user-provided data into a built-in topic sample, but converting + a key is something that can be necessary, e.g., dds_lookup_instance depends on it */ + if (kind != SDK_KEY) + return NULL; + + /* memset x (even though it is entirely superfluous) so we can leave out a default case from the + switch (ensuring at least some compilers will warn when more types are added) without getting + warnings from any compiler */ + memset (&x, 0, sizeof (x)); + switch (tp->type) + { + case DSBT_PARTICIPANT: { + const dds_builtintopic_participant_t *s = sample; + x.extguid = s->key; + break; + } + case DSBT_READER: + case DSBT_WRITER: { + const dds_builtintopic_endpoint_t *s = sample; + x.extguid = s->key; + break; + } + } + + return ddsi_serdata_from_keyhash (tpcmn, &x.keyhash); +} + static struct ddsi_serdata *serdata_builtin_to_topicless (const struct ddsi_serdata *serdata_common) { /* All built-in ones are currently topicless */ @@ -289,12 +326,13 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_builtintopic = { .from_ser = 0, .from_ser_iov = 0, .from_keyhash = ddsi_serdata_builtin_from_keyhash, - .from_sample = 0, + .from_sample = ddsi_serdata_builtin_from_sample, .to_ser = serdata_builtin_to_ser, .to_sample = serdata_builtin_to_sample, .to_ser_ref = serdata_builtin_to_ser_ref, .to_ser_unref = serdata_builtin_to_ser_unref, .to_topicless = serdata_builtin_to_topicless, .topicless_to_sample = serdata_builtin_topicless_to_sample, - .print = serdata_builtin_topic_print + .print = serdata_builtin_topic_print, + .get_keyhash = 0 }; diff --git a/src/core/ddsc/src/dds_topic.c b/src/core/ddsc/src/dds_topic.c index ff177b8..0f48cbd 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) @@ -246,6 +247,7 @@ static dds_return_t lookup_and_check_ktopic (struct dds_ktopic **ktp_out, dds_pa static dds_entity_t create_topic_pp_locked (struct dds_participant *pp, struct dds_ktopic *ktp, bool implicit, struct ddsi_sertopic *sertopic_registered, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist) { + (void) sedp_plist; dds_entity_t hdl; dds_topic *tp = dds_alloc (sizeof (*tp)); hdl = dds_entity_init (&tp->m_entity, &pp->m_entity, DDS_KIND_TOPIC, implicit, NULL, listener, DDS_TOPIC_STATUS_MASK); @@ -253,30 +255,11 @@ static dds_entity_t create_topic_pp_locked (struct dds_participant *pp, struct d dds_entity_register_child (&pp->m_entity, &tp->m_entity); tp->m_ktopic = ktp; tp->m_stopic = sertopic_registered; - - /* Publish Topic */ - if (sedp_plist) - { - struct participant *ddsi_pp; - ddsi_plist_t plist; - - thread_state_awake (lookup_thread_state (), &pp->m_entity.m_domain->gv); - ddsi_pp = entidx_lookup_participant_guid (pp->m_entity.m_domain->gv.entity_index, &pp->m_entity.m_guid); - assert (ddsi_pp); - - ddsi_plist_init_empty (&plist); - ddsi_plist_mergein_missing (&plist, sedp_plist, ~(uint64_t)0, ~(uint64_t)0); - ddsi_xqos_mergein_missing (&plist.qos, ktp->qos, ~(uint64_t)0); - sedp_write_topic (ddsi_pp, &plist); - ddsi_plist_fini (&plist); - thread_state_asleep (lookup_thread_state ()); - } - dds_entity_init_complete (&tp->m_entity); return hdl; } -dds_entity_t dds_create_topic_generic (dds_entity_t participant, struct ddsi_sertopic **sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist) +dds_entity_t dds_create_topic_impl (dds_entity_t participant, struct ddsi_sertopic **sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist) { dds_return_t rc; dds_participant *pp; @@ -315,10 +298,12 @@ dds_entity_t dds_create_topic_generic (dds_entity_t participant, struct ddsi_ser * 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 @@ -331,9 +316,8 @@ dds_entity_t dds_create_topic_generic (dds_entity_t participant, struct ddsi_ser if ((rc = lookup_and_check_ktopic (&ktp, pp, (*sertopic)->name, (*sertopic)->type_name, new_qos)) != DDS_RETCODE_OK) { GVTRACE ("dds_create_topic_generic: 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 @@ -375,13 +359,31 @@ dds_entity_t dds_create_topic_generic (dds_entity_t participant, struct ddsi_ser hdl = create_topic_pp_locked (pp, ktp, (sertopic_registered->ops == &ddsi_sertopic_ops_builtintopic), sertopic_registered, listener, sedp_plist); ddsi_sertopic_unref (*sertopic); *sertopic = sertopic_registered; - dds_participant_unlock (pp); + ddsrt_mutex_unlock (&pp->m_entity.m_mutex); + dds_entity_unpin (&pp->m_entity); GVTRACE ("dds_create_topic_generic: 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_generic (dds_entity_t participant, struct ddsi_sertopic **sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist) +{ + if (sertopic == NULL || *sertopic == NULL || (*sertopic)->name == NULL) + return DDS_RETCODE_BAD_PARAMETER; + if (!strncmp((*sertopic)->name, "DCPS", 4)) + return DDS_RETCODE_BAD_PARAMETER; + return dds_create_topic_impl (participant, sertopic, qos, listener, sedp_plist); } 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) { + if (sertopic == NULL) + return DDS_RETCODE_BAD_PARAMETER; + dds_entity_t ret; struct ddsi_sertopic *st = sertopic; ddsi_sertopic_ref (st); diff --git a/src/core/ddsc/src/dds_whc.c b/src/core/ddsc/src/dds_whc.c index 440746b..eba2f33 100644 --- a/src/core/ddsc/src/dds_whc.c +++ b/src/core/ddsc/src/dds_whc.c @@ -849,7 +849,7 @@ static void whc_delete_one_intv (struct whc_impl *whc, struct whc_intvnode **p_i assert (new_intv->min < new_intv->maxp1); /* insert new node & continue the loop with intv set to the - new interval */ + new interval */ if (ddsrt_avl_lookup_ipath (&whc_seq_treedef, &whc->seq, &new_intv->min, &path) != NULL) assert (0); ddsrt_avl_insert_ipath (&whc_seq_treedef, &whc->seq, new_intv, &path); diff --git a/src/core/ddsc/src/dds_write.c b/src/core/ddsc/src/dds_write.c index a2b978b..cc0b1e8 100644 --- a/src/core/ddsc/src/dds_write.c +++ b/src/core/ddsc/src/dds_write.c @@ -267,8 +267,7 @@ void dds_write_flush (dds_entity_t writer) { struct thread_state1 * const ts1 = lookup_thread_state (); dds_writer *wr; - dds_return_t rc; - if ((rc = dds_writer_lock (writer, &wr)) == DDS_RETCODE_OK) + if (dds_writer_lock (writer, &wr) == DDS_RETCODE_OK) { thread_state_awake (ts1, &wr->m_entity.m_domain->gv); nn_xpack_send (wr->m_xp, true); diff --git a/src/core/ddsc/src/dds_writer.c b/src/core/ddsc/src/dds_writer.c index caedd81..cad0492 100644 --- a/src/core/ddsc/src/dds_writer.c +++ b/src/core/ddsc/src/dds_writer.c @@ -20,6 +20,7 @@ #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_xmsg.h" #include "dds/ddsi/ddsi_entity_index.h" +#include "dds/ddsi/ddsi_security_omg.h" #include "dds__writer.h" #include "dds__listener.h" #include "dds__init.h" @@ -312,6 +313,7 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit dds_topic_defer_set_qos (tp); /* Merge Topic & Publisher qos */ + struct ddsi_domaingv *gv = &pub->m_entity.m_domain->gv; wqos = dds_create_qos (); if (qos) ddsi_xqos_mergein_missing (wqos, qos, DDS_WRITER_QOS_MASK); @@ -319,29 +321,45 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit ddsi_xqos_mergein_missing (wqos, pub->m_entity.m_qos, ~(uint64_t)0); if (tp->m_ktopic->qos) ddsi_xqos_mergein_missing (wqos, tp->m_ktopic->qos, ~(uint64_t)0); - ddsi_xqos_mergein_missing (wqos, &pub->m_entity.m_domain->gv.default_xqos_wr, ~(uint64_t)0); + ddsi_xqos_mergein_missing (wqos, &gv->default_xqos_wr, ~(uint64_t)0); - if ((rc = ddsi_xqos_valid (&pub->m_entity.m_domain->gv.logconfig, wqos)) < 0 || - (rc = validate_writer_qos(wqos)) != DDS_RETCODE_OK) - { - dds_delete_qos(wqos); + if ((rc = ddsi_xqos_valid (&gv->logconfig, wqos)) < 0 || (rc = validate_writer_qos(wqos)) != DDS_RETCODE_OK) goto err_bad_qos; + + thread_state_awake (lookup_thread_state (), gv); + const struct ddsi_guid *ppguid = dds_entity_participant_guid (&pub->m_entity); + struct participant *pp = entidx_lookup_participant_guid (gv->entity_index, ppguid); + /* When deleting a participant, the child handles (that include the publisher) + are removed before removing the DDSI participant. So at this point, within + the publisher lock, we can assert that the participant exists. */ + assert (pp != NULL); + +#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, tp->m_stopic->name, wqos)) + { + rc = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; + goto err_not_allowed; + } } +#endif /* Create writer */ - ddsi_tran_conn_t conn = pub->m_entity.m_domain->gv.xmit_conn; + ddsi_tran_conn_t conn = gv->xmit_conn; struct dds_writer * const wr = dds_alloc (sizeof (*wr)); const dds_entity_t writer = dds_entity_init (&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, false, wqos, listener, DDS_WRITER_STATUS_MASK); wr->m_topic = tp; dds_entity_add_ref_locked (&tp->m_entity); - wr->m_xp = nn_xpack_new (conn, get_bandwidth_limit (wqos->transport_priority), pub->m_entity.m_domain->gv.config.xpack_send_async); + wr->m_xp = nn_xpack_new (conn, get_bandwidth_limit (wqos->transport_priority), gv->config.xpack_send_async); wrinfo = whc_make_wrinfo (wr, wqos); - wr->m_whc = whc_new (&pub->m_entity.m_domain->gv, wrinfo); + wr->m_whc = whc_new (gv, wrinfo); whc_free_wrinfo (wrinfo); - wr->whc_batch = pub->m_entity.m_domain->gv.config.whc_batch; + wr->whc_batch = gv->config.whc_batch; - thread_state_awake (lookup_thread_state (), &pub->m_entity.m_domain->gv); - rc = new_writer (&wr->m_wr, &wr->m_entity.m_domain->gv, &wr->m_entity.m_guid, NULL, dds_entity_participant_guid (&pub->m_entity), tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr); + rc = new_writer (&wr->m_wr, &wr->m_entity.m_guid, NULL, pp, tp->m_stopic, wqos, wr->m_whc, dds_writer_status_cb, wr); assert(rc == DDS_RETCODE_OK); thread_state_asleep (lookup_thread_state ()); @@ -355,7 +373,12 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit dds_publisher_unlock (pub); return writer; +#ifdef DDSI_INCLUDE_SECURITY +err_not_allowed: + thread_state_asleep (lookup_thread_state ()); +#endif err_bad_qos: + dds_delete_qos(wqos); dds_topic_allow_set_qos (tp); err_pp_mismatch: dds_topic_unpin (tp); @@ -387,14 +410,14 @@ dds_entity_t dds_get_publisher (dds_entity_t writer) } } -dds_return_t dds__writer_wait_for_acks (struct dds_writer *wr, dds_time_t abstimeout) +dds_return_t dds__writer_wait_for_acks (struct dds_writer *wr, ddsi_guid_t *rdguid, dds_time_t abstimeout) { /* during lifetime of the writer m_wr is constant, it is only during deletion that it gets erased at some point */ if (wr->m_wr == NULL) return DDS_RETCODE_OK; else - return writer_wait_for_acks (wr->m_wr, abstimeout); + return writer_wait_for_acks (wr->m_wr, rdguid, abstimeout); } DDS_GET_STATUS(writer, publication_matched, PUBLICATION_MATCHED, total_count_change, current_count_change) diff --git a/src/core/ddsc/tests/CMakeLists.txt b/src/core/ddsc/tests/CMakeLists.txt index 8615835..bde5eae 100644 --- a/src/core/ddsc/tests/CMakeLists.txt +++ b/src/core/ddsc/tests/CMakeLists.txt @@ -59,7 +59,9 @@ set(ddsc_test_sources "write_various_types.c" "writer.c" "test_common.c" - "test_common.h") + "test_common.h" + "test_oneliner.c" + "test_oneliner.h") if(ENABLE_LIFESPAN) list(APPEND ddsc_test_sources "lifespan.c") @@ -83,11 +85,10 @@ set(CUnit_ddsc_config_simple_udp_file "${CMAKE_CURRENT_LIST_DIR}/config_simple_u set(CUnit_ddsc_config_simple_udp_uri "file://${CUnit_ddsc_config_simple_udp_file}") set(CUnit_ddsc_config_simple_udp_max_participants "0") set(CUnit_ddsc_config_simple_udp_env "${PROJECT_NAME_CAPS}_URI=${CUnit_ddsc_config_simple_udp_uri};MAX_PARTICIPANTS=${CUnit_ddsc_config_simple_udp_max_participants};${CUnit_ddsc_config_simple_udp_env}") - set_tests_properties( CUnit_ddsc_config_simple_udp PROPERTIES REQUIRED_FILES ${CUnit_ddsc_config_simple_udp_file} ENVIRONMENT "${CUnit_ddsc_config_simple_udp_env}") -configure_file("config_env.h.in" "config_env.h") +configure_file("config_env.h.in" "config_env.h" @ONLY) diff --git a/src/core/ddsc/tests/config.c b/src/core/ddsc/tests/config.c index f9e36c1..bb8f234 100644 --- a/src/core/ddsc/tests/config.c +++ b/src/core/ddsc/tests/config.c @@ -18,6 +18,8 @@ #include "dds/ddsrt/cdtors.h" #include "dds/ddsrt/environ.h" #include "dds/ddsrt/heap.h" +#include "dds/ddsi/q_misc.h" +#include "dds/ddsi/ddsi_xqos.h" #include "test_common.h" @@ -28,7 +30,7 @@ static void config__check_env (const char *env_variable, const char *expected_value) { - char *env_uri = NULL; + const char *env_uri = NULL; ddsrt_getenv (env_variable, &env_uri); #ifdef FORCE_ENV { @@ -84,3 +86,99 @@ CU_Test (ddsc_config, user_config, .init = ddsrt_init, .fini = ddsrt_fini) dds_delete (domain); } +/* + * The 'found' variable will contain flags related to the expected log + * messages that were received. + * Using flags will allow to show that when message isn't received, + * which one it was. + */ +static uint32_t found; +static void logger(void *ptr, const dds_log_data_t *data) +{ + char **expected = (char**)ptr; + for (uint32_t i = 0; expected[i] != NULL; i++) { + if (ddsi2_patmatch(expected[i], data->message)) { + found |= (uint32_t)(1 << i); + } + } +} + +CU_Test(ddsc_security_config, empty, .init = ddsrt_init, .fini = ddsrt_fini) +{ + /* Expected traces when creating participant with an empty security element. We need to + test this one here to be sure that it refuses to start when security is configured + but the implementation doesn't include support for it. */ + const char *log_expected[] = { +#ifndef DDSI_INCLUDE_SECURITY + "config: //CycloneDDS/Domain: DDSSecurity: unknown element*", +#else + "config: //CycloneDDS/Domain/DDSSecurity/Authentication/IdentityCertificate/#text: element missing in configuration*", + "config: //CycloneDDS/Domain/DDSSecurity/Authentication/IdentityCA/#text: element missing in configuration*", + "config: //CycloneDDS/Domain/DDSSecurity/Authentication/PrivateKey/#text: element missing in configuration*", +#endif + NULL + }; + + dds_entity_t participant; + + /* Set up the trace sinks to detect the config parsing. */ + dds_set_log_mask(DDS_LC_FATAL|DDS_LC_ERROR|DDS_LC_WARNING|DDS_LC_CONFIG); + dds_set_log_sink(&logger, (void*)log_expected); + dds_set_trace_sink(&logger, (void*)log_expected); + + /* Create participant with an empty security element. */ + found = 0; + ddsrt_setenv(URI_VARIABLE, ""); + participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); + ddsrt_setenv(URI_VARIABLE, ""); + CU_ASSERT_FATAL(participant < 0); + dds_set_log_sink(NULL, NULL); + dds_set_trace_sink(NULL, NULL); + + /* All traces should have been provided. */ +#ifndef DDSI_INCLUDE_SECURITY + CU_ASSERT_FATAL(found == 0x1); +#else + CU_ASSERT_FATAL(found == 0x7); +#endif +} + +CU_Test(ddsc_security_qos, empty, .init = ddsrt_init, .fini = ddsrt_fini) +{ + /* Expected traces when creating participant with some (not all) security QoS + settings. We need to test this one here to be sure that it also refuses to + start when security is configured but the implementation doesn't include + support for it. */ + const char *log_expected[] = { +#ifdef DDSI_INCLUDE_SECURITY + "new_participant(*): using security settings from QoS*", + "new_participant(*): required security property * missing*", +#endif + NULL + }; + + /* Set up the trace sinks to detect the config parsing. */ + dds_set_log_mask (DDS_LC_FATAL|DDS_LC_ERROR|DDS_LC_WARNING|DDS_LC_CONFIG); + dds_set_log_sink (&logger, (void *) log_expected); + dds_set_trace_sink (&logger, (void *) log_expected); + + /* Create participant with incomplete/nonsensical security configuration: this should always fail */ + found = 0; + dds_qos_t *qos = dds_create_qos (); + dds_qset_prop (qos, "dds.sec.nonsense", ""); + dds_entity_t domain = dds_create_domain (0, "trace"); + CU_ASSERT_FATAL (domain > 0); + dds_entity_t participant = dds_create_participant (0, qos, NULL); + dds_delete_qos (qos); + CU_ASSERT_FATAL (participant < 0); + (void) dds_delete (domain); + dds_set_log_sink (NULL, NULL); + dds_set_trace_sink (NULL, NULL); + + /* All traces should have been provided. */ +#ifndef DDSI_INCLUDE_SECURITY + CU_ASSERT_FATAL (found == 0x0); +#else + CU_ASSERT_FATAL (found == 0x3); +#endif +} diff --git a/src/core/ddsc/tests/deadline.c b/src/core/ddsc/tests/deadline.c index e10bd74..c97debb 100644 --- a/src/core/ddsc/tests/deadline.c +++ b/src/core/ddsc/tests/deadline.c @@ -125,6 +125,7 @@ static void deadline_init(void) dds_qset_history(g_qos, DDS_HISTORY_KEEP_ALL, DDS_LENGTH_UNLIMITED); dds_qset_durability(g_qos, DDS_DURABILITY_TRANSIENT_LOCAL); dds_qset_reliability(g_qos, DDS_RELIABILITY_RELIABLE, DDS_INFINITY); + dds_qset_writer_data_lifecycle(g_qos, false); } static void deadline_fini(void) @@ -422,7 +423,10 @@ CU_Theory((int32_t n_inst, uint8_t unreg_nth, uint8_t dispose_nth), ddsc_deadlin n_dispose++; } } - n_alive = n_inst - n_dispose - n_unreg; + /* FIXME: should unregistered instances cause deadline expirations? I do think so + and that is what it actually implemented + if they shouldn't: n_alive = n_inst - n_dispose - n_unreg */ + n_alive = n_inst - n_dispose; /* Sleep deadline_dur + 50% and check missed deadline count */ sleepfor(3 * deadline_dur / 2); diff --git a/src/core/ddsc/tests/listener.c b/src/core/ddsc/tests/listener.c index 1ad9f71..1bc7005 100644 --- a/src/core/ddsc/tests/listener.c +++ b/src/core/ddsc/tests/listener.c @@ -1,5 +1,5 @@ /* - * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * Copyright(c) 2006 to 2020 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 @@ -9,1254 +9,483 @@ * * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ +#include + #include "dds/dds.h" - -#include "dds/ddsrt/cdtors.h" #include "dds/ddsrt/misc.h" -#include "dds/ddsrt/process.h" #include "dds/ddsrt/sync.h" -#include "dds/ddsrt/threads.h" - +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/environ.h" #include "test_common.h" +#include "test_oneliner.h" -/**************************************************************************** - * TODO: Add DDS_INCONSISTENT_TOPIC_STATUS test - * TODO: Add DDS_OFFERED/REQUESTED_DEADLINE_MISSED_STATUS test - * TODO: Add DDS_LIVELINESS_LOST_STATUS test - * TODO: Check DDS_REQUESTED_INCOMPATIBLE_QOS_STATUS intermittent fail (total_count != 1) - ****************************************************************************/ +#define DEFINE_STATUS_CALLBACK(name, NAME, kind) \ + static void name##_cb (dds_entity_t kind, const dds_##name##_status_t status, void *arg) \ + { \ + (void) arg; \ + (void) kind; \ + (void) status; \ + } + +DEFINE_STATUS_CALLBACK (inconsistent_topic, INCONSISTENT_TOPIC, topic) +DEFINE_STATUS_CALLBACK (liveliness_changed, LIVELINESS_CHANGED, reader) +DEFINE_STATUS_CALLBACK (liveliness_lost, LIVELINESS_LOST, writer) +DEFINE_STATUS_CALLBACK (offered_deadline_missed, OFFERED_DEADLINE_MISSED, writer) +DEFINE_STATUS_CALLBACK (offered_incompatible_qos, OFFERED_INCOMPATIBLE_QOS, writer) +DEFINE_STATUS_CALLBACK (publication_matched, PUBLICATION_MATCHED, writer) +DEFINE_STATUS_CALLBACK (requested_deadline_missed, REQUESTED_DEADLINE_MISSED, reader) +DEFINE_STATUS_CALLBACK (requested_incompatible_qos, REQUESTED_INCOMPATIBLE_QOS, reader) +DEFINE_STATUS_CALLBACK (sample_lost, SAMPLE_LOST, reader) +DEFINE_STATUS_CALLBACK (sample_rejected, SAMPLE_REJECTED, reader) +DEFINE_STATUS_CALLBACK (subscription_matched, SUBSCRIPTION_MATCHED, reader) + +static void data_on_readers_cb (dds_entity_t subscriber, void *arg) +{ + (void) subscriber; + (void) arg; +} + +static void data_available_cb (dds_entity_t reader, void *arg) +{ + (void) reader; + (void) arg; +} + +static void dummy_cb (void) +{ + // Used as a listener function in checking merging of listeners, + // and for that purpose, casting it to whatever function type is + // required is ok. It is not supposed to ever be called. + abort (); +} + +#undef DEFINE_STATUS_CALLBACK + +/************************************************** + **** **** + **** create/delete/get/set/copy/merge/reset **** + **** **** + **************************************************/ + +static void set_all_const (dds_listener_t *l, void (*c) (void)) +{ + dds_lset_data_available (l, (dds_on_data_available_fn) c); + dds_lset_data_on_readers (l, (dds_on_data_on_readers_fn) c); + dds_lset_inconsistent_topic (l, (dds_on_inconsistent_topic_fn) c); + dds_lset_liveliness_changed (l, (dds_on_liveliness_changed_fn) c); + dds_lset_liveliness_lost (l, (dds_on_liveliness_lost_fn) c); + dds_lset_offered_deadline_missed (l, (dds_on_offered_deadline_missed_fn) c); + dds_lset_offered_incompatible_qos (l, (dds_on_offered_incompatible_qos_fn) c); + dds_lset_publication_matched (l, (dds_on_publication_matched_fn) c); + dds_lset_requested_deadline_missed (l, (dds_on_requested_deadline_missed_fn) c); + dds_lset_requested_incompatible_qos (l, (dds_on_requested_incompatible_qos_fn) c); + dds_lset_sample_lost (l, (dds_on_sample_lost_fn) c); + dds_lset_sample_rejected (l, (dds_on_sample_rejected_fn) c); + dds_lset_subscription_matched (l, (dds_on_subscription_matched_fn) c); +} + +static void set_all (dds_listener_t *l) +{ + dds_lset_data_available (l, data_available_cb); + dds_lset_data_on_readers (l, data_on_readers_cb); + dds_lset_inconsistent_topic (l, inconsistent_topic_cb); + dds_lset_liveliness_changed (l, liveliness_changed_cb); + dds_lset_liveliness_lost (l, liveliness_lost_cb); + dds_lset_offered_deadline_missed (l, offered_deadline_missed_cb); + dds_lset_offered_incompatible_qos (l, offered_incompatible_qos_cb); + dds_lset_publication_matched (l, publication_matched_cb); + dds_lset_requested_deadline_missed (l, requested_deadline_missed_cb); + dds_lset_requested_incompatible_qos (l, requested_incompatible_qos_cb); + dds_lset_sample_lost (l, sample_lost_cb); + dds_lset_sample_rejected (l, sample_rejected_cb); + dds_lset_subscription_matched (l, subscription_matched_cb); +} -/**************************************************************************** - * Convenience test macros. - ****************************************************************************/ #define ASSERT_CALLBACK_EQUAL(fntype, listener, expected) \ - do { \ - dds_on_##fntype##_fn cb; \ - dds_lget_##fntype(listener, &cb); \ - CU_ASSERT_EQUAL(cb, expected); \ - } while (0) + do { \ + dds_on_##fntype##_fn cb; \ + dds_lget_##fntype(listener, &cb); \ + CU_ASSERT_EQUAL(cb, expected); \ + } while (0) -#define STR(fntype) #fntype##_cb - -#define TEST_GET_SET(listener, fntype, cb) \ - do { \ - dds_on_##fntype##_fn dummy = NULL; \ - /* Initially expect DDS_LUNSET on a newly created listener */ \ - ASSERT_CALLBACK_EQUAL(fntype, listener, DDS_LUNSET); \ - /* Using listener or callback NULL, shouldn't crash and be noop */ \ - dds_lset_##fntype(NULL, NULL); \ - dds_lget_##fntype(NULL, NULL); \ - dds_lget_##fntype(listener, NULL); \ - dds_lget_##fntype(NULL, &dummy); \ - CU_ASSERT_EQUAL_FATAL(dummy, NULL); \ - /* Set to NULL, get to confirm it succeeds */ \ - dds_lset_##fntype(listener, NULL); \ - ASSERT_CALLBACK_EQUAL(fntype, listener, NULL); \ - /* Set to a proper cb method, get to confirm it succeeds */ \ - dds_lset_##fntype(listener, cb); \ - ASSERT_CALLBACK_EQUAL(fntype, listener, cb); \ - } while (0) - - - -/**************************************************************************** - * Test globals. - ****************************************************************************/ -static dds_entity_t g_participant = 0; -static dds_entity_t g_subscriber = 0; -static dds_entity_t g_publisher = 0; -static dds_entity_t g_topic = 0; -static dds_entity_t g_writer = 0; -static dds_entity_t g_reader = 0; - -static dds_listener_t *g_listener = NULL; -static dds_qos_t *g_qos = NULL; -static ddsrt_mutex_t g_mutex; -static ddsrt_cond_t g_cond; - - - -/**************************************************************************** - * Callback stuff. - ****************************************************************************/ -static uint32_t cb_called = 0; -static dds_entity_t cb_topic = 0; -static dds_entity_t cb_writer = 0; -static dds_entity_t cb_reader = 0; -static dds_entity_t cb_subscriber = 0; - -static dds_inconsistent_topic_status_t cb_inconsistent_topic_status; -static dds_liveliness_lost_status_t cb_liveliness_lost_status; -static dds_offered_deadline_missed_status_t cb_offered_deadline_missed_status; -static dds_offered_incompatible_qos_status_t cb_offered_incompatible_qos_status; -static dds_sample_lost_status_t cb_sample_lost_status; -static dds_sample_rejected_status_t cb_sample_rejected_status; -static dds_liveliness_changed_status_t cb_liveliness_changed_status; -static dds_requested_deadline_missed_status_t cb_requested_deadline_missed_status; -static dds_requested_incompatible_qos_status_t cb_requested_incompatible_qos_status; -static dds_publication_matched_status_t cb_publication_matched_status; -static dds_subscription_matched_status_t cb_subscription_matched_status; - - -static void -inconsistent_topic_cb( - dds_entity_t topic, - const dds_inconsistent_topic_status_t status, void* arg) +static void check_all_const (const dds_listener_t *l, void (*c) (void)) { - (void)arg; - ddsrt_mutex_lock(&g_mutex); - cb_topic = topic; - cb_inconsistent_topic_status = status; - cb_called |= DDS_INCONSISTENT_TOPIC_STATUS; - ddsrt_cond_broadcast(&g_cond); - ddsrt_mutex_unlock(&g_mutex); + ASSERT_CALLBACK_EQUAL (data_available, l, (dds_on_data_available_fn) c); + ASSERT_CALLBACK_EQUAL (data_on_readers, l, (dds_on_data_on_readers_fn) c); + ASSERT_CALLBACK_EQUAL (inconsistent_topic, l, (dds_on_inconsistent_topic_fn) c); + ASSERT_CALLBACK_EQUAL (liveliness_changed, l, (dds_on_liveliness_changed_fn) c); + ASSERT_CALLBACK_EQUAL (liveliness_lost, l, (dds_on_liveliness_lost_fn) c); + ASSERT_CALLBACK_EQUAL (offered_deadline_missed, l, (dds_on_offered_deadline_missed_fn) c); + ASSERT_CALLBACK_EQUAL (offered_incompatible_qos, l, (dds_on_offered_incompatible_qos_fn) c); + ASSERT_CALLBACK_EQUAL (publication_matched, l, (dds_on_publication_matched_fn) c); + ASSERT_CALLBACK_EQUAL (requested_deadline_missed, l, (dds_on_requested_deadline_missed_fn) c); + ASSERT_CALLBACK_EQUAL (requested_incompatible_qos, l, (dds_on_requested_incompatible_qos_fn) c); + ASSERT_CALLBACK_EQUAL (sample_lost, l, (dds_on_sample_lost_fn) c); + ASSERT_CALLBACK_EQUAL (sample_rejected, l, (dds_on_sample_rejected_fn) c); + ASSERT_CALLBACK_EQUAL (subscription_matched, l, (dds_on_subscription_matched_fn) c); } -static void -liveliness_lost_cb( - dds_entity_t writer, - const dds_liveliness_lost_status_t status, - void* arg) +static void check_all (const dds_listener_t *l) { - (void)arg; - ddsrt_mutex_lock(&g_mutex); - cb_writer = writer; - cb_liveliness_lost_status = status; - cb_called |= DDS_LIVELINESS_LOST_STATUS; - ddsrt_cond_broadcast(&g_cond); - ddsrt_mutex_unlock(&g_mutex); + ASSERT_CALLBACK_EQUAL (data_available, l, data_available_cb); + ASSERT_CALLBACK_EQUAL (data_on_readers, l, data_on_readers_cb); + ASSERT_CALLBACK_EQUAL (inconsistent_topic, l, inconsistent_topic_cb); + ASSERT_CALLBACK_EQUAL (liveliness_changed, l, liveliness_changed_cb); + ASSERT_CALLBACK_EQUAL (liveliness_lost, l, liveliness_lost_cb); + ASSERT_CALLBACK_EQUAL (offered_deadline_missed, l, offered_deadline_missed_cb); + ASSERT_CALLBACK_EQUAL (offered_incompatible_qos, l, offered_incompatible_qos_cb); + ASSERT_CALLBACK_EQUAL (publication_matched, l, publication_matched_cb); + ASSERT_CALLBACK_EQUAL (requested_deadline_missed, l, requested_deadline_missed_cb); + ASSERT_CALLBACK_EQUAL (requested_incompatible_qos, l, requested_incompatible_qos_cb); + ASSERT_CALLBACK_EQUAL (sample_lost, l, sample_lost_cb); + ASSERT_CALLBACK_EQUAL (sample_rejected, l, sample_rejected_cb); + ASSERT_CALLBACK_EQUAL (subscription_matched, l, subscription_matched_cb); } -static void -offered_deadline_missed_cb( - dds_entity_t writer, - const dds_offered_deadline_missed_status_t status, - void* arg) +CU_Test (ddsc_listener, create_and_delete) { - (void)arg; - ddsrt_mutex_lock(&g_mutex); - cb_writer = writer; - cb_offered_deadline_missed_status = status; - cb_called |= DDS_OFFERED_DEADLINE_MISSED_STATUS; - ddsrt_cond_broadcast(&g_cond); - ddsrt_mutex_unlock(&g_mutex); + dds_listener_t *listener = dds_create_listener (NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL (listener); + check_all_const (listener, 0); + dds_delete_listener (listener); + + // check delete_listeners handles a null pointer gracefully + dds_delete_listener (NULL); } -static void -offered_incompatible_qos_cb( - dds_entity_t writer, - const dds_offered_incompatible_qos_status_t status, - void* arg) +CU_Test (ddsc_listener, reset) { - (void)arg; - ddsrt_mutex_lock(&g_mutex); - cb_writer = writer; - cb_offered_incompatible_qos_status = status; - cb_called |= DDS_OFFERED_INCOMPATIBLE_QOS_STATUS; - ddsrt_cond_broadcast(&g_cond); - ddsrt_mutex_unlock(&g_mutex); + dds_listener_t *listener = dds_create_listener (NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL (listener); + + set_all (listener); + + // all callbacks should revert to default after reset + dds_reset_listener (listener); + check_all_const (listener, 0); + dds_delete_listener (listener); + + // check reset_listeners handles a null pointer gracefully + dds_reset_listener (NULL); } -static void -data_on_readers_cb( - dds_entity_t subscriber, - void* arg) +CU_Test (ddsc_listener, copy) { - (void)arg; - ddsrt_mutex_lock(&g_mutex); - cb_subscriber = subscriber; - cb_called |= DDS_DATA_ON_READERS_STATUS; - ddsrt_cond_broadcast(&g_cond); - ddsrt_mutex_unlock(&g_mutex); + dds_listener_t *listener1 = dds_create_listener (NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL (listener1); + set_all (listener1); + + dds_listener_t *listener2 = dds_create_listener (NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL (listener2); + dds_copy_listener (listener2, listener1); + check_all (listener2); + + // Calling copy with NULL should not crash and be noops + dds_copy_listener (listener2, NULL); + dds_copy_listener (NULL, listener1); + dds_copy_listener (NULL, NULL); + + dds_delete_listener (listener1); + dds_delete_listener (listener2); } -static void -sample_lost_cb( - dds_entity_t reader, - const dds_sample_lost_status_t status, - void* arg) +CU_Test (ddsc_listener, merge) { - (void)arg; - ddsrt_mutex_lock(&g_mutex); - cb_reader = reader; - cb_sample_lost_status = status; - cb_called |= DDS_SAMPLE_LOST_STATUS; - ddsrt_cond_broadcast(&g_cond); - ddsrt_mutex_unlock(&g_mutex); -} + dds_listener_t *listener1 = dds_create_listener (NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL (listener1); + set_all (listener1); -static void -data_available_cb( - dds_entity_t reader, - void* arg) -{ - (void)arg; - ddsrt_mutex_lock(&g_mutex); - cb_reader = reader; - cb_called |= DDS_DATA_AVAILABLE_STATUS; - ddsrt_cond_broadcast(&g_cond); - ddsrt_mutex_unlock(&g_mutex); -} + // Merging listener1 into empty listener2 be like a copy + dds_listener_t *listener2 = dds_create_listener (NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL (listener2); + dds_merge_listener (listener2, listener1); + check_all (listener2); -static void -sample_rejected_cb( - dds_entity_t reader, - const dds_sample_rejected_status_t status, - void* arg) -{ - (void)arg; - ddsrt_mutex_lock(&g_mutex); - cb_reader = reader; - cb_sample_rejected_status = status; - cb_called |= DDS_SAMPLE_REJECTED_STATUS; - ddsrt_cond_broadcast(&g_cond); - ddsrt_mutex_unlock(&g_mutex); -} + // Merging listener into a full listener2 should not overwrite anything + set_all_const (listener2, dummy_cb); + dds_merge_listener (listener2, listener1); + check_all_const (listener2, dummy_cb); -static void -liveliness_changed_cb( - dds_entity_t reader, - const dds_liveliness_changed_status_t status, - void* arg) -{ - (void)arg; - ddsrt_mutex_lock(&g_mutex); - cb_reader = reader; - cb_liveliness_changed_status = status; - cb_called |= DDS_LIVELINESS_CHANGED_STATUS; - ddsrt_cond_broadcast(&g_cond); - ddsrt_mutex_unlock(&g_mutex); -} + // Using NULLs shouldn't crash and be noops + dds_merge_listener (listener2, NULL); + dds_merge_listener (NULL, listener1); + dds_merge_listener (NULL, NULL); -static void -requested_deadline_missed_cb( - dds_entity_t reader, - const dds_requested_deadline_missed_status_t status, - void* arg) -{ - (void)arg; - ddsrt_mutex_lock(&g_mutex); - cb_reader = reader; - cb_requested_deadline_missed_status = status; - cb_called |= DDS_REQUESTED_DEADLINE_MISSED_STATUS; - ddsrt_cond_broadcast(&g_cond); - ddsrt_mutex_unlock(&g_mutex); -} - -static void -requested_incompatible_qos_cb( - dds_entity_t reader, - const dds_requested_incompatible_qos_status_t status, - void* arg) -{ - (void)arg; - ddsrt_mutex_lock(&g_mutex); - cb_reader = reader; - cb_requested_incompatible_qos_status = status; - cb_called |= DDS_REQUESTED_INCOMPATIBLE_QOS_STATUS; - ddsrt_cond_broadcast(&g_cond); - ddsrt_mutex_unlock(&g_mutex); -} - -static void -publication_matched_cb( - dds_entity_t writer, - const dds_publication_matched_status_t status, - void* arg) -{ - (void)arg; - ddsrt_mutex_lock(&g_mutex); - cb_writer = writer; - cb_publication_matched_status = status; - cb_called |= DDS_PUBLICATION_MATCHED_STATUS; - ddsrt_cond_broadcast(&g_cond); - ddsrt_mutex_unlock(&g_mutex); -} - -static void -subscription_matched_cb( - dds_entity_t reader, - const dds_subscription_matched_status_t status, - void* arg) -{ - (void)arg; - ddsrt_mutex_lock(&g_mutex); - cb_reader = reader; - cb_subscription_matched_status = status; - cb_called |= DDS_SUBSCRIPTION_MATCHED_STATUS; - ddsrt_cond_broadcast(&g_cond); - ddsrt_mutex_unlock(&g_mutex); -} - -static void -callback_dummy(void) -{ -} - -static uint32_t -waitfor_cb(uint32_t expected) -{ - dds_time_t timeout = 5 * DDS_NSECS_IN_SEC; - bool signalled = true; - ddsrt_mutex_lock(&g_mutex); - while (((cb_called & expected) != expected) && (signalled)) { - signalled = ddsrt_cond_waitfor(&g_cond, &g_mutex, timeout); - } - ddsrt_mutex_unlock(&g_mutex); - return cb_called; -} - - - -/**************************************************************************** - * Test initializations and teardowns. - ****************************************************************************/ - -static void -init_triggering_base(void) -{ - char name[100]; - - ddsrt_init(); - - ddsrt_mutex_init(&g_mutex); - ddsrt_cond_init(&g_cond); - - g_participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); - CU_ASSERT_FATAL(g_participant > 0); - - g_subscriber = dds_create_subscriber(g_participant, NULL, NULL); - CU_ASSERT_FATAL(g_subscriber > 0); - - g_publisher = dds_create_publisher(g_participant, NULL, NULL); - CU_ASSERT_FATAL(g_publisher > 0); - - g_topic = dds_create_topic(g_participant, &RoundTripModule_DataType_desc, create_unique_topic_name("ddsc_listener_test", name, 100), NULL, NULL); - CU_ASSERT_FATAL(g_topic > 0); - - g_listener = dds_create_listener(NULL); - CU_ASSERT_PTR_NOT_NULL_FATAL(g_listener); - - g_qos = dds_create_qos(); - CU_ASSERT_PTR_NOT_NULL_FATAL(g_qos); - dds_qset_reliability(g_qos, DDS_RELIABILITY_RELIABLE, DDS_SECS(1)); - dds_qset_history(g_qos, DDS_HISTORY_KEEP_ALL, 0); - - cb_called = 0; -} - -static void -init_triggering_test(void) -{ - uint32_t triggered; - - /* Initialize base. */ - init_triggering_base(); - - /* Set QoS Policies that'll help us test various status callbacks. */ - dds_qset_destination_order(g_qos, DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP); - dds_qset_reliability(g_qos, DDS_RELIABILITY_BEST_EFFORT, DDS_MSECS(100)); - dds_qset_resource_limits(g_qos, 1, 1, 1); - - /* Use these to be sure reader and writer know each other. */ - dds_lset_publication_matched(g_listener, publication_matched_cb); - dds_lset_subscription_matched(g_listener, subscription_matched_cb); - dds_lset_liveliness_changed(g_listener, liveliness_changed_cb); - - /* Create reader and writer with proper listeners. */ - g_writer = dds_create_writer(g_publisher, g_topic, g_qos, g_listener); - CU_ASSERT(g_writer > 0); - g_reader = dds_create_reader(g_subscriber, g_topic, g_qos, g_listener); - CU_ASSERT(g_reader > 0); - - /* Sync. */ - triggered = waitfor_cb(DDS_PUBLICATION_MATCHED_STATUS | DDS_SUBSCRIPTION_MATCHED_STATUS | DDS_LIVELINESS_CHANGED_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_LIVELINESS_CHANGED_STATUS, DDS_LIVELINESS_CHANGED_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_PUBLICATION_MATCHED_STATUS, DDS_PUBLICATION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_SUBSCRIPTION_MATCHED_STATUS, DDS_SUBSCRIPTION_MATCHED_STATUS); -} - -static void -fini_triggering_base(void) -{ - dds_delete_qos(g_qos); - dds_delete_listener(g_listener); - dds_delete(g_participant); - ddsrt_cond_destroy(&g_cond); - ddsrt_mutex_destroy(&g_mutex); - ddsrt_fini(); -} - -static void -fini_triggering_test(void) -{ - dds_delete(g_reader); - if (g_writer) - dds_delete(g_writer); - fini_triggering_base(); -} - - -/**************************************************************************** - * API tests - ****************************************************************************/ -CU_Test(ddsc_listener, create_and_delete) -{ - /* Verify create doesn't return null */ - dds_listener_t *listener; - listener = dds_create_listener(NULL); - CU_ASSERT_PTR_NOT_NULL_FATAL(listener); - - /* Check default cb's are set */ - ASSERT_CALLBACK_EQUAL(inconsistent_topic, listener, DDS_LUNSET); - ASSERT_CALLBACK_EQUAL(liveliness_lost, listener, DDS_LUNSET); - ASSERT_CALLBACK_EQUAL(offered_deadline_missed, listener, DDS_LUNSET); - ASSERT_CALLBACK_EQUAL(offered_incompatible_qos, listener, DDS_LUNSET); - ASSERT_CALLBACK_EQUAL(data_on_readers, listener, DDS_LUNSET); - ASSERT_CALLBACK_EQUAL(sample_lost, listener, DDS_LUNSET); - ASSERT_CALLBACK_EQUAL(sample_rejected, listener, DDS_LUNSET); - ASSERT_CALLBACK_EQUAL(liveliness_changed, listener, DDS_LUNSET); - ASSERT_CALLBACK_EQUAL(requested_deadline_missed, listener, DDS_LUNSET); - ASSERT_CALLBACK_EQUAL(requested_incompatible_qos, listener, DDS_LUNSET); - ASSERT_CALLBACK_EQUAL(publication_matched, listener, DDS_LUNSET); - ASSERT_CALLBACK_EQUAL(subscription_matched, listener, DDS_LUNSET); - ASSERT_CALLBACK_EQUAL(data_available, listener, DDS_LUNSET); - - dds_delete_listener(listener); - DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ - dds_delete_listener(NULL); - DDSRT_WARNING_MSVC_ON(6387); -} - -CU_Test(ddsc_listener, reset) -{ - dds_listener_t *listener; - listener = dds_create_listener(NULL); - CU_ASSERT_PTR_NOT_NULL_FATAL(listener); - - /* Set a listener cb to a non-default value */ - dds_lset_data_available(listener, NULL); - ASSERT_CALLBACK_EQUAL(data_available, listener, NULL); - - /* Listener cb should revert to default after reset */ - dds_reset_listener(listener); - ASSERT_CALLBACK_EQUAL(data_available, listener, DDS_LUNSET); - - /* Resetting a NULL listener should not crash */ - dds_reset_listener(NULL); - - dds_delete_listener(listener); -} - -CU_Test(ddsc_listener, copy) -{ - dds_listener_t *listener1 = NULL, *listener2 = NULL; - listener1 = dds_create_listener(NULL); - listener2 = dds_create_listener(NULL); - CU_ASSERT_PTR_NOT_NULL_FATAL(listener1); - CU_ASSERT_PTR_NOT_NULL_FATAL(listener2); - - /* Set some listener1 callbacks to non-default values */ - dds_lset_data_available(listener1, NULL); - dds_lset_sample_lost(listener1, sample_lost_cb); - ASSERT_CALLBACK_EQUAL(data_available, listener1, NULL); - ASSERT_CALLBACK_EQUAL(sample_lost, listener1, sample_lost_cb); - ASSERT_CALLBACK_EQUAL(data_available, listener2, DDS_LUNSET); - ASSERT_CALLBACK_EQUAL(sample_lost, listener2, DDS_LUNSET); - - /* Cb's should be copied to listener2 */ - dds_copy_listener(listener2, listener1); - ASSERT_CALLBACK_EQUAL(data_available, listener1, NULL); - ASSERT_CALLBACK_EQUAL(data_available, listener2, NULL); - ASSERT_CALLBACK_EQUAL(sample_lost, listener1, sample_lost_cb); - ASSERT_CALLBACK_EQUAL(sample_lost, listener2, sample_lost_cb); - - /* Calling copy with NULL should not crash and be noops. */ - DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ - dds_copy_listener(listener2, NULL); - dds_copy_listener(NULL, listener1); - dds_copy_listener(NULL, NULL); - DDSRT_WARNING_MSVC_ON(6387); - - dds_delete_listener(listener1); - dds_delete_listener(listener2); -} - -CU_Test(ddsc_listener, merge) -{ - dds_listener_t *listener1 = NULL, *listener2 = NULL; - listener1 = dds_create_listener(NULL); - listener2 = dds_create_listener(NULL); - CU_ASSERT_PTR_NOT_NULL_FATAL(listener1); - CU_ASSERT_PTR_NOT_NULL_FATAL(listener2); - - /* Set all listener1 callbacks to non-default values */ - dds_lset_inconsistent_topic (listener1, inconsistent_topic_cb); - dds_lset_liveliness_lost (listener1, liveliness_lost_cb); - dds_lset_offered_deadline_missed (listener1, offered_deadline_missed_cb); - dds_lset_offered_incompatible_qos (listener1, offered_incompatible_qos_cb); - dds_lset_data_on_readers (listener1, data_on_readers_cb); - dds_lset_sample_lost (listener1, sample_lost_cb); - dds_lset_data_available (listener1, data_available_cb); - dds_lset_sample_rejected (listener1, sample_rejected_cb); - dds_lset_liveliness_changed (listener1, liveliness_changed_cb); - dds_lset_requested_deadline_missed (listener1, requested_deadline_missed_cb); - dds_lset_requested_incompatible_qos (listener1, requested_incompatible_qos_cb); - dds_lset_publication_matched (listener1, publication_matched_cb); - dds_lset_subscription_matched (listener1, subscription_matched_cb); - - /* Merging listener1 into empty listener2 should act a bit like a copy. */ - dds_merge_listener(listener2, listener1); - ASSERT_CALLBACK_EQUAL(inconsistent_topic, listener2, inconsistent_topic_cb); - ASSERT_CALLBACK_EQUAL(liveliness_lost, listener2, liveliness_lost_cb); - ASSERT_CALLBACK_EQUAL(offered_deadline_missed, listener2, offered_deadline_missed_cb); - ASSERT_CALLBACK_EQUAL(offered_incompatible_qos, listener2, offered_incompatible_qos_cb); - ASSERT_CALLBACK_EQUAL(data_on_readers, listener2, data_on_readers_cb); - ASSERT_CALLBACK_EQUAL(sample_lost, listener2, sample_lost_cb); - ASSERT_CALLBACK_EQUAL(data_available, listener2, data_available_cb); - ASSERT_CALLBACK_EQUAL(sample_rejected, listener2, sample_rejected_cb); - ASSERT_CALLBACK_EQUAL(liveliness_changed, listener2, liveliness_changed_cb); - ASSERT_CALLBACK_EQUAL(requested_deadline_missed, listener2, requested_deadline_missed_cb); - ASSERT_CALLBACK_EQUAL(requested_incompatible_qos, listener2, requested_incompatible_qos_cb); - ASSERT_CALLBACK_EQUAL(publication_matched, listener2, publication_matched_cb); - ASSERT_CALLBACK_EQUAL(subscription_matched, listener2, subscription_matched_cb); - - /* Merging listener into a full listener2 should act as a noop. */ - dds_lset_inconsistent_topic (listener2, (dds_on_inconsistent_topic_fn)callback_dummy); - dds_lset_liveliness_lost (listener2, (dds_on_liveliness_lost_fn)callback_dummy); - dds_lset_offered_deadline_missed (listener2, (dds_on_offered_deadline_missed_fn)callback_dummy); - dds_lset_offered_incompatible_qos (listener2, (dds_on_offered_incompatible_qos_fn)callback_dummy); - dds_lset_data_on_readers (listener2, (dds_on_data_on_readers_fn)callback_dummy); - dds_lset_sample_lost (listener2, (dds_on_sample_lost_fn)callback_dummy); - dds_lset_data_available (listener2, (dds_on_data_available_fn)callback_dummy); - dds_lset_sample_rejected (listener2, (dds_on_sample_rejected_fn)callback_dummy); - dds_lset_liveliness_changed (listener2, (dds_on_liveliness_changed_fn)callback_dummy); - dds_lset_requested_deadline_missed (listener2, (dds_on_requested_deadline_missed_fn)callback_dummy); - dds_lset_requested_incompatible_qos (listener2, (dds_on_requested_incompatible_qos_fn)callback_dummy); - dds_lset_publication_matched (listener2, (dds_on_publication_matched_fn)callback_dummy); - dds_lset_subscription_matched (listener2, (dds_on_subscription_matched_fn)callback_dummy); - dds_merge_listener(listener2, listener1); - ASSERT_CALLBACK_EQUAL(inconsistent_topic, listener2, (dds_on_inconsistent_topic_fn)callback_dummy); - ASSERT_CALLBACK_EQUAL(liveliness_lost, listener2, (dds_on_liveliness_lost_fn)callback_dummy); - ASSERT_CALLBACK_EQUAL(offered_deadline_missed, listener2, (dds_on_offered_deadline_missed_fn)callback_dummy); - ASSERT_CALLBACK_EQUAL(offered_incompatible_qos, listener2, (dds_on_offered_incompatible_qos_fn)callback_dummy); - ASSERT_CALLBACK_EQUAL(data_on_readers, listener2, (dds_on_data_on_readers_fn)callback_dummy); - ASSERT_CALLBACK_EQUAL(sample_lost, listener2, (dds_on_sample_lost_fn)callback_dummy); - ASSERT_CALLBACK_EQUAL(data_available, listener2, (dds_on_data_available_fn)callback_dummy); - ASSERT_CALLBACK_EQUAL(sample_rejected, listener2, (dds_on_sample_rejected_fn)callback_dummy); - ASSERT_CALLBACK_EQUAL(liveliness_changed, listener2, (dds_on_liveliness_changed_fn)callback_dummy); - ASSERT_CALLBACK_EQUAL(requested_deadline_missed, listener2, (dds_on_requested_deadline_missed_fn)callback_dummy); - ASSERT_CALLBACK_EQUAL(requested_incompatible_qos, listener2, (dds_on_requested_incompatible_qos_fn)callback_dummy); - ASSERT_CALLBACK_EQUAL(publication_matched, listener2, (dds_on_publication_matched_fn)callback_dummy); - ASSERT_CALLBACK_EQUAL(subscription_matched, listener2, (dds_on_subscription_matched_fn)callback_dummy); - - /* Using NULLs shouldn't crash and be noops. */ - dds_merge_listener(listener2, NULL); - dds_merge_listener(NULL, listener1); - dds_merge_listener(NULL, NULL); - - dds_delete_listener(listener1); - dds_delete_listener(listener2); + dds_delete_listener (listener1); + dds_delete_listener (listener2); } CU_Test(ddsc_listener, getters_setters) { - /* test all individual cb get/set methods */ - dds_listener_t *listener = dds_create_listener(NULL); - CU_ASSERT_PTR_NOT_NULL_FATAL(listener); + // test all individual cb get/set methods + dds_listener_t *listener = dds_create_listener (NULL); + CU_ASSERT_PTR_NOT_NULL_FATAL (listener); - DDSRT_WARNING_MSVC_OFF(6387); /* Disable SAL warning on intentional misuse of the API */ \ - TEST_GET_SET(listener, inconsistent_topic, inconsistent_topic_cb); - TEST_GET_SET(listener, liveliness_lost, liveliness_lost_cb); - TEST_GET_SET(listener, offered_deadline_missed, offered_deadline_missed_cb); - TEST_GET_SET(listener, offered_incompatible_qos, offered_incompatible_qos_cb); - TEST_GET_SET(listener, data_on_readers, data_on_readers_cb); - TEST_GET_SET(listener, sample_lost, sample_lost_cb); - TEST_GET_SET(listener, sample_rejected, sample_rejected_cb); - TEST_GET_SET(listener, liveliness_changed, liveliness_changed_cb); - TEST_GET_SET(listener, requested_deadline_missed, requested_deadline_missed_cb); - TEST_GET_SET(listener, requested_incompatible_qos, requested_incompatible_qos_cb); - TEST_GET_SET(listener, publication_matched, publication_matched_cb); - TEST_GET_SET(listener, subscription_matched, subscription_matched_cb); - TEST_GET_SET(listener, data_available, data_available_cb); - DDSRT_WARNING_MSVC_ON(6387); +#define TEST_GET_SET(listener, fntype, cb) \ + do { \ + dds_on_##fntype##_fn dummy = NULL; \ + /* Initially expect DDS_LUNSET on a newly created listener */ \ + ASSERT_CALLBACK_EQUAL (fntype, listener, 0); \ + /* Using listener or callback NULL, shouldn't crash and be noop */ \ + dds_lset_##fntype (NULL, NULL); \ + dds_lget_##fntype (NULL, NULL); \ + dds_lget_##fntype (listener, NULL); \ + dds_lget_##fntype (NULL, &dummy); \ + CU_ASSERT_EQUAL_FATAL (dummy, NULL); \ + /* Set to NULL, get to confirm it succeeds */ \ + dds_lset_##fntype (listener, NULL); \ + ASSERT_CALLBACK_EQUAL (fntype, listener, NULL); \ + /* Set to a proper cb method, get to confirm it succeeds */ \ + dds_lset_##fntype (listener, cb); \ + ASSERT_CALLBACK_EQUAL (fntype, listener, cb); \ + } while (0) + TEST_GET_SET (listener, data_available, data_available_cb); + TEST_GET_SET (listener, data_on_readers, data_on_readers_cb); + TEST_GET_SET (listener, inconsistent_topic, inconsistent_topic_cb); + TEST_GET_SET (listener, liveliness_changed, liveliness_changed_cb); + TEST_GET_SET (listener, liveliness_lost, liveliness_lost_cb); + TEST_GET_SET (listener, offered_deadline_missed, offered_deadline_missed_cb); + TEST_GET_SET (listener, offered_incompatible_qos, offered_incompatible_qos_cb); + TEST_GET_SET (listener, publication_matched, publication_matched_cb); + TEST_GET_SET (listener, requested_deadline_missed, requested_deadline_missed_cb); + TEST_GET_SET (listener, requested_incompatible_qos, requested_incompatible_qos_cb); + TEST_GET_SET (listener, sample_lost, sample_lost_cb); + TEST_GET_SET (listener, sample_rejected, sample_rejected_cb); + TEST_GET_SET (listener, subscription_matched, subscription_matched_cb); +#undef TEST_GET_SET - dds_delete_listener(listener); + dds_delete_listener (listener); } +#undef ASSERT_CALLBACK_EQUAL +#define dotest(ops) CU_ASSERT_FATAL (test_oneliner (ops) > 0) -/**************************************************************************** - * Triggering tests - ****************************************************************************/ -CU_Test(ddsc_listener, propagation, .init=init_triggering_base, .fini=fini_triggering_base) +CU_Test (ddsc_listener, propagation) { - dds_listener_t *listener_par = NULL; - dds_listener_t *listener_pub = NULL; - dds_listener_t *listener_sub = NULL; - uint32_t triggered; - dds_return_t ret; - RoundTripModule_DataType sample; - memset (&sample, 0, sizeof (sample)); - - /* Let participant be interested in data. */ - listener_par = dds_create_listener(NULL); - CU_ASSERT_PTR_NOT_NULL_FATAL(listener_par); - dds_lset_data_on_readers(listener_par, data_on_readers_cb); - ret = dds_set_listener(g_participant, listener_par); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - dds_delete_listener(listener_par); - - /* Let publisher be interested in publication matched. */ - listener_pub = dds_create_listener(NULL); - CU_ASSERT_PTR_NOT_NULL_FATAL(listener_pub); - dds_lset_publication_matched(listener_pub, publication_matched_cb); - ret = dds_set_listener(g_publisher, listener_pub); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - dds_delete_listener(listener_pub); - - /* Let subscriber be interested in subscription matched. */ - listener_sub = dds_create_listener(NULL); - CU_ASSERT_PTR_NOT_NULL_FATAL(listener_pub); - dds_lset_subscription_matched(listener_sub, subscription_matched_cb); - ret = dds_set_listener(g_subscriber, listener_sub); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - dds_delete_listener(listener_sub); - - /* Create reader and writer without listeners. */ - g_reader = dds_create_reader(g_subscriber, g_topic, g_qos, NULL); - CU_ASSERT_FATAL(g_reader > 0); - g_writer = dds_create_writer(g_publisher, g_topic, g_qos, NULL); - CU_ASSERT_FATAL(g_writer > 0); - - /* Publication and Subscription should be matched. */ - triggered = waitfor_cb(DDS_PUBLICATION_MATCHED_STATUS | DDS_SUBSCRIPTION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_SUBSCRIPTION_MATCHED_STATUS, DDS_SUBSCRIPTION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_PUBLICATION_MATCHED_STATUS, DDS_PUBLICATION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_writer, g_writer); - CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); - - /* Write sample. */ - ret = dds_write(g_writer, &sample); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - - /* Data on readers should be triggered with the right status. */ - triggered = waitfor_cb(DDS_DATA_ON_READERS_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_DATA_ON_READERS_STATUS, DDS_DATA_ON_READERS_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_subscriber, g_subscriber); - CU_ASSERT_NOT_EQUAL_FATAL(triggered & DDS_DATA_AVAILABLE_STATUS, DDS_DATA_AVAILABLE_STATUS); - - dds_delete(g_writer); - dds_delete(g_reader); + // data-on-readers set on a participant at creation time must not trigger for + // the readers for DCPSPublication and DCPSSubscription: those events must be + // invisible for the test logic to work reliably. Installing a dummy listener + // for it on the reader should prevent that from happening + dotest ("da dor lc sm P ; ?!dor ?!da ?!sm ?!lc"); + // writing data should trigger data-available unless data-on-readers is set + dotest ("da lc sm P ; r ; wr w 0 ; ?da r ?sm r ?lc r"); + dotest ("da dor lc sm P ; r ; wr w 0 ; ?!da ; ?dor R ?sm r ?lc r"); + // setting listeners after entity creation should work, too + dotest ("P W R ; dor P pm W sm R ; r w ; ?sm r ?pm w ; wr w 0 ; ?dor R ; ?!da"); } - -CU_Test(ddsc_listener, matched, .init=init_triggering_base, .fini=fini_triggering_base) +CU_Test (ddsc_listener, matched) { - uint32_t triggered; + // publication & subscription matched must both trigger; note: reader/writer matching inside + // a process is synchronous, no need to check everywhere + dotest ("sm r pm w ?pm w ?sm r"); + // across the network it should work just as well (matching happens on different threads for + // remote & local entity creation, so it is meaningfully different test) + dotest ("sm r pm w' ?pm w' ?sm r"); - /* We will basically do the same as the 'normal' init_triggering_test() and - * fini_triggering_test() calls. It's just that we do it in a different - * order and use the participant iso subscriber and publisher. */ + // Disconnect + reconnect; "deaf P" means the disconnect is asymmetrical: P no longer observes P' + // but P' still observes P. If r did not ack the data before losing connectivity, w' will hold + // the data and it will be re-delivered after reconnecting, depending on QoS settings (the "..." + // allows for extra samples) and whether the instance was taken or not + // + // If r did ack the data, w will drop it and it can't be delivered. If there is another r'' that + // did not ack, r will still not get the data because the writer determines that it was ack'd + // already and it won't retransmit. + // FIXME: this differs from what the spec says should happen, maybe it should be changed? + // (It is a fall-out from changes to make sure a volatile reader doesn't get historical data, but + // it could be handled differently.) + // + // Waiting for an acknowledgement therefore makes sense (and in the other runs, a 0.3s sleep + // kind-a solves the problem of not known exactly how many events there will be: it means at + // least one event has been observed, and behaviour of Cyclone in a simple case like this means + // the full retransmit request will be replied to with a single packet, and that therefore the + // likelihood of the retransmitted data arriving within a window of 0.3s is very high. (Where + // 0.3s is an attempt to pick a duration on the long side of what's needed and short enough not + // to delay things much.) + dotest ("sm da r pm w' ?sm r ?pm w' ;" // matched reader/writer pair + " wr w' 1 ; ?da r take{(1,0,0)} r ?ack w' ;" // wait-for-acks => writer drops data + " deaf P ; ?sm(1,0,0,-1,w') r ?da r take{d1} r ; wr w' 2 ;" // write lost on "wire" + " hearing P ; ?sm(2,1,1,1,w') r ?da r sleep 0.3 take{(2,0,0)} r ; ?!pm"); + dotest ("sm da r pm w' ; ?sm r ?pm w' ;" + " r'' ?pm w' deaf P'' ;" // with second reader: reader is deaf so won't ACK + " wr w' 1 ; ?da r take{(1,0,0)} r ?ack(r) w' ;" // wait for ack from r' (not r'') + " deaf P ; ?sm(1,0,0,-1,w') r ?da r take{d1} r ; wr w' 2 ;" // write lost on "wire" + " hearing P ; ?sm(2,1,1,1,w') r ?da r sleep 0.3 take{(2,0,0)} r ; ?!pm"); + // same without taking the "dispose" after disconnect + // sample 1 will be delivered anew + dotest ("sm da r pm w' ; ?sm r ?pm w' ; wr w' 1 ; ?da r take{(1,0,0)} r ;" + " deaf P ; ?sm(1,0,0,-1,w') r ?da r ; wr w' 2 ;" + " hearing P ; ?sm(2,1,1,1,w') r ?da r sleep 0.3 take{d1,(2,0,0)} r ; ?!pm"); - /* We are interested in matched notifications. */ - dds_lset_publication_matched(g_listener, publication_matched_cb); - dds_lset_subscription_matched(g_listener, subscription_matched_cb); - - /* Create reader and writer with proper listeners. - * The creation order is deliberately different from publication_matched and subscription_matched. */ - g_reader = dds_create_reader(g_participant, g_topic, g_qos, g_listener); - CU_ASSERT_FATAL(g_reader > 0); - g_writer = dds_create_writer(g_participant, g_topic, g_qos, g_listener); - CU_ASSERT_FATAL(g_writer > 0); - - /* Both matched should be triggered on the right entities. */ - triggered = waitfor_cb(DDS_PUBLICATION_MATCHED_STATUS | DDS_SUBSCRIPTION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_SUBSCRIPTION_MATCHED_STATUS, DDS_SUBSCRIPTION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_PUBLICATION_MATCHED_STATUS, DDS_PUBLICATION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_writer, g_writer); - CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); - - dds_delete(g_writer); - dds_delete(g_reader); + // if a volatile writer loses the reader temporarily, the data won't show up + dotest ("sm da r pm w' ; ?sm r ?pm w' ; wr w' 1 ; ?da r read{(1,0,0)} r ;" + " deaf P' ; ?!sm ?!da ?pm(1,0,0,-1,r) w' ; wr w' 2 ;" + " hearing P' ; ?!sm ?pm(2,1,1,1,r) w' ?!da ; wr w' 3 ;" + " ?da r sleep 0.3 read{s(1,0,0),f(3,0,0)} r"); + // if a transient-local writer loses the reader temporarily, what data + // has been published during the disconnect must still show up; delete + // writer, &c. checks nothing else showed up afterward + // - first: durability service history depth 1: 2nd write of 2 pushes + // the 1st write of it out of the history and only 2 samples arrive + // - second: d.s. keep-all: both writes are kept and 3 samples arrive + dotest ("sm da r(d=tl) pm w'(d=tl,h=1,ds=0/1) ; ?sm r ?pm w' ;" + " wr w' 1 ; ?da r read{(1,0,0)} r ;" + " deaf P' ; ?pm(1,0,0,-1,r) w' ; wr w' 2 wr w' 2 ;" + " hearing P' ; ?pm(2,1,1,1,r) w' ; wr w' 3 ;" + " ?da(2) r read{s(1,0,0),f(2,0,0),f(3,0,0)} r ;" + " -w' ?sm r ?da r read(3,3) r"); + dotest ("sm da r(d=tl) pm w'(d=tl,h=1,ds=0/all) ; ?sm r ?pm w' ;" + " wr w' 1 ; ?da r read{(1,0,0)} r ;" + " deaf P' ; ?pm(1,0,0,-1,r) w' ; wr w' 2 wr w' 2 ;" + " hearing P' ; ?pm(2,1,1,1,r) w' ; wr w' 3 ;" + " ?da(3) r read{s(1,0,0),f(2,0,0),f(2,0,0),f(3,0,0)} r ;" + " -w' ?sm r ?da r read(4,3) r"); } -CU_Test(ddsc_listener, publication_matched, .init=init_triggering_test, .fini=fini_triggering_test) +CU_Test (ddsc_listener, publication_matched) { - dds_publication_matched_status_t publication_matched; - dds_instance_handle_t reader_hdl; - dds_return_t ret; - uint32_t triggered; - uint32_t status; + // regardless of order of creation, the writer should see one reader come & then go + dotest ("sm r pm w ; ?pm(1,1,1,1,r) w ?sm r ; -r ; ?pm(1,0,0,-1,r) w"); + dotest ("pm w sm r ; ?pm(1,1,1,1,r) w ?sm r ; -r ; ?pm(1,0,0,-1,r) w"); - /* Get reader handle that should be part of the status. */ - ret = dds_get_instance_handle(g_reader, &reader_hdl); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + // regardless of order of creation, the writer should see one reader come & then go, also + // when a second reader introduced + dotest ("sm r pm w ; ?pm(1,1,1,1,r) w ?sm r ; t ?pm(2,1,2,1,t) w ; -r ; ?pm(2,0,1,-1,r) w"); + dotest ("pm w sm r ; ?pm(1,1,1,1,r) w ?sm r ; t ?pm(2,1,2,1,t) w ; -t ; ?pm(2,0,1,-1,t) w"); - /* Publication matched should be triggered with the right status. */ - triggered = waitfor_cb(DDS_PUBLICATION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_PUBLICATION_MATCHED_STATUS, DDS_PUBLICATION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_writer, g_writer); - CU_ASSERT_EQUAL_FATAL(cb_publication_matched_status.current_count, 1); - CU_ASSERT_EQUAL_FATAL(cb_publication_matched_status.current_count_change, 1); - CU_ASSERT_EQUAL_FATAL(cb_publication_matched_status.total_count, 1); - CU_ASSERT_EQUAL_FATAL(cb_publication_matched_status.total_count_change, 1); - CU_ASSERT_EQUAL_FATAL(cb_publication_matched_status.last_subscription_handle, reader_hdl); + // same with 2 domains + dotest ("sm r pm w' ; ?pm(1,1,1,1,r) w' ?sm r ; -r ; ?pm(1,0,0,-1,r) w'"); + dotest ("pm w sm r' ; ?pm(1,1,1,1,r') w ?sm r' ; -r' ; ?pm(1,0,0,-1,r') w"); - /* The listener should have swallowed the status. */ - ret = dds_read_status(g_writer, &status, DDS_PUBLICATION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); - - /* The listener should have reset the count_change. */ - ret = dds_get_publication_matched_status(g_writer, &publication_matched); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(publication_matched.current_count, 1); - CU_ASSERT_EQUAL_FATAL(publication_matched.current_count_change, 0); - CU_ASSERT_EQUAL_FATAL(publication_matched.total_count, 1); - CU_ASSERT_EQUAL_FATAL(publication_matched.total_count_change, 0); - CU_ASSERT_EQUAL_FATAL(publication_matched.last_subscription_handle, reader_hdl); - - /* Reset the trigger flags. */ - ddsrt_mutex_lock(&g_mutex); - cb_called = 0; - ddsrt_mutex_unlock(&g_mutex); - - /* Un-match the publication by deleting the reader. */ - dds_delete(g_reader); - - /* Publication matched should be triggered with the right status. */ - triggered = waitfor_cb(DDS_PUBLICATION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_PUBLICATION_MATCHED_STATUS, DDS_PUBLICATION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_writer, g_writer); - CU_ASSERT_EQUAL_FATAL(cb_publication_matched_status.current_count, 0); - CU_ASSERT_EQUAL_FATAL(cb_publication_matched_status.current_count_change, -1); - CU_ASSERT_EQUAL_FATAL(cb_publication_matched_status.total_count, 1); - CU_ASSERT_EQUAL_FATAL(cb_publication_matched_status.total_count_change, 0); - CU_ASSERT_EQUAL_FATAL(cb_publication_matched_status.last_subscription_handle, reader_hdl); - - /* The listener should have reset the count_change. */ - ret = dds_get_publication_matched_status(g_writer, &publication_matched); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(publication_matched.current_count, 0); - CU_ASSERT_EQUAL_FATAL(publication_matched.current_count_change, 0); - CU_ASSERT_EQUAL_FATAL(publication_matched.total_count, 1); - CU_ASSERT_EQUAL_FATAL(publication_matched.total_count_change, 0); - CU_ASSERT_EQUAL_FATAL(publication_matched.last_subscription_handle, reader_hdl); + dotest ("sm r pm w' ; ?pm(1,1,1,1,r) w' ?sm r ; t ?pm(2,1,2,1,t) w' ; -r ; ?pm(2,0,1,-1,r) w'"); + dotest ("pm w sm r' ; ?pm(1,1,1,1,r') w ?sm r' ; t ?pm(2,1,2,1,t) w ; -t ; ?pm(2,0,1,-1,t) w"); + dotest ("sm r pm w' ; ?pm(1,1,1,1,r) w' ?sm r ; t' ?pm(2,1,2,1,t') w' ; -r ; ?pm(2,0,1,-1,r) w'"); + dotest ("pm w sm r' ; ?pm(1,1,1,1,r') w ?sm r' ; t' ?pm(2,1,2,1,t') w ; -t' ; ?pm(2,0,1,-1,t') w"); } -CU_Test(ddsc_listener, subscription_matched, .init=init_triggering_test, .fini=fini_triggering_test) +CU_Test (ddsc_listener, subscription_matched) { - dds_subscription_matched_status_t subscription_matched; - dds_instance_handle_t writer_hdl; - dds_return_t ret; - uint32_t triggered; - uint32_t status; + // regardless of order of creation, the reader should see one writer come & then go + dotest ("sm r pm w ; ?pm w ?sm(1,1,1,1,w) r ; -w ; ?sm(1,0,0,-1,w) r"); + dotest ("pm w sm r ; ?pm w ?sm(1,1,1,1,w) r ; -w ; ?sm(1,0,0,-1,w) r"); - /* Get writer handle that should be part of the status. */ - ret = dds_get_instance_handle(g_writer, &writer_hdl); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + // regardless of order of creation, the reader should see one writer come & then go, also + // when a second writer is introduced + dotest ("sm r pm w ; ?pm w ?sm(1,1,1,1,w) r ; x ?sm(2,1,2,1,x) r ; -w ; ?sm(2,0,1,-1,w) r"); + dotest ("pm w sm r ; ?pm w ?sm(1,1,1,1,w) r ; x ?sm(2,1,2,1,x) r ; -x ; ?sm(2,0,1,-1,x) r"); - /* Subscription matched should be triggered with the right status. */ - triggered = waitfor_cb(DDS_SUBSCRIPTION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_SUBSCRIPTION_MATCHED_STATUS, DDS_SUBSCRIPTION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); - CU_ASSERT_EQUAL_FATAL(cb_subscription_matched_status.current_count, 1); - CU_ASSERT_EQUAL_FATAL(cb_subscription_matched_status.current_count_change, 1); - CU_ASSERT_EQUAL_FATAL(cb_subscription_matched_status.total_count, 1); - CU_ASSERT_EQUAL_FATAL(cb_subscription_matched_status.total_count_change, 1); - CU_ASSERT_EQUAL_FATAL(cb_subscription_matched_status.last_publication_handle, writer_hdl); + // same with 2 domains + dotest ("sm r pm w' ; ?pm w' ?sm(1,1,1,1,w') r ; -w' ; ?sm(1,0,0,-1,w') r"); + dotest ("pm w sm r' ; ?pm w ?sm(1,1,1,1,w) r' ; -w ; ?sm(1,0,0,-1,w) r'"); - /* The listener should have swallowed the status. */ - ret = dds_read_status(g_reader, &status, DDS_SUBSCRIPTION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); - - /* The listener should have reset the count_change. */ - ret = dds_get_subscription_matched_status(g_reader, &subscription_matched); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(subscription_matched.current_count, 1); - CU_ASSERT_EQUAL_FATAL(subscription_matched.current_count_change, 0); - CU_ASSERT_EQUAL_FATAL(subscription_matched.total_count, 1); - CU_ASSERT_EQUAL_FATAL(subscription_matched.total_count_change, 0); - CU_ASSERT_EQUAL_FATAL(subscription_matched.last_publication_handle, writer_hdl); - - /* Reset the trigger flags. */ - ddsrt_mutex_lock(&g_mutex); - cb_called = 0; - ddsrt_mutex_unlock(&g_mutex); - - /* Un-match the subscription by deleting the writer. */ - dds_delete(g_writer); - - /* Subscription matched should be triggered with the right status. */ - triggered = waitfor_cb(DDS_SUBSCRIPTION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_SUBSCRIPTION_MATCHED_STATUS, DDS_SUBSCRIPTION_MATCHED_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); - CU_ASSERT_EQUAL_FATAL(cb_subscription_matched_status.current_count, 0); - CU_ASSERT_EQUAL_FATAL(cb_subscription_matched_status.current_count_change, -1); - CU_ASSERT_EQUAL_FATAL(cb_subscription_matched_status.total_count, 1); - CU_ASSERT_EQUAL_FATAL(cb_subscription_matched_status.total_count_change, 0); - CU_ASSERT_EQUAL_FATAL(cb_subscription_matched_status.last_publication_handle, writer_hdl); - - /* The listener should have reset the count_change. */ - ret = dds_get_subscription_matched_status(g_reader, &subscription_matched); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(subscription_matched.current_count, 0); - CU_ASSERT_EQUAL_FATAL(subscription_matched.current_count_change, 0); - CU_ASSERT_EQUAL_FATAL(subscription_matched.total_count, 1); - CU_ASSERT_EQUAL_FATAL(subscription_matched.total_count_change, 0); - CU_ASSERT_EQUAL_FATAL(subscription_matched.last_publication_handle, writer_hdl); + dotest ("sm r pm w' ; ?pm w' ?sm(1,1,1,1,w') r ; x ?sm(2,1,2,1,x) r ; -w' ; ?sm(2,0,1,-1,w') r"); + dotest ("pm w sm r' ; ?pm w ?sm(1,1,1,1,w) r' ; x ?sm(2,1,2,1,x) r' ; -x ; ?sm(2,0,1,-1,x) r'"); + dotest ("sm r pm w' ; ?pm w' ?sm(1,1,1,1,w') r ; x' ?sm(2,1,2,1,x') r ; -w' ; ?sm(2,0,1,-1,w') r"); + dotest ("pm w sm r' ; ?pm w ?sm(1,1,1,1,w) r' ; x' ?sm(2,1,2,1,x') r' ; -x' ; ?sm(2,0,1,-1,x') r'"); } -CU_Test(ddsc_listener, incompatible_qos, .init=init_triggering_base, .fini=fini_triggering_base) +CU_Test (ddsc_listener, incompatible_qos) { - dds_offered_incompatible_qos_status_t offered_incompatible_qos; - dds_requested_incompatible_qos_status_t requested_incompatible_qos; - dds_return_t ret; - uint32_t triggered; - uint32_t status; - - /* We are interested in incompatible qos notifications. */ - dds_lset_offered_incompatible_qos(g_listener, offered_incompatible_qos_cb); - dds_lset_requested_incompatible_qos(g_listener, requested_incompatible_qos_cb); - - /* Create reader and writer with proper listeners. - * But create reader with persistent durability to get incompatible qos. */ - g_writer = dds_create_writer(g_participant, g_topic, g_qos, g_listener); - CU_ASSERT_FATAL(g_writer > 0); - dds_qset_durability (g_qos, DDS_DURABILITY_PERSISTENT); - g_reader = dds_create_reader(g_participant, g_topic, g_qos, g_listener); - CU_ASSERT_FATAL(g_reader > 0); - - /* Incompatible QoS should be triggered with the right status. */ - triggered = waitfor_cb(DDS_OFFERED_INCOMPATIBLE_QOS_STATUS | DDS_REQUESTED_INCOMPATIBLE_QOS_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_OFFERED_INCOMPATIBLE_QOS_STATUS, DDS_OFFERED_INCOMPATIBLE_QOS_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_REQUESTED_INCOMPATIBLE_QOS_STATUS, DDS_REQUESTED_INCOMPATIBLE_QOS_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); - CU_ASSERT_EQUAL_FATAL(cb_writer, g_writer); - CU_ASSERT_EQUAL_FATAL(cb_offered_incompatible_qos_status.total_count, 1); - CU_ASSERT_EQUAL_FATAL(cb_offered_incompatible_qos_status.total_count_change, 1); - CU_ASSERT_EQUAL_FATAL(cb_offered_incompatible_qos_status.last_policy_id, DDS_DURABILITY_QOS_POLICY_ID); - CU_ASSERT_EQUAL_FATAL(cb_requested_incompatible_qos_status.total_count, 1); - CU_ASSERT_EQUAL_FATAL(cb_requested_incompatible_qos_status.total_count_change, 1); - CU_ASSERT_EQUAL_FATAL(cb_requested_incompatible_qos_status.last_policy_id, DDS_DURABILITY_QOS_POLICY_ID); - - /* The listener should have swallowed the status. */ - ret = dds_read_status(g_writer, &status, DDS_OFFERED_INCOMPATIBLE_QOS_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); - ret = dds_read_status(g_reader, &status, DDS_REQUESTED_INCOMPATIBLE_QOS_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); - - /* The listener should have reset the count_change. */ - ret = dds_get_offered_incompatible_qos_status(g_writer, &offered_incompatible_qos); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - ret = dds_get_requested_incompatible_qos_status(g_reader, &requested_incompatible_qos); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(offered_incompatible_qos.total_count, 1); - CU_ASSERT_EQUAL_FATAL(offered_incompatible_qos.total_count_change, 0); - CU_ASSERT_EQUAL_FATAL(offered_incompatible_qos.last_policy_id, DDS_DURABILITY_QOS_POLICY_ID); - CU_ASSERT_EQUAL_FATAL(requested_incompatible_qos.total_count, 1); - CU_ASSERT_EQUAL_FATAL(requested_incompatible_qos.total_count_change, 0); - CU_ASSERT_EQUAL_FATAL(requested_incompatible_qos.last_policy_id, DDS_DURABILITY_QOS_POLICY_ID); - - dds_delete(g_writer); - dds_delete(g_reader); + // best-effort writer & reliable reader: both must trigger incompatible QoS event + dotest ("oiq w(r=be) riq r ; ?oiq(1,1,r) w ?riq(1,1,r) r"); + dotest ("riq r oiq w(r=be) ; ?oiq(1,1,r) w ?riq(1,1,r) r"); + dotest ("oiq w(o=x) riq r ; ?oiq(1,1,o) w ?riq(1,1,o) r"); + dotest ("riq r oiq w(o=x) ; ?oiq(1,1,o) w ?riq(1,1,o) r"); } -CU_Test(ddsc_listener, data_available, .init=init_triggering_test, .fini=fini_triggering_test) +CU_Test (ddsc_listener, data_available) { - dds_return_t ret; - uint32_t triggered; - uint32_t status; - RoundTripModule_DataType sample; - memset (&sample, 0, sizeof (sample)); + // data available on reader (+ absence of data-on-readers) + dotest ("da sm r pm w ?pm w ?sm r wr w 0 ?da r ?!dor"); + // data available set on subscriber (+ absence of data-on-readers) + dotest ("da R sm r pm w ?pm w ?sm r wr w 0 ?da r ?!dor"); + // data available set on participant (+ absence of data-on-readers) + dotest ("da P sm r pm w ?pm w ?sm r wr w 0 ?da r ?!dor"); - /* We are interested in data available notifications. */ - dds_lset_data_available(g_listener, data_available_cb); - ret = dds_set_listener(g_reader, g_listener); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - - /* Write sample. */ - ret = dds_write(g_writer, &sample); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - - /* Data available should be triggered with the right status. */ - triggered = waitfor_cb(DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_DATA_AVAILABLE_STATUS, DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); - - /* The listener should have swallowed the status. */ - ret = dds_read_status(g_subscriber, &status, DDS_DATA_ON_READERS_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); - ret = dds_read_status(g_reader, &status, DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); - - /* Deleting the writer causes unregisters (or dispose+unregister), and those - should trigger DATA_AVAILABLE as well */ - ddsrt_mutex_lock(&g_mutex); - cb_called = 0; - cb_reader = 0; - ddsrt_mutex_unlock(&g_mutex); - ret = dds_delete (g_writer); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - g_writer = 0; - triggered = waitfor_cb(DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_DATA_AVAILABLE_STATUS, DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); - - /* The listener should have swallowed the status. */ - ret = dds_read_status(g_subscriber, &status, DDS_DATA_ON_READERS_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); - ret = dds_read_status(g_reader, &status, DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); + // non-auto-dispose, transient-local: disconnect => no_writers, reconnect => alive (using invalid samples) + // the invalid sample has the source time stamp of the latest update -- one wonders whether that is wise? + dotest ("da r(d=tl) ?pm w'(d=tl,ad=n) ; wr w' (1,2,3)@1.1 ?da r read{fan(1,2,3)w'} r ;" + " deaf P ; ?da r read{suo(1,2,3)w'@1.1,fuo1w'@1.1} r ;" + " hearing P ; ?da r read{sao(1,2,3)w'@1.1,fao1w'@1.1} r"); } -CU_Test(ddsc_listener, data_available_delete_writer, .init=init_triggering_test, .fini=fini_triggering_test) +CU_Test (ddsc_listener, data_available_delete_writer) { - dds_return_t ret; - uint32_t triggered; - uint32_t status; - RoundTripModule_DataType sample; - memset (&sample, 0, sizeof (sample)); - - /* We are interested in data available notifications. */ - dds_lset_data_available(g_listener, data_available_cb); - ret = dds_set_listener(g_reader, g_listener); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - - /* Write sample, wait for the listener to swallow the status. */ - ret = dds_write(g_writer, &sample); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - triggered = waitfor_cb(DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_DATA_AVAILABLE_STATUS, DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); - - /* Deleting the writer must trigger DATA_AVAILABLE as well */ - ddsrt_mutex_lock(&g_mutex); - cb_called = 0; - cb_reader = 0; - ddsrt_mutex_unlock(&g_mutex); - ret = dds_delete (g_writer); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - g_writer = 0; - triggered = waitfor_cb(DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_DATA_AVAILABLE_STATUS, DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); - - /* The listener should have swallowed the status. */ - ret = dds_read_status(g_subscriber, &status, DDS_DATA_ON_READERS_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); - ret = dds_read_status(g_reader, &status, DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); + // unmatching a writer that didn't read anything has no visible effect on RHC + // subscription-matched event is generated synchronously, so "?sm r" doesn't + // really add anything (it'd be different if there are two domain instances) + dotest ("da sm r w ; -w ?sm r ?!da ; take(0,0) r"); + // after writing: auto-dispose should always trigger data available, an invalid + // sample needs to show up if there isn't an unread sample to use instead + dotest ("da r w ; wr w 0 ?da r ; -w ?da r ; take(1,0) r"); + dotest ("da r w ; wr w 0 ?da r ; read(1,0) r ; -w ?da r ; take(1,1) r"); + dotest ("da r w ; wr w 0 ?da r ; take(1,0) r ; -w ?da r ; take(0,1) r"); + // same with two writers (no point in doing this also with two domains) + dotest ("da r w x ; -w ?!da -x ?!da ; take(0,0) r"); + dotest ("da r w x ; wr w 0 ?da r ; -x ?!da ; -w ?da r ; take(1,0) r"); + dotest ("da r w x ; wr w 0 ?da r ; -w ?da r ; take(1,0) r ; -x ?!da ; take(0,0) r"); + dotest ("da r w x ; wr w 0 wr x 0 ?da r ; -w ?!da ; take(2,0) r ; -x ?da r ; take(0,1) r"); + dotest ("da r w x ; wr w 0 wr x 0 ?da r ; read(2,0) r ; -w ?!da -x ?da r ; take(2,1) r"); + dotest ("da r w x ; wr w 0 wr x 0 ?da r ; read(2,0) r ; -x ?!da -w ?da r ; take(2,1) r"); + dotest ("da r w x ; wr w 0 read(1,0) r ; wr x 0 ?da r ; -w ?!da -x ?da r ; take(2,0) r"); + dotest ("da r w x ; wr w 0 read(1,0) r ; wr x 0 ?da r ; -x ?!da -w ?da r ; take(2,0) r"); + dotest ("da r w x ; wr w 0 read(1,0) r ; wr x 0 ?da r ; read(2,0) r ; -w ?!da -x ?da r ; take(2,1) r"); + dotest ("da r w x ; wr w 0 read(1,0) r ; wr x 0 ?da r ; read(2,0) r ; -x ?!da -w ?da r ; take(2,1) r"); + dotest ("da r w x ; wr w 0 wr x 0 ?da r ; take(2,0) r ; -w ?!da -x ?da r ; take(0,1) r"); + dotest ("da r w x ; wr w 0 wr x 0 ?da r ; take(2,0) r ; -x ?!da -w ?da r ; take(0,1) r"); } -CU_Test(ddsc_listener, data_available_delete_writer_disposed, .init=init_triggering_test, .fini=fini_triggering_test) +CU_Test (ddsc_listener, data_available_delete_writer_disposed) { - dds_return_t ret; - uint32_t triggered; - uint32_t status; - RoundTripModule_DataType sample; - memset (&sample, 0, sizeof (sample)); + // same as data_available_delete_writer, but now with the instance disposed first + dotest ("da r w ; wr w 0 disp w 0 ?da r ; -w ?!da"); + dotest ("da r w ; wr w 0 disp w 0 ?da r ; read(1,0) r ; -w ?!da"); + dotest ("da r w ; wr w 0 disp w 0 ?da r ; take(1,0) r ; -w ?!da"); - /* We are interested in data available notifications. */ - dds_lset_data_available(g_listener, data_available_cb); - ret = dds_set_listener(g_reader, g_listener); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dotest ("da r w x ; wr w 0 ?da r ; read(1,0) r ; disp w 0 ?da r ; read(1,1) r ; -w ?!da -x ?!da"); + dotest ("da r w x ; wr w 0 ?da r ; take(1,0) r ; disp w 0 ?da r ; take(0,1) r ; -w ?!da -x ?!da"); + dotest ("da r w x ; wr w 0 ?da r ; read(1,0) r ; disp w 0 ?da r ; read(1,1) r ; -x ?!da -w ?!da"); + dotest ("da r w x ; wr w 0 ?da r ; take(1,0) r ; disp w 0 ?da r ; take(0,1) r ; -x ?!da -w ?!da"); - /* Write & dispose sample and take it so that the instance is empty & disposed. Then deleting - the writer should silently drop the instance. */ - ret = dds_write(g_writer, &sample); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - ret = dds_dispose(g_writer, &sample); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - triggered = waitfor_cb(DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_DATA_AVAILABLE_STATUS, DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); - - /* Take all data so that the instance becomes empty & disposed */ - do { - void *sampleptr = &sample; - dds_sample_info_t info; - ret = dds_take (g_reader, &sampleptr, &info, 1, 1); - } while (ret > 0); - - /* Deleting the writer should not trigger DATA_AVAILABLE with all instances empty & disposed */ - ddsrt_mutex_lock(&g_mutex); - cb_called = 0; - cb_reader = 0; - ddsrt_mutex_unlock(&g_mutex); - ret = dds_delete (g_writer); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - g_writer = 0; - triggered = waitfor_cb(DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_DATA_AVAILABLE_STATUS, DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); - - /* The listener should have swallowed the status. */ - ret = dds_read_status(g_subscriber, &status, DDS_DATA_ON_READERS_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); - ret = dds_read_status(g_reader, &status, DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); + dotest ("da r w x ; wr w 0 ?da r ; read(1,0) r ; disp x 0 ?da r ; read(1,1) r ; -w ?!da -x ?!da"); + dotest ("da r w x ; wr w 0 ?da r ; take(1,0) r ; disp x 0 ?da r ; take(0,1) r ; -w ?!da -x ?!da"); + dotest ("da r w x ; wr w 0 ?da r ; read(1,0) r ; disp x 0 ?da r ; read(1,1) r ; -x ?!da -w ?!da"); + dotest ("da r w x ; wr w 0 ?da r ; take(1,0) r ; disp x 0 ?da r ; take(0,1) r ; -x ?!da -w ?!da"); } -CU_Test(ddsc_listener, data_on_readers, .init=init_triggering_test, .fini=fini_triggering_test) +CU_Test (ddsc_listener, data_on_readers) { - dds_return_t ret; - uint32_t triggered; - uint32_t status; - RoundTripModule_DataType sample; - memset (&sample, 0, sizeof (sample)); - - /* We are interested in data available notifications. */ - dds_lset_data_on_readers(g_listener, data_on_readers_cb); - ret = dds_set_listener(g_subscriber, g_listener); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - - /* Setting data available notifications should not 'sabotage' the on_readers call. */ - dds_lset_data_available(g_listener, data_available_cb); - ret = dds_set_listener(g_reader, g_listener); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - - /* Write sample. */ - ret = dds_write(g_writer, &sample); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - - /* Data on readers should be triggered with the right status. */ - triggered = waitfor_cb(DDS_DATA_ON_READERS_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_DATA_ON_READERS_STATUS, DDS_DATA_ON_READERS_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_subscriber, g_subscriber); - CU_ASSERT_NOT_EQUAL_FATAL(triggered & DDS_DATA_AVAILABLE_STATUS, DDS_DATA_AVAILABLE_STATUS); - - /* The listener should have swallowed the status. */ - ret = dds_read_status(g_subscriber, &status, DDS_DATA_ON_READERS_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); - ret = dds_read_status(g_reader, &status, DDS_DATA_AVAILABLE_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); + // data on readers wins from data available + dotest ("dor R da r ; wr w 0 ; ?dor R ?!da"); + dotest ("dor P da r ; wr w 0 ; ?dor R ?!da"); } - -CU_Test(ddsc_listener, sample_lost, .init=init_triggering_test, .fini=fini_triggering_test) +CU_Test (ddsc_listener, sample_lost) { - dds_sample_lost_status_t sample_lost; - dds_return_t ret; - uint32_t triggered; - dds_time_t the_past; - uint32_t status; - RoundTripModule_DataType sample; - memset (&sample, 0, sizeof (sample)); - - /* Get a time that should be historic on all platforms.*/ - the_past = dds_time() - 1000000; - - /* We are interested in sample lost notifications. */ - dds_lset_sample_lost(g_listener, sample_lost_cb); - ret = dds_set_listener(g_reader, g_listener); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - - /* Write first sample with current timestamp. */ - ret = dds_write_ts(g_writer, &sample, dds_time()); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - - /* Write second sample with older timestamp. */ - ret = dds_write_ts(g_writer, &sample, the_past); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - - /* Sample lost should be triggered with the right status. */ - triggered = waitfor_cb(DDS_SAMPLE_LOST_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_SAMPLE_LOST_STATUS, DDS_SAMPLE_LOST_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); - CU_ASSERT_EQUAL_FATAL(cb_sample_lost_status.total_count, 1); - CU_ASSERT_EQUAL_FATAL(cb_sample_lost_status.total_count_change, 1); - - /* The listener should have swallowed the status. */ - ret = dds_read_status(g_reader, &status, DDS_SAMPLE_LOST_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); - - /* The listener should have reset the count_change. */ - ret = dds_get_sample_lost_status(g_reader, &sample_lost); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(sample_lost.total_count, 1); - CU_ASSERT_EQUAL_FATAL(sample_lost.total_count_change, 0); + // FIXME: figure out what really constitutes a "lost sample" + dotest ("sl r ; wr w 0@0 ?!sl ; wr w 0@-1 ?sl(1,1) r"); } -CU_Test(ddsc_listener, sample_rejected, .init=init_triggering_test, .fini=fini_triggering_test) +CU_Test (ddsc_listener, sample_rejected) { - dds_sample_rejected_status_t sample_rejected; - dds_return_t ret; - uint32_t triggered; - uint32_t status; - RoundTripModule_DataType sample; - memset (&sample, 0, sizeof (sample)); + // FIXME: rejection counts with retries? + // reliable: expect timeout on the write when max samples has been reached + // invalid samples don't count towards resource limits, so dispose should + // not be blocked + dotest ("sr r(rl=1) ; wr w 0 wrfail w 0 wrfail w 0 ; ?sr r"); + dotest ("sr r(rl=1) ; wr w 0 wrfail w 0 ; read(1,0) r ; disp w 0 ; read(1,1) r ; ?sr r"); - /* We are interested in sample rejected notifications. */ - dds_lset_sample_rejected(g_listener, sample_rejected_cb); - ret = dds_set_listener(g_reader, g_listener); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - - /* Write more than resource limits set by the reader. */ - ret = dds_write(g_writer, &sample); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - ret = dds_write(g_writer, &sample); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - ret = dds_write(g_writer, &sample); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - - /* Sample lost should be triggered with the right status. */ - triggered = waitfor_cb(DDS_SAMPLE_REJECTED_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_SAMPLE_REJECTED_STATUS, DDS_SAMPLE_REJECTED_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); - CU_ASSERT_EQUAL_FATAL(cb_sample_rejected_status.total_count, 2); - CU_ASSERT_EQUAL_FATAL(cb_sample_rejected_status.total_count_change, 1); - CU_ASSERT_EQUAL_FATAL(cb_sample_rejected_status.last_reason, DDS_REJECTED_BY_SAMPLES_LIMIT); - - /* The listener should have swallowed the status. */ - ret = dds_read_status(g_reader, &status, DDS_SAMPLE_REJECTED_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); - - /* The listener should have reset the count_change. */ - ret = dds_get_sample_rejected_status(g_reader, &sample_rejected); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(sample_rejected.total_count, 2); - CU_ASSERT_EQUAL_FATAL(sample_rejected.total_count_change, 0); - CU_ASSERT_EQUAL_FATAL(cb_sample_rejected_status.last_reason, DDS_REJECTED_BY_SAMPLES_LIMIT); + // best-effort: writes should succeed despite not delivering the data adding + // the data in the RHC, also check number of samples rejected + dotest ("sr r(rl=1,r=be) ; wr w(r=be) 0 wr w 0 wr w 0 ; ?sr(2,1,s) r"); + dotest ("sr r(rl=1,r=be) ; wr w(r=be) 0 wr w 0 ; read(1,0) r ; disp w 0 ; read(1,1) r ; ?sr(1,1,s) r"); } -CU_Test(ddsc_listener, liveliness_changed, .init=init_triggering_test, .fini=fini_triggering_base) +CU_Test (ddsc_listener, liveliness_changed) { - dds_liveliness_changed_status_t liveliness_changed; - dds_instance_handle_t writer_hdl; - dds_return_t ret; - uint32_t triggered; - uint32_t status; - - /* The init_triggering_test_byliveliness set our interest in liveliness. */ - - /* Get writer handle that should be part of the status. */ - ret = dds_get_instance_handle(g_writer, &writer_hdl); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - - /* Liveliness changed should be triggered with the right status. */ - triggered = waitfor_cb(DDS_LIVELINESS_CHANGED_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_LIVELINESS_CHANGED_STATUS, DDS_LIVELINESS_CHANGED_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); - CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.alive_count, 1); - CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.alive_count_change, 1); - CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count, 0); - CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count_change, 0); - CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.last_publication_handle, writer_hdl); - - /* The listener should have swallowed the status. */ - ret = dds_read_status(g_reader, &status, DDS_LIVELINESS_CHANGED_STATUS); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(status, 0); - - /* The listener should have reset the count_change. */ - ret = dds_get_liveliness_changed_status(g_reader, &liveliness_changed); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count, 1); - CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, 0); - CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 0); - CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change, 0); - CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_hdl); - - /* Reset the trigger flags. */ - ddsrt_mutex_lock(&g_mutex); - cb_called = 0; - ddsrt_mutex_unlock(&g_mutex); - - /* Change liveliness again by deleting the writer. */ - dds_delete(g_writer); - - /* Liveliness changed should be triggered with the right status. */ - triggered = waitfor_cb(DDS_LIVELINESS_CHANGED_STATUS); - CU_ASSERT_EQUAL_FATAL(triggered & DDS_LIVELINESS_CHANGED_STATUS, DDS_LIVELINESS_CHANGED_STATUS); - CU_ASSERT_EQUAL_FATAL(cb_reader, g_reader); - CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.alive_count, 0); - CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.alive_count_change, -1); - CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count, 0); - CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.not_alive_count_change, 0); - CU_ASSERT_EQUAL_FATAL(cb_liveliness_changed_status.last_publication_handle, writer_hdl); - - /* The listener should have reset the count_change. */ - ret = dds_get_liveliness_changed_status(g_reader, &liveliness_changed); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); - CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count, 0); - CU_ASSERT_EQUAL_FATAL(liveliness_changed.alive_count_change, 0); - CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count, 0); - CU_ASSERT_EQUAL_FATAL(liveliness_changed.not_alive_count_change, 0); - CU_ASSERT_EQUAL_FATAL(liveliness_changed.last_publication_handle, writer_hdl); + // liveliness changed should trigger along with matching + dotest ("pm w lc sm r ; ?pm w ?sm r ; ?lc(1,0,1,0,w) r ; -w ; ?lc(0,0,-1,0,w) r"); + dotest ("pm w lc sm r' ; ?pm w ?sm r' ; ?lc(1,0,1,0,w) r' ; -w ; ?lc(0,0,-1,0,w) r'"); } - -#if 0 -/* This is basically the same as the Lite test, but inconsistent topic is not triggered. - * That is actually what I would expect, because the code doesn't seem to be the way - * to go to test for inconsistent topic. */ -Test(ddsc_listener, inconsistent_topic, .init=init_triggering_base, .fini=fini_triggering_base) -{ - dds_entity_t wr_topic; - dds_entity_t rd_topic; - dds_entity_t writer; - dds_entity_t reader; - uint32_t triggered; - - os_osInit(); - - ddsrt_mutex_init(&g_mutex); - ddsrt_cond_init(&g_cond); - - g_qos = dds_create_qos(); - cr_assert_not_null(g_qos, "Failed to create prerequisite g_qos"); - - g_listener = dds_create_listener(NULL); - cr_assert_not_null(g_listener, "Failed to create prerequisite g_listener"); - - g_participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); - cr_assert_gt(g_participant, 0, "Failed to create prerequisite g_participant"); - - /* We are interested in inconsistent topics. */ - dds_lset_inconsistent_topic(g_listener, inconsistent_topic_cb); - - wr_topic = dds_create_topic(g_participant, &RoundTripModule_DataType_desc, "WRITER_TOPIC", NULL, g_listener); - cr_assert_gt(g_topic, 0, "Failed to create prerequisite wr_topic"); - - rd_topic = dds_create_topic(g_participant, &RoundTripModule_DataType_desc, "READER_TOPIC", NULL, g_listener); - cr_assert_gt(g_topic, 0, "Failed to create prerequisite rd_topic"); - - /* Create reader and writer. */ - writer = dds_create_writer(g_participant, g_topic, NULL, NULL); - cr_assert_gt(writer, 0, "Failed to create prerequisite writer"); - dds_qset_reliability (g_qos, DDS_RELIABILITY_RELIABLE, DDS_SECS (1)); - dds_qset_history (g_qos, DDS_HISTORY_KEEP_ALL, 0); - reader = dds_create_reader(g_subscriber, g_topic, g_qos, NULL); - cr_assert_gt(reader, 0, "Failed to create prerequisite reader"); - - /* Inconsistent topic should be triggered with the right status. */ - triggered = waitfor_cb(DDS_INCONSISTENT_TOPIC_STATUS); - cr_assert_eq(triggered & DDS_INCONSISTENT_TOPIC_STATUS, DDS_INCONSISTENT_TOPIC_STATUS, "DDS_INCONSISTENT_TOPIC_STATUS not triggered"); - - dds_delete(reader); - dds_delete(writer); - dds_delete(rd_topic); - dds_delete(wr_topic); - dds_delete(g_participant); - - dds_delete_listener(g_listener); - dds_delete_qos(g_qos); -} -#endif - diff --git a/src/core/ddsc/tests/loan.c b/src/core/ddsc/tests/loan.c index 5e12d84..2b822c7 100644 --- a/src/core/ddsc/tests/loan.c +++ b/src/core/ddsc/tests/loan.c @@ -110,6 +110,7 @@ CU_Test (ddsc_loan, success, .init = create_entities, .fini = delete_entities) CU_ASSERT_FATAL (result == DDS_RETCODE_OK); /* return resets buf[0] (so that it picks up the loan the next time) and zeros the data */ CU_ASSERT_FATAL (ptrs[0] == NULL); + assert (ptr0copy != NULL); /* clang static analyzer */ CU_ASSERT_FATAL (memcmp (ptr0copy, zeros, sizeof (s)) == 0); /* read 3, return: should work fine, causes realloc */ @@ -121,6 +122,7 @@ CU_Test (ddsc_loan, success, .init = create_entities, .fini = delete_entities) result = dds_return_loan (reader, ptrs, n); CU_ASSERT_FATAL (result == DDS_RETCODE_OK); CU_ASSERT_FATAL (ptrs[0] == NULL); + assert (ptr0copy != NULL); /* clang static analyzer */ CU_ASSERT_FATAL (memcmp (ptr0copy, zeros, 3 * sizeof (s)) == 0); /* read 1 using loan, expecting to get the same address (no realloc needed), defer return. @@ -145,6 +147,7 @@ CU_Test (ddsc_loan, success, .init = create_entities, .fini = delete_entities) { const struct RoundTripModule_DataType *a = ptrs[0]; const struct RoundTripModule_DataType *b = ptrs2[0]; + assert (a != NULL && b != NULL); /* clang static analyzer */ CU_ASSERT_FATAL (a->payload._length == b->payload._length); CU_ASSERT_FATAL (a->payload._buffer != b->payload._buffer); CU_ASSERT_FATAL (a->payload._buffer[0] == b->payload._buffer[0]); @@ -164,6 +167,7 @@ CU_Test (ddsc_loan, success, .init = create_entities, .fini = delete_entities) //This should be a use-after-free //CU_ASSERT_FATAL (memcmp (ptr0copy, zeros, sizeof (s)) == 0); + (void) ptr0copy; } CU_Test (ddsc_loan, take_cleanup, .init = create_entities, .fini = delete_entities) diff --git a/src/core/ddsc/tests/participant.c b/src/core/ddsc/tests/participant.c index 6100f5d..70697a5 100644 --- a/src/core/ddsc/tests/participant.c +++ b/src/core/ddsc/tests/participant.c @@ -111,7 +111,7 @@ CU_Test(ddsc_participant, create_with_conf_no_env) { ddsrt_setenv(DDS_PROJECT_NAME_NOSPACE_CAPS"_URI", CONFIG_ENV_SIMPLE_UDP); ddsrt_setenv("MAX_PARTICIPANTS", CONFIG_ENV_MAX_PARTICIPANTS); - char * env_uri = NULL; + const char * env_uri = NULL; ddsrt_getenv(DDS_PROJECT_NAME_NOSPACE_CAPS"_URI", &env_uri); CU_ASSERT_PTR_NOT_EQUAL_FATAL(env_uri, NULL); diff --git a/src/core/ddsc/tests/qos.c b/src/core/ddsc/tests/qos.c index 88fe4e6..24be7d3 100644 --- a/src/core/ddsc/tests/qos.c +++ b/src/core/ddsc/tests/qos.c @@ -11,6 +11,7 @@ */ #include "CUnit/Test.h" #include "dds/dds.h" +#include /**************************************************************************** * Convenience global policies @@ -146,7 +147,10 @@ static const char* c_userdata = "user_key"; static const char* c_topicdata = "topic_key"; static const char* c_groupdata = "group_key"; static const char* c_partitions[] = {"Partition1", "Partition2"}; - +static const char* c_property_names[] = {"prop1", "prop2", "prop3"}; +static const char* c_property_values[] = {"val1", "val2", "val3"}; +static const char* c_bproperty_names[] = {"bprop1", "bprop2", "bprop3"}; +static const unsigned char c_bproperty_values[3][3] = {{0x0, 0x1, 0x2}, {0x2, 0x3, 0x4}, {0x5, 0x6, 0x7}}; /**************************************************************************** @@ -646,3 +650,191 @@ CU_Test(ddsc_qos, durability_service, .init=qos_init, .fini=qos_fini) CU_ASSERT_EQUAL_FATAL(p.max_samples_per_instance, g_pol_durability_service.max_samples_per_instance); } +CU_Test(ddsc_qos, property, .init=qos_init, .fini=qos_fini) +{ + char * value = NULL; + char ** names = NULL; + uint32_t cnt = 0; + + /* NULLs shouldn't crash and be a noops. */ + CU_ASSERT_FATAL (!dds_qget_prop (g_qos, NULL, NULL)); + CU_ASSERT_FATAL (!dds_qget_prop (g_qos, c_property_names[0], NULL)); + CU_ASSERT_FATAL (!dds_qget_prop (g_qos, NULL, &value)); + CU_ASSERT_FATAL (!dds_qget_prop (NULL, c_property_names[0], &value)); + + dds_qset_prop (g_qos, NULL, NULL); + dds_qset_prop (g_qos, NULL, c_property_values[0]); + dds_qset_prop (NULL, c_property_names[0], c_property_values[0]); + + /* Set null value should not succeed, setting empty string should */ + dds_qset_prop (g_qos, c_property_names[0], NULL); + CU_ASSERT_FATAL (!dds_qget_prop (g_qos, c_property_names[0], &value)); + dds_qset_prop (g_qos, c_property_names[0], ""); + CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[0], &value)); + CU_ASSERT_STRING_EQUAL_FATAL (value, ""); + dds_free (value); + + /* Getting after setting, should yield the original input. */ + dds_qset_prop (g_qos, c_property_names[0], c_property_values[0]); + CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[0], &value)); + CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[0]); + dds_free (value); + + /* Overwrite value for existing property (and reset value) */ + dds_qset_prop (g_qos, c_property_names[0], c_property_values[1]); + CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[0], &value)); + CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[1]); + dds_free (value); + dds_qset_prop (g_qos, c_property_names[0], c_property_values[0]); + + /* Set 2nd prop and get length */ + dds_qset_prop (g_qos, c_property_names[1], c_property_values[1]); + CU_ASSERT_FATAL (dds_qget_propnames (g_qos, &cnt, NULL)); + CU_ASSERT_EQUAL_FATAL (cnt, 2); + + /* Set another property and get list of property names */ + dds_qset_prop (g_qos, c_property_names[2], c_property_values[2]); + CU_ASSERT_FATAL (dds_qget_propnames (g_qos, &cnt, &names)); + CU_ASSERT_EQUAL_FATAL (cnt, 3); + for (uint32_t i = 0; i < cnt; i++) + { + CU_ASSERT_STRING_EQUAL_FATAL (names[i], c_property_names[i]); + dds_free (names[i]); + } + dds_free (names); + + /* Unset a property and check if removed */ + dds_qunset_prop (g_qos, c_property_names[1]); + CU_ASSERT_FATAL (!dds_qget_prop (g_qos, c_property_names[1], &value)); + CU_ASSERT_FATAL (dds_qget_propnames (g_qos, &cnt, NULL)); + CU_ASSERT_EQUAL_FATAL (cnt, 2); + CU_ASSERT_FATAL(dds_qget_prop (g_qos, c_property_names[0], &value)); + CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[0]); + dds_free (value); + CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[2], &value)); + CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[2]); + dds_free (value); + dds_qunset_prop (g_qos, c_property_names[0]); + dds_qunset_prop (g_qos, c_property_names[2]); + CU_ASSERT_FATAL (!dds_qget_propnames (g_qos, &cnt, NULL)); +} + +CU_Test(ddsc_qos, bproperty, .init=qos_init, .fini=qos_fini) +{ + void * bvalue = NULL; + size_t size = 0; + char ** names = NULL; + uint32_t cnt = 0; + + /* NULLs shouldn't crash and be a noops. */ + CU_ASSERT_FATAL (!dds_qget_bprop (g_qos, NULL, NULL, NULL)); + CU_ASSERT_FATAL (!dds_qget_bprop (g_qos, c_bproperty_names[0], NULL, NULL)); + CU_ASSERT_FATAL (!dds_qget_bprop (g_qos, NULL, &bvalue, &size)); + CU_ASSERT_FATAL (!dds_qget_bprop (NULL, c_bproperty_names[0], &bvalue, &size)); + + dds_qset_bprop (g_qos, NULL, NULL, 0); + dds_qset_bprop (g_qos, NULL, &c_bproperty_values[0], 0); + dds_qset_bprop (NULL, c_bproperty_names[0], c_bproperty_values[0], 0); + + /* Set null value should succeed */ + dds_qset_bprop (g_qos, c_bproperty_names[0], NULL, 0); + CU_ASSERT_FATAL (dds_qget_bprop (g_qos, c_bproperty_names[0], &bvalue, &size)); + CU_ASSERT_EQUAL_FATAL (bvalue, NULL); + CU_ASSERT_EQUAL_FATAL (size, 0); + + /* Getting after setting, should yield the original input. */ + dds_qset_bprop (g_qos, c_bproperty_names[0], c_bproperty_values[0], 3); + CU_ASSERT_FATAL(dds_qget_bprop (g_qos, c_bproperty_names[0], &bvalue, &size)); + CU_ASSERT_FATAL (bvalue != NULL); + CU_ASSERT_EQUAL_FATAL (size, 3); + assert (c_bproperty_values[0] != NULL); /* for Clang static analyzer */ + CU_ASSERT_EQUAL_FATAL (memcmp (bvalue, c_bproperty_values[0], size), 0); + dds_free (bvalue); + + /* Overwrite value for existing binary property (and reset value) */ + dds_qset_bprop (g_qos, c_bproperty_names[0], c_bproperty_values[1], 3); + CU_ASSERT_FATAL (dds_qget_bprop (g_qos, c_bproperty_names[0], &bvalue, &size)); + CU_ASSERT_FATAL (bvalue != NULL); + CU_ASSERT_EQUAL_FATAL (size, 3); + assert (c_bproperty_values[1] != NULL); /* for Clang static analyzer */ + CU_ASSERT_EQUAL_FATAL (memcmp (bvalue, c_bproperty_values[1], size), 0); + dds_free (bvalue); + dds_qset_bprop (g_qos, c_bproperty_names[0], &c_bproperty_values[0], 3); + + /* Set 2nd binary prop and get length */ + dds_qset_bprop (g_qos, c_bproperty_names[1], &c_bproperty_values[1], 3); + CU_ASSERT_FATAL (dds_qget_bpropnames (g_qos, &cnt, NULL)); + CU_ASSERT_EQUAL_FATAL (cnt, 2); + + /* Set another binary property and get list of property names */ + dds_qset_bprop (g_qos, c_bproperty_names[2], &c_bproperty_values[2], 3); + CU_ASSERT_FATAL (dds_qget_bpropnames (g_qos, &cnt, &names)); + CU_ASSERT_EQUAL_FATAL (cnt, 3); + for (uint32_t i = 0; i < cnt; i++) + { + CU_ASSERT_STRING_EQUAL_FATAL (names[i], c_bproperty_names[i]); + dds_free (names[i]); + } + dds_free (names); + + /* Unset a binary property and check if removed */ + dds_qunset_bprop (g_qos, c_bproperty_names[1]); + CU_ASSERT_FATAL (!dds_qget_bprop (g_qos, c_bproperty_names[1], &bvalue, &size)); + CU_ASSERT_FATAL (dds_qget_bpropnames (g_qos, &cnt, NULL)); + CU_ASSERT_EQUAL_FATAL (cnt, 2); + CU_ASSERT_FATAL (dds_qget_bprop (g_qos, c_bproperty_names[0], &bvalue, &size)); + CU_ASSERT_FATAL (bvalue != NULL); + CU_ASSERT_EQUAL_FATAL (size, 3); + assert (c_bproperty_values[0] != NULL); /* for Clang static analyzer */ + CU_ASSERT_EQUAL_FATAL (memcmp (bvalue, c_bproperty_values[0], size), 0); + dds_free (bvalue); + CU_ASSERT_FATAL (dds_qget_bprop (g_qos, c_bproperty_names[2], &bvalue, &size)); + CU_ASSERT_FATAL (bvalue != NULL); + CU_ASSERT_EQUAL_FATAL (size, 3); + assert (c_bproperty_values[2] != NULL); /* for Clang static analyzer */ + CU_ASSERT_EQUAL_FATAL (memcmp (bvalue, c_bproperty_values[2], size), 0); + dds_free (bvalue); + dds_qunset_bprop (g_qos, c_bproperty_names[0]); + dds_qunset_bprop (g_qos, c_bproperty_names[2]); + CU_ASSERT_FATAL (!dds_qget_bpropnames (g_qos, &cnt, NULL)); +} + +CU_Test(ddsc_qos, property_mixed, .init=qos_init, .fini=qos_fini) +{ + char * value = NULL; + void * bvalue = NULL; + size_t size = 0; + uint32_t cnt = 0; + + /* Set property and binary property with same name */ + dds_qset_prop (g_qos, c_property_names[0], c_property_values[0]); + dds_qset_bprop (g_qos, c_property_names[0], c_bproperty_values[0], 3); + + /* Check property values and count */ + CU_ASSERT_FATAL (dds_qget_bprop (g_qos, c_property_names[0], &bvalue, &size)); + CU_ASSERT_FATAL (bvalue != NULL); + CU_ASSERT_EQUAL_FATAL (size, 3); + assert (c_bproperty_values[0] != NULL); /* for Clang static analyzer */ + CU_ASSERT_EQUAL_FATAL (memcmp (bvalue, c_bproperty_values[0], size), 0); + dds_free (bvalue); + CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[0], &value)); + CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[0]); + dds_free (value); + + CU_ASSERT_FATAL (dds_qget_propnames (g_qos, &cnt, NULL)); + CU_ASSERT_EQUAL_FATAL (cnt, 1); + CU_ASSERT_FATAL (dds_qget_bpropnames (g_qos, &cnt, NULL)); + CU_ASSERT_EQUAL_FATAL (cnt, 1); + + /* Unset and check */ + dds_qunset_bprop (g_qos, c_property_names[0]); + CU_ASSERT_FATAL (!dds_qget_bprop (g_qos, c_property_names[0], &bvalue, &size)); + CU_ASSERT_FATAL (dds_qget_prop (g_qos, c_property_names[0], &value)); + CU_ASSERT_STRING_EQUAL_FATAL (value, c_property_values[0]); + dds_free (value); + + dds_qunset_prop (g_qos, c_property_names[0]); + CU_ASSERT_FATAL (!dds_qget_prop (g_qos, c_property_names[0], &value)); + CU_ASSERT_FATAL (!dds_qget_propnames (g_qos, &cnt, NULL)); + CU_ASSERT_FATAL (!dds_qget_bpropnames (g_qos, &cnt, NULL)); +} diff --git a/src/core/ddsc/tests/reader_iterator.c b/src/core/ddsc/tests/reader_iterator.c index df1e4c1..945564c 100644 --- a/src/core/ddsc/tests/reader_iterator.c +++ b/src/core/ddsc/tests/reader_iterator.c @@ -55,7 +55,7 @@ #define MAX_SAMPLES 21 #define RDR_NOT_READ_CNT 11 -#define RDR_INV_READ_CNT 1 +#define RDR_INV_READ_CNT 2 int rdr_expected_long_2[RDR_NOT_READ_CNT] = { 0, 1, 2, 6, 7, 9, 11, 13, 14, 16, 19 }; /* Because we only read one sample at a time, only the first sample of an instance diff --git a/src/core/ddsc/tests/test_oneliner.c b/src/core/ddsc/tests/test_oneliner.c new file mode 100644 index 0000000..2b635bd --- /dev/null +++ b/src/core/ddsc/tests/test_oneliner.c @@ -0,0 +1,1842 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include + +#include "dds/dds.h" +#include "dds/ddsrt/misc.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/strtod.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/environ.h" + +#include "dds__types.h" +#include "dds__entity.h" +#include "dds__writer.h" +#include "dds/ddsi/q_bswap.h" +#include "dds/ddsi/q_lease.h" +#include "dds/ddsi/q_xevent.h" +#include "dds/ddsi/ddsi_entity_index.h" + +#include "test_common.h" +#include "test_oneliner.h" + +#define MAXDOMS (sizeof (((struct oneliner_ctx){.result=0}).doms) / sizeof (((struct oneliner_ctx){.result=0}).doms[0])) + +static const char knownentities[] = "PRWrstwxy"; +typedef struct { char n[MAXDOMS + 1]; } entname_t; + +#define DEFINE_STATUS_CALLBACK(name, NAME, kind) \ + static void name##_cb (dds_entity_t kind, const dds_##name##_status_t status, void *arg) \ + { \ + struct oneliner_cb *cb = arg; \ + ddsrt_mutex_lock (&cb->ctx->g_mutex); \ + cb->cb_##kind = kind; \ + cb->cb_##name##_status = status; \ + cb->cb_called[DDS_##NAME##_STATUS_ID]++; \ + ddsrt_cond_broadcast (&cb->ctx->g_cond); \ + ddsrt_mutex_unlock (&cb->ctx->g_mutex); \ + } + +DEFINE_STATUS_CALLBACK (inconsistent_topic, INCONSISTENT_TOPIC, topic) +DEFINE_STATUS_CALLBACK (liveliness_changed, LIVELINESS_CHANGED, reader) +DEFINE_STATUS_CALLBACK (liveliness_lost, LIVELINESS_LOST, writer) +DEFINE_STATUS_CALLBACK (offered_deadline_missed, OFFERED_DEADLINE_MISSED, writer) +DEFINE_STATUS_CALLBACK (offered_incompatible_qos, OFFERED_INCOMPATIBLE_QOS, writer) +DEFINE_STATUS_CALLBACK (publication_matched, PUBLICATION_MATCHED, writer) +DEFINE_STATUS_CALLBACK (requested_deadline_missed, REQUESTED_DEADLINE_MISSED, reader) +DEFINE_STATUS_CALLBACK (requested_incompatible_qos, REQUESTED_INCOMPATIBLE_QOS, reader) +DEFINE_STATUS_CALLBACK (sample_lost, SAMPLE_LOST, reader) +DEFINE_STATUS_CALLBACK (sample_rejected, SAMPLE_REJECTED, reader) +DEFINE_STATUS_CALLBACK (subscription_matched, SUBSCRIPTION_MATCHED, reader) + +static void data_on_readers_cb (dds_entity_t subscriber, void *arg) +{ + struct oneliner_cb *cb = arg; + ddsrt_mutex_lock (&cb->ctx->g_mutex); + cb->cb_subscriber = subscriber; + cb->cb_called[DDS_DATA_ON_READERS_STATUS_ID]++; + ddsrt_cond_broadcast (&cb->ctx->g_cond); + ddsrt_mutex_unlock (&cb->ctx->g_mutex); +} + +static void data_available_cb (dds_entity_t reader, void *arg) +{ + struct oneliner_cb *cb = arg; + ddsrt_mutex_lock (&cb->ctx->g_mutex); + cb->cb_reader = reader; + cb->cb_called[DDS_DATA_AVAILABLE_STATUS_ID]++; + ddsrt_cond_broadcast (&cb->ctx->g_cond); + ddsrt_mutex_unlock (&cb->ctx->g_mutex); +} + +static void dummy_data_on_readers_cb (dds_entity_t subscriber, void *arg) +{ + (void)subscriber; + (void)arg; +} + +static void dummy_data_available_cb (dds_entity_t reader, void *arg) +{ + (void)reader; + (void)arg; +} + +static void dummy_subscription_matched_cb (dds_entity_t reader, const dds_subscription_matched_status_t status, void *arg) +{ + (void)reader; + (void)status; + (void)arg; +} + +static void dummy_liveliness_changed_cb (dds_entity_t reader, const dds_liveliness_changed_status_t status, void *arg) +{ + (void)reader; + (void)status; + (void)arg; +} + +static void dummy_cb (void) +{ + // Used as a listener function in checking merging of listeners, + // and for that purpose, casting it to whatever function type is + // required is ok. It is not supposed to ever be called. + abort (); +} + +#undef DEFINE_STATUS_CALLBACK + +// These had better match the corresponding type definitions! +// n uint32_t ...count +// c int32_t ...count_change +// I instance handle of a data instance +// P uint32_t QoS policy ID +// E instance handle of an entity +// R sample_rejected_status_kind +static const struct { + const char *name; + size_t size; // size of status struct + const char *desc; // description of status struct + dds_status_id_t id; // status id, entry in "cb_called" + size_t cb_entity_off; // which cb_... entity to look at + size_t cb_status_off; // cb_..._status to look at +} lldesc[] = { +#define S0(abbrev, NAME, entity) \ + { abbrev, 0, NULL, DDS_##NAME##_STATUS_ID, offsetof (struct oneliner_cb, cb_##entity), 0 } +#define S(abbrev, name, NAME, desc, entity) \ + { abbrev, sizeof (dds_##name##_status_t), desc, DDS_##NAME##_STATUS_ID, offsetof (struct oneliner_cb, cb_##entity), offsetof (struct oneliner_cb, cb_##name##_status) } + S0 ("da", DATA_AVAILABLE, reader), + S0 ("dor", DATA_ON_READERS, subscriber), + S ("it", inconsistent_topic, INCONSISTENT_TOPIC, "nc", topic), + S ("lc", liveliness_changed, LIVELINESS_CHANGED, "nnccE", reader), + S ("ll", liveliness_lost, LIVELINESS_LOST, "nc", writer), + S ("odm", offered_deadline_missed, OFFERED_DEADLINE_MISSED, "ncI", writer), + S ("oiq", offered_incompatible_qos, OFFERED_INCOMPATIBLE_QOS, "ncP", writer), + S ("pm", publication_matched, PUBLICATION_MATCHED, "ncncE", writer), + S ("rdm", requested_deadline_missed, REQUESTED_DEADLINE_MISSED, "ncI", reader), + S ("riq", requested_incompatible_qos, REQUESTED_INCOMPATIBLE_QOS, "ncP", reader), + S ("sl", sample_lost, SAMPLE_LOST, "nc", reader), + S ("sr", sample_rejected, SAMPLE_REJECTED, "ncRI", reader), + S ("sm", subscription_matched, SUBSCRIPTION_MATCHED, "ncncE", reader) +#undef S +#undef S0 +}; + + +static const void *advance (const void *status, size_t *off, char code) +{ +#define alignof(type_) offsetof (struct { char c; type_ d; }, d) + size_t align = 1, size = 1; + switch (code) + { + case 'n': case 'c': case 'P': + align = alignof (uint32_t); size = sizeof (uint32_t); + break; + case 'E': case 'I': + align = alignof (dds_instance_handle_t); size = sizeof (dds_instance_handle_t); + break; + case 'R': + align = alignof (dds_sample_rejected_status_kind); size = sizeof (dds_sample_rejected_status_kind); + break; + default: + abort (); + } +#undef alignof + *off = (*off + align - 1) & ~(align - 1); + const void *p = (const char *) status + *off; + *off += size; + return p; +} + +static dds_return_t get_status (int ll, dds_entity_t ent, void *status) +{ + dds_return_t ret; + switch (ll) + { + case 2: ret = dds_get_inconsistent_topic_status (ent, status); break; + case 3: ret = dds_get_liveliness_changed_status (ent, status); break; + case 4: ret = dds_get_liveliness_lost_status (ent, status); break; + case 5: ret = dds_get_offered_deadline_missed_status (ent, status); break; + case 6: ret = dds_get_offered_incompatible_qos_status (ent, status); break; + case 7: ret = dds_get_publication_matched_status (ent, status); break; + case 8: ret = dds_get_requested_deadline_missed_status (ent, status); break; + case 9: ret = dds_get_requested_incompatible_qos_status (ent, status); break; + case 10: ret = dds_get_sample_lost_status (ent, status); break; + case 11: ret = dds_get_sample_rejected_status (ent, status); break; + case 12: ret = dds_get_subscription_matched_status (ent, status); break; + default: return -1; + } + return (ret == 0); +} + +static dds_return_t check_status_change_fields_are_0 (int ll, dds_entity_t ent) +{ + if (lldesc[ll].desc) + { + const char *d = lldesc[ll].desc; + void *status = malloc (lldesc[ll].size); + dds_return_t ret; + if ((ret = get_status (ll, ent, status)) <= 0) + { + free (status); + return ret; + } + size_t off = 0; + while (*d) + { + const uint32_t *p = advance (status, &off, *d); + if (*d == 'c' && *p != 0) + { + free (status); + return 0; + } + d++; + } + assert (off <= lldesc[ll].size); + free (status); + } + return 1; +} + +#define TOK_END -1 +#define TOK_NAME -2 +#define TOK_INT -3 +#define TOK_DURATION -4 +#define TOK_TIMESTAMP -5 +#define TOK_ELLIPSIS -6 +#define TOK_INVALID -7 + +static int setresult (struct oneliner_ctx *ctx, int result, const char *msg, ...) ddsrt_attribute_format((printf, 3, 4)); +static void error (struct oneliner_ctx *ctx, const char *msg, ...) ddsrt_attribute_format((printf, 2, 3)); +static void error_dds (struct oneliner_ctx *ctx, dds_return_t ret, const char *msg, ...) ddsrt_attribute_format((printf, 3, 4)); +static void testfail (struct oneliner_ctx *ctx, const char *msg, ...) ddsrt_attribute_format((printf, 2, 3)); + +static void vsetresult (struct oneliner_ctx *ctx, int result, const char *msg, va_list ap) +{ + assert (result <= 0); + ctx->result = result; + vsnprintf (ctx->msg, sizeof (ctx->msg), msg, ap); +} + +static int setresult (struct oneliner_ctx *ctx, int result, const char *msg, ...) +{ + va_list ap; + va_start (ap, msg); + vsetresult (ctx, result, msg, ap); + va_end (ap); + return result; +} + +static void error (struct oneliner_ctx *ctx, const char *msg, ...) +{ + va_list ap; + va_start (ap, msg); + vsetresult (ctx, -1, msg, ap); + va_end (ap); + longjmp (ctx->jb, 1); +} + +static void error_dds (struct oneliner_ctx *ctx, dds_return_t ret, const char *msg, ...) +{ + va_list ap; + va_start (ap, msg); + vsetresult (ctx, -1, msg, ap); + va_end (ap); + size_t n = strlen (ctx->msg); + if (n < sizeof (ctx->msg)) + snprintf (ctx->msg + n, sizeof (ctx->msg) - n, " (%s)", dds_strretcode (ret)); + longjmp (ctx->jb, 1); +} + +static void testfail (struct oneliner_ctx *ctx, const char *msg, ...) +{ + va_list ap; + va_start (ap, msg); + vsetresult (ctx, 0, msg, ap); + va_end (ap); + longjmp (ctx->jb, 1); +} + +static void advancetok (struct oneliner_lex *l) +{ + while (isspace ((unsigned char) *l->inp)) + l->inp++; +} + +static int issymchar0 (char c) +{ + return isalpha ((unsigned char) c) || c == '_'; +} + +static int issymchar (char c) +{ + return isalnum ((unsigned char) c) || c == '_' || c == '\''; +} + +static bool lookingatnum (const struct oneliner_lex *l) +{ + return (isdigit ((unsigned char) l->inp[(l->inp[0] == '-')])); +} + +static int nexttok_dur (struct oneliner_lex *l, union oneliner_tokval *v, bool expecting_duration) +{ + advancetok (l); + if (l->inp[0] == 0) + { + l->tok = TOK_END; + } + else if (strncmp (l->inp, "...", 3) == 0) + { + l->inp += 3; + l->tok = TOK_ELLIPSIS; + } + else if (!expecting_duration && lookingatnum (l)) + { + char *endp; + // strtol: [0-9]+ ; endp = l->inp if no digits present + l->v.i = (int) strtol (l->inp, &endp, 10); + l->inp = endp; + if (v) *v = l->v; + l->tok = TOK_INT; + } + else if (l->inp[0] == '@' || (expecting_duration && lookingatnum (l))) + { + const int ists = (l->inp[0] == '@'); + char *endp; + if (!ists && strncmp (l->inp + ists, "inf", 3) == 0 && !issymchar (l->inp[ists + 3])) + { + l->inp += ists + 3; + l->v.d = DDS_INFINITY; + } + else + { + double d; + if (ddsrt_strtod (l->inp + ists, &endp, &d) != DDS_RETCODE_OK) + return false; + if (!ists && d < 0) + return false; + if (d >= (double) (INT64_MAX / DDS_NSECS_IN_SEC)) + l->v.d = DDS_INFINITY; + else if (d >= 0) + l->v.d = (int64_t) (d * 1e9 + 0.5); + else + l->v.d = -(int64_t) (-d * 1e9 + 0.5); + if (ists) + l->v.d += l->tref; + l->inp = endp; + } + if (v) *v = l->v; + l->tok = ists ? TOK_TIMESTAMP : TOK_DURATION; + } + else if (issymchar0 (l->inp[0])) + { + int p = 0; + while (issymchar (l->inp[p])) + { + if (p == (int) sizeof (l->v.n)) + return TOK_INVALID; + l->v.n[p] = l->inp[p]; + p++; + } + l->v.n[p] = 0; + l->inp += p; + if (v) *v = l->v; + l->tok = TOK_NAME; + } + else + { + l->tok = *l->inp++; + } + return l->tok; +} + +static int nexttok (struct oneliner_lex *l, union oneliner_tokval *v) +{ + return nexttok_dur (l, v, false); +} + +static int peektok (const struct oneliner_lex *l, union oneliner_tokval *v) +{ + struct oneliner_lex l1 = *l; + return nexttok (&l1, v); +} + +static bool nexttok_if (struct oneliner_lex *l, int tok) +{ + if (peektok (l, NULL) != tok) + return false; + nexttok (l, NULL); + return true; +} + +static bool nexttok_int (struct oneliner_lex *l, int *dst) +{ + if (peektok (l, NULL) != TOK_INT) + return false; + (void) nexttok (l, NULL); + *dst = l->v.i; + return true; +} + +struct kvarg { + const char *k; + size_t klen; + int v; + bool (*arg) (struct oneliner_lex *l, void *dst); // *inp unchanged when false + void (*def) (void *dst); +}; + +static void def_kvarg_int0 (void *dst) { *(int *)dst = 0; } +static void def_kvarg_int1 (void *dst) { *(int *)dst = 1; } +static void def_kvarg_dur_inf (void *dst) { *(dds_duration_t *)dst = DDS_INFINITY; } +static void def_kvarg_dur_100ms (void *dst) { *(dds_duration_t *)dst = DDS_MSECS (100); } + +static bool read_kvarg_int (struct oneliner_lex *l, void *dst) +{ + return nexttok_int (l, dst); +} + +static bool read_kvarg_posint (struct oneliner_lex *l, void *dst) +{ + return nexttok_int (l, dst) && l->v.i > 0; +} + +static bool read_kvarg_dur (struct oneliner_lex *l, void *dst) +{ + dds_duration_t *x = dst; + struct oneliner_lex l1 = *l; + if (nexttok_dur (&l1, NULL, true) != TOK_DURATION) + return false; + *x = l1.v.d; + *l = l1; + return true; +} + +static bool read_kvarg_3len (struct oneliner_lex *l, void *dst) +{ + struct oneliner_lex l1 = *l; + int *x = dst, i = 0; + x[0] = x[1] = x[2] = DDS_LENGTH_UNLIMITED; + do { + if (!nexttok_int (&l1, &x[i]) || (x[i] <= 0 && x[i] != DDS_LENGTH_UNLIMITED)) + return false; + } while (++i < 3 && nexttok_if (&l1, '/')); + *l = l1; + return true; +} + +static bool read_kvarg (const struct kvarg *ks, size_t sizeof_ks, struct oneliner_lex *l, int *v, void *arg) +{ + // l points at name, *inp is , or ) terminated; *l unchanged when false + const struct kvarg *kend = ks + sizeof_ks / sizeof (*ks); + struct oneliner_lex l1 = *l; + advancetok (&l1); + for (const struct kvarg *k = ks; k < kend; k++) + { + assert (strlen (k->k) == k->klen); + *v = k->v; + if (k->klen == 0) + { + assert (k->arg != 0 && k->def == 0); + struct oneliner_lex l2 = l1; + if (k->arg (&l2, arg) && (peektok (&l2, NULL) == ',' || peektok (&l2, NULL) == ')')) + { + *l = l2; + return true; + } + } + else if (strncmp (l1.inp, k->k, k->klen) != 0) + { + continue; + } + else + { + /* skip symbol */ + struct oneliner_lex l2 = l1; + l2.inp += k->klen; + if (peektok (&l2, NULL) == ',' || peektok (&l2, NULL) == ')') + { + if (k->arg == 0 || k->def != 0) + { + if (k->def) k->def (arg); + *l = l2; + return true; + } + } + else if (k->arg != 0 && nexttok (&l2, NULL) == ':') + { + if (k->arg (&l2, arg) && (peektok (&l2, NULL) == ',' || peektok (&l2, NULL) == ')')) + { + *l = l2; + return true; + } + } + } + } + return false; +} + +static bool qos_durability (struct oneliner_lex *l, dds_qos_t *q) +{ + static const struct kvarg ks[] = { + { "v", 1, (int) DDS_DURABILITY_VOLATILE }, + { "tl", 2, (int) DDS_DURABILITY_TRANSIENT_LOCAL }, + { "t", 1, (int) DDS_DURABILITY_TRANSIENT }, + { "p", 1, (int) DDS_DURABILITY_PERSISTENT } + }; + int v; + if (!read_kvarg (ks, sizeof ks, l, &v, NULL)) + return false; + dds_qset_durability (q, (dds_durability_kind_t) v); + return true; +} + +static const struct kvarg ks_history[] = { + { "all", 3, (int) DDS_HISTORY_KEEP_ALL, .def = def_kvarg_int1 }, + { "", 0, (int) DDS_HISTORY_KEEP_LAST, .arg = read_kvarg_posint } +}; + +static bool qos_history (struct oneliner_lex *l, dds_qos_t *q) +{ + int v, x = 1; + if (!read_kvarg (ks_history, sizeof ks_history, l, &v, &x)) + return false; + dds_qset_history (q, (dds_history_kind_t) v, x); + return true; +} + +static bool qos_destination_order (struct oneliner_lex *l, dds_qos_t *q) +{ + static const struct kvarg ks[] = { + { "r", 1, (int) DDS_DESTINATIONORDER_BY_RECEPTION_TIMESTAMP }, + { "s", 1, (int) DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP } + }; + int v; + if (!read_kvarg (ks, sizeof ks, l, &v, NULL)) + return false; + dds_qset_destination_order (q, (dds_destination_order_kind_t) v); + return true; +} + +static bool qos_ownership (struct oneliner_lex *l, dds_qos_t *q) +{ + static const struct kvarg ks[] = { + { "s", 1, (int) DDS_OWNERSHIP_SHARED, .def = def_kvarg_int0 }, + { "x", 1, (int) DDS_OWNERSHIP_EXCLUSIVE, .arg = read_kvarg_int, .def = def_kvarg_int0 } + }; + int v, x; + if (!read_kvarg (ks, sizeof ks, l, &v, &x)) + return false; + dds_qset_ownership (q, (dds_ownership_kind_t) v); + dds_qset_ownership_strength (q, x); + return true; +} + +static bool qos_transport_priority (struct oneliner_lex *l, dds_qos_t *q) +{ + static const struct kvarg k = { "", 0, 0, .arg = read_kvarg_int }; + int v, x; + if (!read_kvarg (&k, sizeof k, l, &v, &x)) + return false; + dds_qset_transport_priority (q, x); + return true; +} + +static bool qos_reliability (struct oneliner_lex *l, dds_qos_t *q) +{ + static const struct kvarg ks[] = { + { "be", 2, (int) DDS_RELIABILITY_BEST_EFFORT, .def = def_kvarg_dur_100ms }, + { "r", 1, (int) DDS_RELIABILITY_RELIABLE, .def = def_kvarg_dur_100ms, .arg = read_kvarg_dur } + }; + int v; + dds_duration_t x; + if (!read_kvarg (ks, sizeof ks, l, &v, &x)) + return false; + dds_qset_reliability (q, (dds_reliability_kind_t) v, x); + return true; +} + +static bool qos_liveliness (struct oneliner_lex *l, dds_qos_t *q) +{ + static const struct kvarg ks[] = { + { "a", 1, (int) DDS_LIVELINESS_AUTOMATIC, .def = def_kvarg_dur_inf, .arg = read_kvarg_dur }, + { "p", 1, (int) DDS_LIVELINESS_MANUAL_BY_PARTICIPANT, .arg = read_kvarg_dur }, + { "w", 1, (int) DDS_LIVELINESS_MANUAL_BY_TOPIC, .arg = read_kvarg_dur } + }; + int v; + dds_duration_t x; + if (!read_kvarg (ks, sizeof ks, l, &v, &x)) + return false; + dds_qset_liveliness (q, (dds_liveliness_kind_t) v, x); + return true; +} + +static bool qos_simple_duration (struct oneliner_lex *l, dds_qos_t *q, void (*set) (dds_qos_t * __restrict q, dds_duration_t dur)) +{ + static const struct kvarg k = { "", 0, 0, .arg = read_kvarg_dur }; + int v; + dds_duration_t x; + if (!read_kvarg (&k, sizeof k, l, &v, &x)) + return false; + set (q, x); + return true; +} + +static bool qos_latency_budget (struct oneliner_lex *l, dds_qos_t *q) +{ + return qos_simple_duration (l, q, dds_qset_latency_budget); +} + +static bool qos_deadline (struct oneliner_lex *l, dds_qos_t *q) +{ + return qos_simple_duration (l, q, dds_qset_deadline); +} + +static bool qos_lifespan (struct oneliner_lex *l, dds_qos_t *q) +{ + return qos_simple_duration (l, q, dds_qset_lifespan); +} + +static bool qos_resource_limits (struct oneliner_lex *l, dds_qos_t *q) +{ + int rl[3]; + if (!read_kvarg_3len (l, rl)) + return false; + dds_qset_resource_limits (q, rl[0], rl[1], rl[2]); + return true; +} + +static bool qos_durability_service (struct oneliner_lex *l, dds_qos_t *q) +{ + struct oneliner_lex l1 = *l; + dds_duration_t scd; + int hk = DDS_HISTORY_KEEP_LAST, hd = 1, rl[3]; + if (!read_kvarg_dur (&l1, &scd)) + return false; + if (peektok (&l1, NULL) == '/') + { + (void) nexttok (&l1, NULL); + if (!read_kvarg (ks_history, sizeof ks_history, &l1, &hk, &hd)) + return false; + } + if (peektok (&l1, NULL) != '/') + rl[0] = rl[1] = rl[2] = DDS_LENGTH_UNLIMITED; + else + { + (void) nexttok (&l1, NULL); + if (!read_kvarg_3len (&l1, rl)) + return false; + } + dds_qset_durability_service (q, scd, (dds_history_kind_t) hk, hd, rl[0], rl[1], rl[2]); + *l = l1; + return true; +} + +static bool qos_presentation (struct oneliner_lex *l, dds_qos_t *q) +{ + static const struct kvarg ks[] = { + { "i", 1, (int) DDS_PRESENTATION_INSTANCE, .def = def_kvarg_int0 }, + { "t", 1, (int) DDS_PRESENTATION_TOPIC, .def = def_kvarg_int1 }, + { "g", 1, (int) DDS_PRESENTATION_GROUP, .def = def_kvarg_int1 } + }; + int v, x; + if (!read_kvarg (ks, sizeof ks, l, &v, &x)) + return false; + dds_qset_presentation (q, (dds_presentation_access_scope_kind_t) v, x, 0); + return true; +} + +static bool qos_autodispose_unregistered_instances (struct oneliner_lex *l, dds_qos_t *q) +{ + static const struct kvarg ks[] = { + { "y", 1, 1 }, + { "n", 1, 0 } + }; + int v; + if (!read_kvarg (ks, sizeof ks, l, &v, NULL)) + return false; + dds_qset_writer_data_lifecycle (q, !!v); + return true; +} + +static const struct { + char *abbrev; + size_t n; + bool (*fn) (struct oneliner_lex *l, dds_qos_t *q); + dds_qos_policy_id_t id; +} qostab[] = { + { "ll", 2, qos_liveliness, DDS_LIVELINESS_QOS_POLICY_ID }, + { "d", 1, qos_durability, DDS_DURABILITY_QOS_POLICY_ID }, + { "dl", 2, qos_deadline, DDS_DEADLINE_QOS_POLICY_ID }, + { "h", 1, qos_history, DDS_HISTORY_QOS_POLICY_ID }, + { "lb", 2, qos_latency_budget, DDS_LATENCYBUDGET_QOS_POLICY_ID }, + { "ls", 2, qos_lifespan, DDS_LIFESPAN_QOS_POLICY_ID }, + { "do", 2, qos_destination_order, DDS_DESTINATIONORDER_QOS_POLICY_ID }, + { "o", 1, qos_ownership, DDS_OWNERSHIP_QOS_POLICY_ID }, + { "tp", 2, qos_transport_priority, DDS_OWNERSHIPSTRENGTH_QOS_POLICY_ID }, + { "p", 1, qos_presentation, DDS_PRESENTATION_QOS_POLICY_ID }, + { "r", 1, qos_reliability, DDS_RELIABILITY_QOS_POLICY_ID }, + { "rl", 2, qos_resource_limits, DDS_RESOURCELIMITS_QOS_POLICY_ID }, + { "ds", 2, qos_durability_service, DDS_DURABILITYSERVICE_QOS_POLICY_ID }, + { "ad", 2, qos_autodispose_unregistered_instances, DDS_WRITERDATALIFECYCLE_QOS_POLICY_ID } +}; + +static bool setqos (struct oneliner_lex *l, dds_qos_t *q) +{ + struct oneliner_lex l1 = *l; + dds_reset_qos (q); + // no whitespace between name & QoS + if (*l1.inp != '(') + return true; + nexttok (&l1, NULL); // eat '(' + do { + size_t i; + union oneliner_tokval name; + if (nexttok (&l1, &name) != TOK_NAME || nexttok (&l1, NULL) != '=') + return false; + for (i = 0; i < sizeof (qostab) / sizeof (qostab[0]); i++) + { + assert (strlen (qostab[i].abbrev) == qostab[i].n); + if (strcmp (name.n, qostab[i].abbrev) == 0) + break; + } + if (i == sizeof (qostab) / sizeof (qostab[0])) + return false; + if (!qostab[i].fn (&l1, q)) + return false; + } while (nexttok_if (&l1, ',')); + if (nexttok (&l1, NULL) != ')') + return false; + *l = l1; + return true; +} + +static int parse_entity1 (struct oneliner_lex *l, dds_qos_t *qos) +{ + struct oneliner_lex l1 = *l; + if (nexttok (&l1, NULL) != TOK_NAME) + return -1; + const char *p; + if ((p = strchr (knownentities, l1.v.n[0])) == NULL) + return -1; + int ent = (int) (p - knownentities); + int i; + for (i = 1; l1.v.n[i] == '\''; i++) + ent += (int) sizeof (knownentities) - 1; + if (l1.v.n[i] != 0) + return -1; + if (ent / 9 >= (int) MAXDOMS) + return -1; + if (!setqos (&l1, qos)) + return -1; + *l = l1; + return ent; +} + +static int parse_entity (struct oneliner_ctx *ctx) +{ + return parse_entity1 (&ctx->l, ctx->rwqos); +} + +static int parse_listener1 (struct oneliner_lex *l) +{ + struct oneliner_lex l1 = *l; + size_t i; + if (nexttok (&l1, NULL) != TOK_NAME) + return -1; + for (i = 0; i < sizeof (lldesc) / sizeof (lldesc[0]); i++) + if (strcmp (l1.v.n, lldesc[i].name) == 0) + break; + if (i == sizeof (lldesc) / sizeof (lldesc[0])) + return -1; + *l = l1; + return (int) i; +} + +static int parse_listener (struct oneliner_ctx *ctx) +{ + return parse_listener1 (&ctx->l); +} + +static const char *getentname (entname_t *name, int ent) +{ + DDSRT_STATIC_ASSERT (sizeof (knownentities) == 10); + DDSRT_STATIC_ASSERT (MAXDOMS == 3); + name->n[0] = knownentities[ent % 9]; + const int dom = ent / 9; + int i; + for (i = 1; i <= dom; i++) + name->n[i] = '\''; + name->n[i] = 0; + return name->n; +} + +static void make_participant (struct oneliner_ctx *ctx, int ent, dds_listener_t *list) +{ + const dds_domainid_t domid = (dds_domainid_t) (ent / 9); + char *conf = ddsrt_expand_envvars ("${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}0", domid); + entname_t name; + printf ("create domain %"PRIu32, domid); + fflush (stdout); + if ((ctx->doms[domid] = dds_create_domain (domid, conf)) <= 0) + error_dds (ctx, ctx->doms[domid], "make_participant: create domain %"PRIu32" failed", domid); + ddsrt_free (conf); + printf (" create participant %s", getentname (&name, ent)); + fflush (stdout); + if ((ctx->es[ent] = dds_create_participant (domid, NULL, list)) <= 0) + error_dds (ctx, ctx->es[ent], "make_participant: create participant failed in domain %"PRIu32, domid); + if ((ctx->tps[domid] = dds_create_topic (ctx->es[ent], &Space_Type1_desc, ctx->topicname, ctx->qos, NULL)) <= 0) + error_dds (ctx, ctx->tps[domid], "make_participant: create topic failed in domain %"PRIu32, domid); + + // Create the built-in topic readers with a dummy listener to avoid any event (data available comes to mind) + // from propagating to the normal data available listener, in case it has been set on the participant. + // + // - dummy_cb aborts when it is invoked, but all reader-related listeners that can possibly trigger are set + // separately (incompatible qos, deadline missed, sample lost and sample rejected are all impossible by + // construction) + // - regarding data_on_readers: Cyclone handles listeners installed on an ancestor by *inheriting* them, + // rather than by walking up ancestor chain. Setting data_on_readers on the reader therefore overrides the + // listener set on the subscriber. It is a nice feature! + dds_listener_t *dummylist = dds_create_listener (ctx); + dds_lset_data_available (dummylist, dummy_data_available_cb); + dds_lset_data_on_readers (dummylist, dummy_data_on_readers_cb); + dds_lset_inconsistent_topic (dummylist, (dds_on_inconsistent_topic_fn) dummy_cb); + dds_lset_liveliness_changed (dummylist, dummy_liveliness_changed_cb); + dds_lset_liveliness_lost (dummylist, (dds_on_liveliness_lost_fn) dummy_cb); + dds_lset_offered_deadline_missed (dummylist, (dds_on_offered_deadline_missed_fn) dummy_cb); + dds_lset_offered_incompatible_qos (dummylist, (dds_on_offered_incompatible_qos_fn) dummy_cb); + dds_lset_publication_matched (dummylist, (dds_on_publication_matched_fn) dummy_cb); + dds_lset_requested_deadline_missed (dummylist, (dds_on_requested_deadline_missed_fn) dummy_cb); + dds_lset_requested_incompatible_qos (dummylist, (dds_on_requested_incompatible_qos_fn) dummy_cb); + dds_lset_sample_lost (dummylist, (dds_on_sample_lost_fn) dummy_cb); + dds_lset_sample_rejected (dummylist, (dds_on_sample_rejected_fn) dummy_cb); + dds_lset_subscription_matched (dummylist, dummy_subscription_matched_cb); + if ((ctx->pubrd[domid] = dds_create_reader (ctx->es[ent], DDS_BUILTIN_TOPIC_DCPSPUBLICATION, NULL, dummylist)) <= 0) + error_dds (ctx, ctx->pubrd[domid], "make_participant: create DCPSPublication reader in domain %"PRIu32, domid); + if ((ctx->subrd[domid] = dds_create_reader (ctx->es[ent], DDS_BUILTIN_TOPIC_DCPSSUBSCRIPTION, NULL, dummylist)) <= 0) + error_dds (ctx, ctx->subrd[domid], "make_participant: create DCPSSubscription reader in domain %"PRIu32, domid); + dds_delete_listener (dummylist); + //printf ("pubrd %"PRId32" subrd %"PRId32" sub %"PRId32"\n", es->pubrd[domid], es->subrd[domid], dds_get_parent (es->pubrd[domid])); +} + +static void make_entity1 (struct oneliner_ctx *ctx, int ent, dds_listener_t *list) +{ + entname_t wrname; + dds_return_t ret; + int domid = ent / 9; + int ent1 = ent % 9; + switch (ent1) + { + case 0: + make_participant (ctx, ent, list); + break; + case 1: + if (ctx->es[ent-1] == 0) + { + printf ("["); + make_entity1 (ctx, ent-1, NULL); + printf ("] "); + } + printf ("create subscriber %s", getentname (&wrname, ent)); + fflush (stdout); + ctx->es[ent] = dds_create_subscriber (ctx->es[ent-1], NULL, list); + break; + case 2: + if (ctx->es[ent-2] == 0) + { + printf ("["); + make_entity1 (ctx, ent-2, NULL); + printf ("] "); + } + printf ("create publisher %s", getentname (&wrname, ent)); + fflush (stdout); + ctx->es[ent] = dds_create_publisher (ctx->es[ent-2], NULL, list); + break; + case 3: case 4: case 5: + if (ctx->es[9*domid+1] == 0) + { + printf ("["); + make_entity1 (ctx, 9*domid+1, NULL); + printf ("] "); + } + printf ("create reader %s", getentname (&wrname, ent)); + fflush (stdout); + ctx->es[ent] = dds_create_reader (ctx->es[9*domid+1], ctx->tps[domid], ctx->rwqos, list); + break; + case 6: case 7: case 8: + if (ctx->es[9*domid+2] == 0) + { + printf ("["); + make_entity1 (ctx, 9*domid+2, NULL); + printf ("] "); + } + printf ("create writer %s", getentname (&wrname, ent)); + fflush (stdout); + ctx->es[ent] = dds_create_writer (ctx->es[9*domid+2], ctx->tps[domid], ctx->rwqos, list); + break; + default: + abort (); + } + printf (" = %"PRId32, ctx->es[ent]); + fflush (stdout); + if (ctx->es[ent] <= 0) + error_dds (ctx, ctx->es[ent], "create entity %d failed", ent); + if ((ret = dds_get_instance_handle (ctx->es[ent], &ctx->esi[ent])) != 0) + error_dds (ctx, ret, "get instance handle for entity %"PRId32" failed", ctx->es[ent]); + //printf (" %"PRIx64, es->esi[ent]); + //fflush (stdout); +} + +static void make_entity (struct oneliner_ctx *ctx, int ent, dds_listener_t *list) +{ + make_entity1 (ctx, ent, list); + printf ("\n"); +} + +static void setlistener (struct oneliner_ctx *ctx, struct oneliner_lex *l, int ll, int ent) +{ + printf ("set listener:"); + dds_return_t ret; + int dom = ent / 9; + dds_listener_t *list = ctx->cb[dom].list; + dds_reset_listener (list); + do { + printf (" %s", lldesc[ll].name); + switch (ll) + { + case 0: dds_lset_data_available (list, data_available_cb); break; + case 1: dds_lset_data_on_readers (list, data_on_readers_cb); break; + case 2: dds_lset_inconsistent_topic (list, inconsistent_topic_cb); break; + case 3: dds_lset_liveliness_changed (list, liveliness_changed_cb); break; + case 4: dds_lset_liveliness_lost (list, liveliness_lost_cb); break; + case 5: dds_lset_offered_deadline_missed (list, offered_deadline_missed_cb); break; + case 6: dds_lset_offered_incompatible_qos (list, offered_incompatible_qos_cb); break; + case 7: dds_lset_publication_matched (list, publication_matched_cb); break; + case 8: dds_lset_requested_deadline_missed (list, requested_deadline_missed_cb); break; + case 9: dds_lset_requested_incompatible_qos (list, requested_incompatible_qos_cb); break; + case 10: dds_lset_sample_lost (list, sample_lost_cb); break; + case 11: dds_lset_sample_rejected (list, sample_rejected_cb); break; + case 12: dds_lset_subscription_matched (list, subscription_matched_cb); break; + default: abort (); + } + } while (l && (ll = parse_listener1 (l)) >= 0); + if (ctx->es[ent] == 0) + { + printf (" for "); + make_entity (ctx, ent, list); + } + else + { + dds_listener_t *tmplist = dds_create_listener (&ctx->cb[dom]); + if ((ret = dds_get_listener (ctx->es[ent], tmplist)) != 0) + { + dds_delete_listener (tmplist); + error_dds (ctx, ret, "set listener: dds_get_listener failed on %"PRId32, ctx->es[ent]); + } + dds_merge_listener (list, tmplist); + dds_delete_listener (tmplist); + printf (" on entity %"PRId32"\n", ctx->es[ent]); + if ((ret = dds_set_listener (ctx->es[ent], list)) != 0) + error_dds (ctx, ret, "set listener: dds_set_listener failed on %"PRId32, ctx->es[ent]); + } +} + +static dds_instance_handle_t lookup_insthandle (const struct oneliner_ctx *ctx, int ent, int ent1) +{ + // if both are in the same domain, it's easy + if (ent / 9 == ent1 / 9) + return ctx->esi[ent1]; + else + { + // if they aren't ... find GUID from instance handle in the one domain, + // then find instance handle for GUID in the other + dds_entity_t rd1 = 0, rd2 = 0; + switch (ent1 % 9) + { + case 3: case 4: case 5: rd1 = ctx->subrd[ent1/9]; rd2 = ctx->subrd[ent/9]; break; + case 6: case 7: case 8: rd1 = ctx->pubrd[ent1/9]; rd2 = ctx->pubrd[ent/9]; break; + default: return 0; + } + + dds_builtintopic_endpoint_t keysample; + //printf ("(in %"PRId32" %"PRIx64" -> ", rd1, es->esi[ent1]); + //fflush (stdout); + if (dds_instance_get_key (rd1, ctx->esi[ent1], &keysample) != 0) + return 0; + // In principle, only key fields are set in sample returned by get_key; + // in the case of a built-in topic that is extended to the participant + // key. The qos and topic/type names should not be set, and there is no + // (therefore) memory allocated for the sample. + assert (keysample.qos == NULL); + assert (keysample.topic_name == NULL); + assert (keysample.type_name == NULL); + //for (size_t j = 0; j < sizeof (keysample.key.v); j++) + // printf ("%s%02x", (j > 0 && j % 4 == 0) ? ":" : "", keysample.key.v[j]); + const dds_instance_handle_t ih = dds_lookup_instance (rd2, &keysample); + //printf (" -> %"PRIx64")", ih); + //fflush (stdout); + return ih; + } +} + +static void print_timestamp (struct oneliner_ctx *ctx, dds_time_t ts) +{ + dds_time_t dt = ts - ctx->l.tref; + if ((dt % DDS_NSECS_IN_SEC) == 0) + printf ("@%"PRId64, dt / DDS_NSECS_IN_SEC); + else + { + unsigned frac = (unsigned) (dt % DDS_NSECS_IN_SEC); + int digs = 9; + while ((frac % 10) == 0) + { + digs--; + frac /= 10; + } + printf ("@%"PRId64".%0*u", dt / DDS_NSECS_IN_SEC, digs, frac); + } +} + +static bool parse_sample_value (struct oneliner_ctx *ctx, Space_Type1 *s, bool *valid_data, int def) +{ + s->long_1 = s->long_2 = s->long_3 = def; + if (nexttok (&ctx->l, NULL) == TOK_INT) // key value (invalid sample) + { + if (ctx->l.v.i < 0) + return false; + s->long_1 = ctx->l.v.i; + *valid_data = false; + return true; + } + else if (ctx->l.tok == '(') + { + if (nexttok (&ctx->l, NULL) != TOK_INT || ctx->l.v.i < 0) + return false; + s->long_1 = ctx->l.v.i; + if (nexttok (&ctx->l, NULL) != ',' || nexttok (&ctx->l, NULL) != TOK_INT || ctx->l.v.i < 0) + return false; + s->long_2 = ctx->l.v.i; + if (nexttok (&ctx->l, NULL) != ',' || nexttok (&ctx->l, NULL) != TOK_INT || ctx->l.v.i < 0) + return false; + s->long_3 = ctx->l.v.i; + *valid_data = true; + return nexttok (&ctx->l, NULL) == ')'; + } + else + { + return false; + } +} + +struct doreadlike_sample { + uint32_t state; + bool valid_data; + dds_time_t ts; + int wrent; + dds_instance_handle_t wrih; + Space_Type1 data; +}; + +static bool wrname_from_pubhandle (const struct oneliner_ctx *ctx, int ent, dds_instance_handle_t pubhandle, entname_t *wrname) +{ + dds_builtintopic_endpoint_t inf, inf1; + if (dds_instance_get_key (ctx->pubrd[ent/9], pubhandle, &inf) != 0) + return false; + for (int j = 0; j < (int) (sizeof (ctx->doms) / sizeof (ctx->doms[0])); j++) + { + for (int k = 6; k < 9; k++) + { + if (ctx->esi[9*j+k] != 0) + { + if (dds_instance_get_key (ctx->pubrd[j], ctx->esi[9*j+k], &inf1) != 0) + return false; + if (memcmp (&inf.key, &inf1.key, sizeof (inf.key)) == 0) + { + getentname (wrname, 9*j+k); + return true; + } + } + } + } + return false; +} + +static bool doreadlike_parse_sample (struct oneliner_ctx *ctx, struct doreadlike_sample *s) +{ + static const char *statechars = "fsaudno"; + static const uint32_t statemap[] = { + DDS_NOT_READ_SAMPLE_STATE, DDS_READ_SAMPLE_STATE, + DDS_ALIVE_INSTANCE_STATE, DDS_NOT_ALIVE_NO_WRITERS_INSTANCE_STATE, DDS_NOT_ALIVE_DISPOSED_INSTANCE_STATE, + DDS_NEW_VIEW_STATE, DDS_NOT_NEW_VIEW_STATE + }; + // syntax: [state]k[pubhandle][@ts] or [state](k,l,m)[pubhandle][@ts] + // the first is an invalid sample, the second a valid one, the third says anything goes + // state is a combination of: sample state (F,S fresh/stale), instance state (A,U,D), view state (N,O) + // unspecified: don't care + s->state = 0; + s->ts = -1; + s->wrent = -1; + s->wrih = 0; + struct oneliner_lex l1 = ctx->l; + if (nexttok_if (&ctx->l, TOK_NAME)) + { + char *inp1 = ctx->l.v.n; + char *p; + while (*inp1 && (p = strchr (statechars, *inp1)) != NULL) + { + s->state |= statemap[(int) (p - statechars)]; + inp1++; + } + if (*inp1 == 0) + ; + else if (!isdigit (*inp1)) + return false; + else // rewind input to digit + ctx->l.inp = l1.inp + (inp1 - ctx->l.v.n); + } + // missing states: allow everything + if ((s->state & (statemap[0] | statemap[1])) == 0) + s->state |= statemap[0] | statemap[1]; + if ((s->state & (statemap[2] | statemap[3] | statemap[4])) == 0) + s->state |= statemap[2] | statemap[3] | statemap[4]; + if ((s->state & (statemap[5] | statemap[6])) == 0) + s->state |= statemap[5] | statemap[6]; + if (!parse_sample_value (ctx, &s->data, &s->valid_data, -1)) + return false; + s->wrent = parse_entity1 (&ctx->l, NULL); + if (nexttok_if (&ctx->l, TOK_TIMESTAMP)) + s->ts = ctx->l.v.d; + return true; +} + +static bool doreadlike_ismatch (const dds_sample_info_t *si, const Space_Type1 *s, const struct doreadlike_sample *exp) +{ + return (si->valid_data == exp->valid_data && + (si->sample_state & exp->state) != 0 && + (si->instance_state & exp->state) != 0 && + (si->view_state & exp->state) != 0 && + (exp->data.long_1 < 0 || s->long_1 == exp->data.long_1) && + (!exp->valid_data || exp->data.long_2 < 0 || s->long_2 == exp->data.long_2) && + (!exp->valid_data || exp->data.long_3 < 0 || s->long_3 == exp->data.long_3) && + (exp->ts < 0 || si->source_timestamp == exp->ts) && + (exp->wrent < 0 || si->publication_handle == exp->wrih)); +} + +static bool doreadlike_matchstep (const dds_sample_info_t *si, const Space_Type1 *s, const struct doreadlike_sample *exp, int nexp, bool ellipsis, unsigned *tomatch, int *cursor, dds_instance_handle_t *lastih, int *matchidx) +{ + if (si->instance_handle != *lastih) + { + *lastih = si->instance_handle; + *cursor = -1; + for (int m = 0; m < nexp; m++) + { + if ((*tomatch & (1u << m)) && s->long_1 == exp[m].data.long_1) + { + *cursor = m; + break; + } + } + } + if (*cursor < 0 || *cursor >= nexp) + { + *matchidx = ellipsis ? nexp : -1; + return ellipsis; + } + else if (doreadlike_ismatch (si, s, &exp[*cursor])) + { + *matchidx = *cursor; + *tomatch &= ~(1u << *cursor); + (*cursor)++; + return true; + } + else if (ellipsis) + { + *matchidx = nexp; + return true; + } + else + { + *matchidx = -1; + return false; + } +} + +static void doreadlike (struct oneliner_ctx *ctx, const char *name, dds_return_t (*fn) (dds_entity_t, void **buf, dds_sample_info_t *, size_t, uint32_t)) +{ +#define MAXN 10 + struct doreadlike_sample exp[MAXN]; + int nexp = 0; + bool ellipsis = false; + int exp_nvalid = -1, exp_ninvalid = -1; + int ent; + switch (peektok (&ctx->l, NULL)) + { + default: // no expectations + ellipsis = true; + break; + case '(': // (# valid, # invalid) + nexttok (&ctx->l, NULL); + if (!(nexttok_int (&ctx->l, &exp_nvalid) && nexttok_if (&ctx->l, ',') && nexttok_int (&ctx->l, &exp_ninvalid) && nexttok_if (&ctx->l, ')'))) + error (ctx, "%s: expecting (NINVALID, NVALID)", name); + ellipsis = true; + break; + case '{': + nexttok (&ctx->l, NULL); + if (!nexttok_if (&ctx->l, '}')) + { + do { + if (nexttok_if (&ctx->l, TOK_ELLIPSIS)) { + ellipsis = true; break; + } else if (nexp == MAXN) { + error (ctx, "%s: too many samples specified", name); + } else if (!doreadlike_parse_sample (ctx, &exp[nexp++])) { + error (ctx, "%s: expecting sample", name); + } + } while (nexttok_if (&ctx->l, ',')); + if (!nexttok_if (&ctx->l, '}')) + error (ctx, "%s: expecting '}'", name); + } + break; + } + if ((ent = parse_entity1 (&ctx->l, NULL)) < 0) + error (ctx, "%s: entity required", name); + + for (int i = 0; i < nexp; i++) + { + if (exp[i].wrent >= 0 && (exp[i].wrih = lookup_insthandle (ctx, ent, exp[i].wrent)) == 0) + error (ctx, "%s: instance lookup failed", name); + } + + printf ("entity %"PRId32": %s: ", ctx->es[ent], (fn == dds_take) ? "take" : "read"); + fflush (stdout); + Space_Type1 data[MAXN]; + void *raw[MAXN]; + for (int i = 0; i < MAXN; i++) + raw[i] = &data[i]; + int matchidx[MAXN]; + dds_sample_info_t si[MAXN]; + DDSRT_STATIC_ASSERT (MAXN < CHAR_BIT * sizeof (unsigned)); + const uint32_t maxs = (uint32_t) (sizeof (raw) / sizeof (raw[0])); + const int32_t n = fn (ctx->es[ent], raw, si, maxs, maxs); + if (n < 0) + error_dds (ctx, n, "%s: failed on %"PRId32, name, ctx->es[ent]); + unsigned tomatch = (1u << nexp) - 1; // used to track result entries matched by spec + dds_instance_handle_t lastih = 0; + int cursor = -1; + int count[2] = { 0, 0 }; + bool matchok = true; + printf ("{"); + for (int i = 0; i < n; i++) + { + const Space_Type1 *s = raw[i]; + entname_t wrname; + count[si[i].valid_data]++; + printf ("%s%c%c%c", + (i > 0) ? "," : "", + (si[i].sample_state == DDS_NOT_READ_SAMPLE_STATE) ? 'f' : 's', + (si[i].instance_state == DDS_ALIVE_INSTANCE_STATE) ? 'a' : (si[i].instance_state == DDS_NOT_ALIVE_NO_WRITERS_INSTANCE_STATE) ? 'u' : 'd', + (si[i].view_state == DDS_NEW_VIEW_STATE) ? 'n' : 'o'); + if (si[i].valid_data) + printf ("(%"PRId32",%"PRId32",%"PRId32")", s->long_1, s->long_2, s->long_3); + else + printf ("%"PRId32, s->long_1); + if (!wrname_from_pubhandle (ctx, ent, si[i].publication_handle, &wrname)) + error (ctx, "%s: unknown publication handle received", name); + printf ("%s", wrname.n); + print_timestamp (ctx, si[i].source_timestamp); + if (!doreadlike_matchstep (&si[i], s, exp, nexp, ellipsis, &tomatch, &cursor, &lastih, &matchidx[i])) + matchok = false; + } + printf ("}:"); + for (int i = 0; i < n; i++) + printf (" %d", matchidx[i]); + if (tomatch != 0) + { + printf (" (samples missing)"); + matchok = false; + } + printf (" valid %d %d invalid %d %d", count[1], exp_nvalid, count[0], exp_ninvalid); + if (exp_nvalid >= 0 && (count[1] != exp_nvalid)) + matchok = false; + if (exp_ninvalid >= 0 && (count[0] != exp_ninvalid)) + matchok = false; + printf ("\n"); + fflush (stdout); + if (!matchok) + testfail (ctx, "%s: mismatch between actual and expected set\n", name); +#undef MAXN +} + +static void dotake (struct oneliner_ctx *ctx) { doreadlike (ctx, "take", dds_take); } +static void doread (struct oneliner_ctx *ctx) { doreadlike (ctx, "read", dds_read); } + +static void dowritelike (struct oneliner_ctx *ctx, const char *name, bool fail, dds_return_t (*fn) (dds_entity_t wr, const void *sample, dds_time_t ts)) +{ + dds_return_t ret; + dds_time_t ts = dds_time (); + bool valid_data; + int ent; + Space_Type1 sample; + if ((ent = parse_entity (ctx)) < 0) + error (ctx, "%s: expecting entity", name); + if (ctx->es[ent] == 0) + make_entity (ctx, ent, NULL); + if (!parse_sample_value (ctx, &sample, &valid_data, 0)) + error (ctx, "%s: expecting sample value", name); + if (nexttok_if (&ctx->l, TOK_TIMESTAMP)) + ts = ctx->l.v.d; + printf ("entity %"PRId32": %s (%"PRId32",%"PRId32",%"PRId32")", ctx->es[ent], name, sample.long_1, sample.long_2, sample.long_3); + print_timestamp (ctx, ts); + printf ("\n"); + ret = fn (ctx->es[ent], &sample, ts); + if (!fail) + { + if (ret != 0) + error_dds (ctx, ret, "%s: failed", name); + } + else + { + if (ret == 0) + testfail (ctx, "%s: succeeded unexpectedly", name); + else if (ret != DDS_RETCODE_TIMEOUT) + error_dds (ctx, ret, "%s: failed", name); + } +} + +static void dowr (struct oneliner_ctx *ctx) { dowritelike (ctx, "wr", false, dds_write_ts); } +static void dowrfail (struct oneliner_ctx *ctx) { dowritelike (ctx, "wrfail", true, dds_write_ts); } +static void dowrdisp (struct oneliner_ctx *ctx) { dowritelike (ctx, "wrdisp", false, dds_writedispose_ts); } +static void dowrdispfail (struct oneliner_ctx *ctx) { dowritelike (ctx, "wrdispfail", true, dds_writedispose_ts); } +static void dodisp (struct oneliner_ctx *ctx) { dowritelike (ctx, "disp", false, dds_dispose_ts); } +static void dodispfail (struct oneliner_ctx *ctx) { dowritelike (ctx, "dispfail", true, dds_dispose_ts); } +static void dounreg (struct oneliner_ctx *ctx) { dowritelike (ctx, "unreg", false, dds_unregister_instance_ts); } +static void dounregfail (struct oneliner_ctx *ctx) { dowritelike (ctx, "unregfail", true, dds_unregister_instance_ts); } + +static int checkstatus (struct oneliner_ctx *ctx, int ll, int ent, struct oneliner_lex *argl, const void *status) +{ + assert (lldesc[ll].desc != NULL); + const char *d = lldesc[ll].desc; + int field = 0; + const char *sep = "("; + size_t off = 0; + if (nexttok (argl, NULL) != '(') + abort (); + while (*d) + { + const void *p = advance (status, &off, *d); + int i; + switch (*d) + { + case 'n': + if (!nexttok_int (argl, &i) || i < 0) + return setresult (ctx, -1, "checkstatus: field %d expecting non-negative integer", field); + printf ("%s%"PRIu32" %d", sep, *(uint32_t *)p, i); fflush (stdout); + if (*(uint32_t *)p != (uint32_t)i) + return setresult (ctx, 0, "checkstatus: field %d has actual %"PRIu32" expected %d", field, *(uint32_t *)p, i); + break; + case 'c': + if (!nexttok_int (argl, &i)) + return setresult (ctx, -1, "checkstatus: field %d expecting integer", field); + printf ("%s%"PRId32" %d", sep, *(int32_t *)p, i); fflush (stdout); + if (*(int32_t *)p != i) + return setresult (ctx, 0, "checkstatus: field %d has actual %"PRId32" expected %d", field, *(int32_t *)p, i); + break; + case 'P': + if (nexttok (argl, NULL) != TOK_NAME) + return setresult (ctx, -1, "checkstatus: field %d expecting policy name", field); + size_t polidx; + for (polidx = 0; polidx < sizeof (qostab) / sizeof (qostab[0]); polidx++) + if (strcmp (argl->v.n, qostab[polidx].abbrev) == 0) + break; + if (polidx == sizeof (qostab) / sizeof (qostab[0])) + return setresult (ctx, -1, "checkstatus: field %d expecting policy name", field); + printf ("%s%"PRIu32" %"PRIu32, sep, *(uint32_t *)p, (uint32_t) qostab[polidx].id); fflush (stdout); + if (*(uint32_t *)p != (uint32_t) qostab[polidx].id) + return setresult (ctx, 0, "checkstatus: field %d has actual %"PRIu32" expected %d", field, *(uint32_t *)p, (int) qostab[polidx].id); + break; + case 'R': + if (nexttok (argl, NULL) != TOK_NAME) + return setresult (ctx, -1, "checkstatus: field %d expecting reason", field); + if (strcmp (argl->v.n, "i") == 0) i = (int) DDS_REJECTED_BY_INSTANCES_LIMIT; + else if (strcmp (argl->v.n, "s") == 0) i = (int) DDS_REJECTED_BY_SAMPLES_LIMIT; + else if (strcmp (argl->v.n, "spi") == 0) i = (int) DDS_REJECTED_BY_SAMPLES_PER_INSTANCE_LIMIT; + else return setresult (ctx, -1, "checkstatus: field %d expecting reason", field); + printf ("%s%d %d", sep, (int) *(dds_sample_rejected_status_kind *)p, i); fflush (stdout); + if (*(dds_sample_rejected_status_kind *)p != (dds_sample_rejected_status_kind) i) + return setresult (ctx, 0, "checkstatus: field %d has actual %d expected %d", field, (int) (*(dds_sample_rejected_status_kind *)p), i); + break; + case 'I': // instance handle is too complicated + break; + case 'E': { + int ent1 = -1; + dds_instance_handle_t esi1 = 0; + if (nexttok_if (argl, '*')) + ent1 = -1; + else if ((ent1 = parse_entity1 (argl, NULL)) < 0) + return setresult (ctx, -1, "checkstatus: field %d expecting * or entity name", field); + else if ((esi1 = lookup_insthandle (ctx, ent, ent1)) == 0) + return setresult (ctx, -1, "checkstatus: field %d instance handle lookup failed", field); + printf ("%s%"PRIx64" %"PRIx64, sep, *(dds_instance_handle_t *)p, esi1); fflush (stdout); + if (ent1 >= 0 && *(dds_instance_handle_t *)p != esi1) + return setresult (ctx, 0, "checkstatus: field %d has actual %"PRIx64" expected %"PRIx64, field, *(dds_instance_handle_t *)p, esi1); + break; + } + default: + return DDS_RETCODE_BAD_PARAMETER; + } + sep = ", "; + if (*d != 'I') + field++; + ++d; + if (*d && *d != 'I' && !nexttok_if (argl, ',')) + return setresult (ctx, -1, "checkstatus: field %d expecting ','", field); + } + printf (")"); + if (!nexttok_if (argl, ')')) + return setresult (ctx, -1, "checkstatus: field %d expecting ')'", field); + assert (off <= lldesc[ll].size); + return 1; +} + +static void checklistener (struct oneliner_ctx *ctx, int ll, int ent, struct oneliner_lex *argl) +{ + bool signalled = true; + uint32_t min_cnt = 1, max_cnt = UINT32_MAX; + uint32_t status; + const int dom = ent / 9; + dds_return_t ret; + printf ("listener %s: check called for entity %"PRId32, lldesc[ll].name, ctx->es[ent]); + fflush (stdout); + if (argl && lldesc[ll].cb_status_off == 0) + { + // those that don't have a status can check the number of invocations + int cnt = -1; + if (!(nexttok_if (argl, '(') && nexttok_int (argl, &cnt) && nexttok_if (argl, ')'))) + error (ctx, "listener %s: expecting (COUNT)", lldesc[ll].name); + if (cnt < 0) + error (ctx, "listener %s: invocation count must be at least 0", lldesc[ll].name); + min_cnt = max_cnt = (uint32_t) cnt; + } + ddsrt_mutex_lock (&ctx->g_mutex); + bool cnt_ok = (ctx->cb[dom].cb_called[lldesc[ll].id] >= min_cnt && ctx->cb[dom].cb_called[lldesc[ll].id] <= max_cnt); + while (ctx->cb[dom].cb_called[lldesc[ll].id] < min_cnt && signalled) + { + signalled = ddsrt_cond_waitfor (&ctx->g_cond, &ctx->g_mutex, DDS_SECS (5)); + cnt_ok = (ctx->cb[dom].cb_called[lldesc[ll].id] >= min_cnt && ctx->cb[dom].cb_called[lldesc[ll].id] <= max_cnt); + } + printf (" cb_called %"PRIu32" (%s)", ctx->cb[dom].cb_called[lldesc[ll].id], cnt_ok ? "ok" : "fail"); + fflush (stdout); + if (!cnt_ok) + { + ddsrt_mutex_unlock (&ctx->g_mutex); + testfail (ctx, "listener %s: not invoked [%"PRIu32",%"PRIu32"] times", lldesc[ll].name, min_cnt, max_cnt); + } + dds_entity_t * const cb_entity = (dds_entity_t *) ((char *) &ctx->cb[dom] + lldesc[ll].cb_entity_off); + printf (" cb_entity %"PRId32" %"PRId32" (%s)", *cb_entity, ctx->es[ent], (*cb_entity == ctx->es[ent]) ? "ok" : "fail"); + fflush (stdout); + if (*cb_entity != ctx->es[ent]) + { + ddsrt_mutex_unlock (&ctx->g_mutex); + testfail (ctx, "listener %s: invoked on %"PRId32" instead of %"PRId32, lldesc[ll].name, *cb_entity, ctx->es[ent]); + } + if (!(ctx->doms[0] && ctx->doms[1])) + { + // FIXME: two domains: listener invocation happens on another thread and we can observe non-0 "change" fields + // they get updated, listener gets invoked, then they get reset -- pretty sure it is allowed by the spec, but + // not quite elegant + if ((ret = check_status_change_fields_are_0 (ll, ctx->es[ent])) <= 0) + { + ddsrt_mutex_unlock (&ctx->g_mutex); + if (ret == 0) + testfail (ctx, "listener %s: status contains non-zero change fields", lldesc[ll].name); + else if (ret < 0) + error_dds (ctx, ret, "listener %s: get entity status failed", lldesc[ll].name); + } + } + if (argl && lldesc[ll].cb_status_off != 0) + { + void *cb_status = (char *) &ctx->cb[dom] + lldesc[ll].cb_status_off; + if (checkstatus (ctx, ll, ent, argl, cb_status) <= 0) + { + ddsrt_mutex_unlock (&ctx->g_mutex); + longjmp (ctx->jb, 1); + } + } + printf ("\n"); + ctx->cb[dom].cb_called[lldesc[ll].id] = 0; + ddsrt_mutex_unlock (&ctx->g_mutex); + if ((ret = dds_get_status_changes (ctx->es[ent], &status)) != 0) + error_dds (ctx, ret, "listener %s: dds_get_status_change on %"PRId32, lldesc[ll].name, ctx->es[ent]); + if ((status & (1u << lldesc[ll].id)) != 0) + testfail (ctx, "listener %s: status mask not cleared", lldesc[ll].name); +} + +static void dowaitforack (struct oneliner_ctx *ctx) +{ + dds_return_t ret; + int ent, ent1 = -1; + union { dds_guid_t x; ddsi_guid_t i; } rdguid; + if (*ctx->l.inp == '(') // reader present + { + nexttok (&ctx->l, NULL); + if ((ent1 = parse_entity (ctx)) < 0) + error (ctx, "wait for ack: expecting entity"); + if ((ent1 % 9) < 3 || (ent1 % 9) > 5 || ctx->es[ent1] == 0) + error (ctx, "wait for ack: expecting existing reader as argument"); + if ((ret = dds_get_guid (ctx->es[ent1], &rdguid.x)) != 0) + error_dds (ctx, ret, "wait for ack: failed to get GUID for reader %"PRId32, ctx->es[ent1]); + rdguid.i = nn_ntoh_guid (rdguid.i); + if (!nexttok_if (&ctx->l, ')')) + error (ctx, "wait for ack: expecting ')'"); + } + if ((ent = parse_entity (ctx)) < 0) + error (ctx, "wait for ack: expecting writer"); + if (ent1 >= 0 && ent / 9 == ent1 / 9) + error (ctx, "wait for ack: reader and writer must be in different domains"); + if (ctx->es[ent] == 0) + make_entity (ctx, ent, NULL); + printf ("wait for ack %"PRId32" reader %"PRId32"\n", ctx->es[ent], ent1 < 0 ? 0 : ctx->es[ent1]); + + // without a reader argument a simple dds_wait_for_acks (ctx->es[ent], DDS_SECS (5)) suffices + struct dds_entity *x; + if ((ret = dds_entity_pin (ctx->es[ent], &x)) < 0) + error_dds (ctx, ret, "wait for ack: pin entity failed %"PRId32, ctx->es[ent]); + if (dds_entity_kind (x) != DDS_KIND_WRITER) + error_dds (ctx, ret, "wait for ack: %"PRId32" is not a writer", ctx->es[ent]); + else + ret = dds__writer_wait_for_acks ((struct dds_writer *) x, (ent1 < 0) ? NULL : &rdguid.i, dds_time () + DDS_SECS (5)); + dds_entity_unpin (x); + if (ret != 0) + { + if (ret == DDS_RETCODE_TIMEOUT) + testfail (ctx, "wait for acks timed out on entity %"PRId32, ctx->es[ent]); + else + error_dds (ctx, ret, "wait for acks failed on entity %"PRId32, ctx->es[ent]); + } +} + +static void dowaitfornolistener (struct oneliner_ctx *ctx, int ll) +{ + printf ("listener %s: check not called", lldesc[ll].name); + fflush (stdout); + ddsrt_mutex_lock (&ctx->g_mutex); + bool ret = true; + for (int i = 0; i < (int) (sizeof (ctx->doms) / sizeof (ctx->doms[0])); i++) + { + printf (" %"PRIu32, ctx->cb[i].cb_called[lldesc[ll].id]); + if (ctx->cb[i].cb_called[lldesc[ll].id] != 0) + ret = false; + } + printf (" (%s)\n", ret ? "ok" : "fail"); + ddsrt_mutex_unlock (&ctx->g_mutex); + if (!ret) + testfail (ctx, "callback %s invoked unexpectedly", lldesc[ll].name); +} + +static void dowaitforlistener (struct oneliner_ctx *ctx, int ll) +{ + struct oneliner_lex l1 = ctx->l; + // no whitespace between name and args + const bool have_args = (*ctx->l.inp == '('); + if (have_args) + { + // skip args: we need the entity before we can interpret them + int tok; + while ((tok = nexttok (&ctx->l, NULL)) != EOF && tok != ')') + ; + } + const int ent = parse_entity (ctx); + if (ent < 0) + error (ctx, "check listener: requires an entity"); + if (ctx->es[ent] == 0) + setlistener (ctx, NULL, ll, ent); + checklistener (ctx, ll, ent, have_args ? &l1 : NULL); +} + +static void dowait (struct oneliner_ctx *ctx) +{ + union oneliner_tokval tokval; + if (peektok (&ctx->l, &tokval) == TOK_NAME && strcmp (tokval.n, "ack") == 0) + { + nexttok (&ctx->l, NULL); + dowaitforack (ctx); + } + else + { + const bool expectclear = nexttok_if (&ctx->l, '!'); + const int ll = parse_listener (ctx); + if (ll < 0) + error (ctx, "check listener: requires listener name"); + if (expectclear) + dowaitfornolistener (ctx, ll); + else + dowaitforlistener (ctx, ll); + } +} + +static void dodelete (struct oneliner_ctx *ctx) +{ + dds_return_t ret; + int ent; + if ((ent = parse_entity (ctx)) < 0) + error (ctx, "delete: requires entity"); + if ((ret = dds_delete (ctx->es[ent])) != 0) + error_dds (ctx, ret, "delete: failed on %"PRId32, ctx->es[ent]); + ctx->es[ent] = 0; +} + +static void dodeaf (struct oneliner_ctx *ctx) +{ + dds_return_t ret; + entname_t name; + int ent; + if ((ent = parse_entity (ctx)) < 0 || (ent % 9) != 0) + error (ctx, "deaf: requires participant"); + printf ("deaf: %s\n", getentname (&name, ent)); + if ((ret = dds_domain_set_deafmute (ctx->es[ent], true, false, DDS_INFINITY)) != 0) + error_dds (ctx, ret, "deaf: dds_domain_set_deafmute failed on %"PRId32, ctx->es[ent]); + // speed up the process by forcing lease expiry + dds_entity *x, *xprime; + if ((ret = dds_entity_pin (ctx->es[ent], &x)) < 0) + error_dds (ctx, ret, "deaf: pin participant failed %"PRId32, ctx->es[ent]); + for (int i = 0; i < (int) (sizeof (ctx->doms) / sizeof (ctx->doms[0])); i++) + { + if (i == ent / 9 || ctx->es[9*i] == 0) + continue; + if ((ret = dds_entity_pin (ctx->es[9*i], &xprime)) < 0) + { + dds_entity_unpin (x); + error_dds (ctx, ret, "deaf: pin counterpart participant failed %"PRId32, ctx->es[9*i]); + } + thread_state_awake (lookup_thread_state (), &x->m_domain->gv); + delete_proxy_participant_by_guid (&x->m_domain->gv, &xprime->m_guid, ddsrt_time_wallclock (), true); + thread_state_asleep (lookup_thread_state ()); + dds_entity_unpin (xprime); + } + dds_entity_unpin (x); +} + +static void dohearing (struct oneliner_ctx *ctx) +{ + dds_return_t ret; + entname_t name; + int ent; + if ((ent = parse_entity (ctx)) < 0 || (ent % 9) != 0) + error (ctx, "hearing: requires participant"); + printf ("hearing: %s\n", getentname (&name, ent)); + if ((ret = dds_domain_set_deafmute (ctx->es[ent], false, false, DDS_INFINITY)) != 0) + error_dds (ctx, ret, "hearing: dds_domain_set_deafmute failed %"PRId32, ctx->es[ent]); + // speed up the process by forcing SPDP publication on the remote + for (int i = 0; i < (int) (sizeof (ctx->doms) / sizeof (ctx->doms[0])); i++) + { + if (i == ent / 9 || ctx->es[9*i] == 0) + continue; + dds_entity *xprime; + struct participant *pp; + if ((ret = dds_entity_pin (ctx->es[9*i], &xprime)) < 0) + error_dds (ctx, ret, "hearing: pin counterpart participant failed %"PRId32, ctx->es[9*i]); + thread_state_awake (lookup_thread_state (), &xprime->m_domain->gv); + if ((pp = entidx_lookup_participant_guid (xprime->m_domain->gv.entity_index, &xprime->m_guid)) != NULL) + resched_xevent_if_earlier (pp->spdp_xevent, ddsrt_mtime_add_duration (ddsrt_time_monotonic (), DDS_MSECS (100))); + thread_state_asleep (lookup_thread_state ()); + dds_entity_unpin (xprime); + } +} + +static void dosleep (struct oneliner_ctx *ctx) +{ + if (nexttok_dur (&ctx->l, NULL, true) != TOK_DURATION) + error (ctx, "sleep: invalid duration"); + dds_sleepfor (ctx->l.v.d); +} + +static void dispatchcmd (struct oneliner_ctx *ctx) +{ + static const struct { + const char *name; + void (*fn) (struct oneliner_ctx *ct); + } cs[] = { + { "-", dodelete }, + { "?", dowait }, + { "wr", dowr }, + { "wrdisp", dowrdisp }, + { "disp", dodisp }, + { "unreg", dounreg }, + { "wrfail", dowrfail }, + { "wrdispfail", dowrdispfail }, + { "dispfail", dodispfail }, + { "unregfail", dounregfail }, + { "take", dotake }, + { "read", doread }, + { "deaf", dodeaf }, + { "hearing", dohearing }, + { "sleep", dosleep } + }; + size_t i; + if (ctx->l.tok > 0) + { + // convert single-character token to string + ctx->l.v.n[0] = (char) ctx->l.tok; + ctx->l.v.n[1] = 0; + } + for (i = 0; i < sizeof (cs) / sizeof (cs[0]); i++) + if (strcmp (ctx->l.v.n, cs[i].name) == 0) + break; + if (i == sizeof (cs) / sizeof (cs[0])) + error (ctx, "%s: unknown command", ctx->l.v.n); + cs[i].fn (ctx); +} + +static void dosetlistener (struct oneliner_ctx *ctx, int ll) +{ + int ent; + struct oneliner_lex l1 = ctx->l; + // scan past listener names to get at the entity, which we need + // to get the right listener object (and hence argument) + while (parse_listener1 (&ctx->l) >= 0) + ; + if ((ent = parse_entity (ctx)) < 0) + error (ctx, "set listener: entity required"); + setlistener (ctx, &l1, ll, ent); +} + +static void test_oneliner_step1 (struct oneliner_ctx *ctx) +{ + while (peektok (&ctx->l, NULL) != TOK_END) + { + int ent, ll; + if (nexttok_if (&ctx->l, ';')) + ; // skip ;s + else if ((ent = parse_entity (ctx)) >= 0) + make_entity (ctx, ent, NULL); + else if ((ll = parse_listener (ctx)) >= 0) + dosetlistener (ctx, ll); + else if (nexttok (&ctx->l, NULL) == TOK_NAME || ctx->l.tok > 0) + dispatchcmd (ctx); + else + error (ctx, "unexpected token %d", ctx->l.tok); + } +} + +void test_oneliner_init (struct oneliner_ctx *ctx) +{ + dds_qos_t *qos = dds_create_qos (); + dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_MSECS (100)); + dds_qset_destination_order (qos, DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP); + dds_qset_history (qos, DDS_HISTORY_KEEP_ALL, 0); + + *ctx = (struct oneliner_ctx) { + .l = { .tref = dds_time () }, + .qos = qos, + .rwqos = dds_create_qos (), + .result = 1, + .cb = { + [0] = { .ctx = ctx, .list = dds_create_listener (&ctx->cb[0]) }, + [1] = { .ctx = ctx, .list = dds_create_listener (&ctx->cb[1]) }, + [2] = { .ctx = ctx, .list = dds_create_listener (&ctx->cb[2]) } + } + }; + + ddsrt_mutex_init (&ctx->g_mutex); + ddsrt_cond_init (&ctx->g_cond); + + create_unique_topic_name ("ddsc_listener_test", ctx->topicname, sizeof (ctx->topicname)); +} + +int test_oneliner_step (struct oneliner_ctx *ctx, const char *ops) +{ + if (ctx->result > 0 && setjmp (ctx->jb) == 0) + { + ctx->l.inp = ops; + test_oneliner_step1 (ctx); + } + return ctx->result; +} + +const char *test_oneliner_message (const struct oneliner_ctx *ctx) +{ + return ctx->msg; +} + +int test_oneliner_fini (struct oneliner_ctx *ctx) +{ + for (size_t i = 0; i < sizeof (ctx->cb) / sizeof (ctx->cb[0]); i++) + dds_delete_listener (ctx->cb[i].list); + dds_delete_qos (ctx->rwqos); + dds_delete_qos ((dds_qos_t *) ctx->qos); + // prevent any listeners from being invoked so we can safely delete the + // mutex and the condition variable -- must do this going down the + // hierarchy, or listeners may remain set through inheritance + dds_return_t ret; + for (size_t i = 0; i < sizeof (ctx->es) / sizeof (ctx->es[0]); i++) + if (ctx->es[i] && (ret = dds_set_listener (ctx->es[i], NULL)) != 0) + setresult (ctx, ret, "terminate: reset listener failed on %"PRId32, ctx->es[i]); + if (ctx->result == 0) + { + printf ("\n-- dumping content of readers after failure --\n"); + for (int i = 0; i < (int) (sizeof (ctx->doms) / sizeof (ctx->doms[0])); i++) + { + for (int j = 3; j <= 5; j++) + { + if (ctx->es[9*i + j]) + { + const char *inp_orig = ctx->l.inp; + entname_t n; + ctx->l.inp = getentname (&n, 9*i + j); + doreadlike (ctx, "read", dds_read); + ctx->l.inp = inp_orig; + } + } + } + } + ddsrt_mutex_destroy (&ctx->g_mutex); + ddsrt_cond_destroy (&ctx->g_cond); + for (size_t i = 0; i < sizeof (ctx->doms) / sizeof (ctx->doms[0]); i++) + if (ctx->doms[i] && (ret = dds_delete (ctx->doms[i])) != 0) + setresult (ctx, ret, "terminate: delete domain on %"PRId32, ctx->doms[i]); + return ctx->result; +} + +int test_oneliner (const char *ops) +{ + struct oneliner_ctx ctx; + printf ("dotest: %s\n", ops); + test_oneliner_init (&ctx); + test_oneliner_step (&ctx, ops); + if (test_oneliner_fini (&ctx) <= 0) + fprintf (stderr, "FAIL: %s\n", test_oneliner_message (&ctx)); + return ctx.result; +} diff --git a/src/core/ddsc/tests/test_oneliner.h b/src/core/ddsc/tests/test_oneliner.h new file mode 100644 index 0000000..1a8b75e --- /dev/null +++ b/src/core/ddsc/tests/test_oneliner.h @@ -0,0 +1,326 @@ +/* + * Copyright(c) 2020 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 _TEST_ONELINER_H_ +#define _TEST_ONELINER_H_ + +#include +#include + +#include "dds/dds.h" +#include "dds/ddsrt/sync.h" + +/** @brief run a "test" consisting of a sequence of simplish operations + * + * This operation takes a test description, really a program in a bizarre syntax, and + * executes it. Any failures, be it because of error codes coming out of the Cyclone + * calls or expected values being wrong cause it to fail the test via CU_ASSERT_FATAL. + * While it is doing this, it outputs the test steps to stdout including some actual + * values. An invalid program is mostly reported by calling abort(). It is geared towards + * checking for listener invocations and the effects on statuses. + * + * Entities in play: + * + * - participants: P P' P'' + * - subscribers: R R' R'' + * - publishers: W W' W'' + * - readers: r s t r' s' t' r'' s'' t'' + * - writers: w x y w' x' y' w'' x'' y'' + * + * The unprimed ones exist in domain 0, the primed ones in domain 1 (but configured such + * that it talks to domain 0), and the double-primed ones in domain 2 (again configured such + * that it talks to domain 0) so that network-related listener invocations can be checked + * as well. + * + * The first mention of an entity creates it as well as its ancestors. Implicitly created + * ancestors always have standard QoS and have no listeners. There is one topic that is + * created implicitly when the participant is created. + * + * Standard QoS is: default + reliable (100ms), by-source-timestamp, keep-all. The QoS of + * a reader/writer can be overridden at the first mention of it (i.e., when it is created) + * by appending a list of QoS overrides between parentheses. + * + * A program consists of a sequence of operations separated by whitespace, ';' or '/' + * (there is no meaning to the separators, they exist to allow visual grouping): + * + * PROGRAM ::= (OP (\s+|;)*)* + * + * OP ::= (LISTENER)* ENTITY-NAME[(QOS[,QOS[,QOS...]])] + * + * If entity ENTITY-NAME does not exist: + * creates the entity with the given listeners installed + * QOS can be used to override the standard QoS + * else + * changes the entity's listeners to the specified ones + * (see above for the valid ENTITY-NAMEs) + * + * | -ENTITY-NAME + * + * Deletes the specified entity + * + * | WRITE-LIKE[fail] ENTITY-NAME K[@DT] + * | WRITE-LIKE[fail] ENTITY-NAME (K,X,Y)[@DT] + * + * Writes/disposes/unregisters (K,0,0) (first form) or (K,X,Y). If + * "fail" is appended, the expectation is that it fails with a + * timeout, if @DT is appended, the timestamp is the start time of + * the test +

    s rather than the current time; DT is a + * floating-point number + * + * | READ-LIKE ENTITY-NAME + * | READ-LIKE(A,B) ENTITY-NAME + * | READ-LIKE{[S1[,S2[,S3...]][,...]} ENTITY-NAME + * + * Reads/takes at most 10 samples. The second form counts the + * number of valid and invalid samples seen and checks them against + * A and B. + * + * In the third form, the exact result set is given by the sample + * Si, which is a comma-separated list of samples: + * + * [STATE]K[ENTITY-NAME][@DT] + * [STATE](K,X,Y)[ENTITY-NAME][@DT] + * + * The first form is an invalid sample with only the (integer) key + * value K, the second form also specifies the two (integer) + * attribute fields. + * + * STATE specifies allowed sample (f - not-read (fresh), s - read + * (stale)), instance (a - alive, u - no-writers (unregistered) d - + * disposed) and view states (n - new, o - old). If no sample state + * is specified, all sample states are allowed, &c. + * + * ENTITY-NAME is the name of the publishing writer expected in the + * publication_handle. Not specifying a writer means any writer is + * ok. DT is the timestamp in the same manner as the write-like + * operations. Not specifying a timestamp means any timestamp is + * ok. + * + * If the expected set ends up with "..." there may be other samples + * in the result as well. + * + * | ?LISTENER[(ARGS)] ENTITY-NAME + * + * Waits until the specified listener has been invoked on using a flag set by the listener function, resets the flag + * and verifies that neither the entity status bit nor the "change" + * fields in the various statuses were set. + * + * ARGS is used to check the status argument most recently passed to + * the listener: + * + * da(A) verifies that it has been invoked A times + * dor(A) see da + * it(A,B) verifies count and change match A and B, policy + * matches RELIABILITY + * lc(A,B,C,D,E) verifies that alive and not-alive counts match A + * and B, that alive and not-alive changes match C and D + * and that the last handle matches E if an entity name + * (ignored if E = "*") + * ll (A,B) verifies count and change match A and B + * odm (A,B) verifies count and change match A and B, last handle + * is ignored + * oiq (A,B,C) verifies that total count and change match A and B + * and that the mismatching QoS is C (using the same + * abbreviations as used for defining QoS on entity + * creation) + * pm (A,B,C,D,E) verifies that total count and change match A and + * B, that current count and change match C and D and + * that the last handle matches E if an entity name + * (ignored if E = "*") + * rdm see odm + * riq see oiq + * sl (A,B) verifies that total count and change match A and B + * sr (A,B,C) verifies total count and change match A and B, and + * that the reason matches C (one of "s" for samples, + * "i" for instances, "spi" for samples per instance) + * sm see pm + * + * | ?!LISTENER + * + * (Not listener) tests that LISTENER has not been invoked since + * last reset + * + * | sleep D + * + * Delay program execution for D s (D is a floating-point number) + * + * | deaf ENTITY-NAME + * | hearing ENTITY-NAME + * + * Makes the domain wherein the specified entity exists deaf, + * respectively restoring hearing. The entity must be either P or + * P' and both must exist. Plays some tricks to speed up lease + * expiry and reconnection (like forcibly deleting a proxy + * participant or triggering the publication of SPDP packets). + * + * WRITE-LIKE ::= wr write + * | wrdisp write-dispose + * | disp dispose + * | unreg unregister + * + * READ-LIKE ::= read dds_read (so any state) + * | take dds_take (so any state) + * + * LISTENER ::= da data available (acts on a reader) + * | dor data on readers (acts on a subcsriber) + * | it incompatible topic (acts on a topic) + * | lc liveliness changed (acts on a reader) + * | ll liveliness lost (acts on a writer) + * | odm offered deadline missed (acts on a writer) + * | oiq offered incompatible QoS (acts on a writer) + * | pm publication matched (acts on a writer) + * | rdm requested deadline missed (acts on a reader) + * | riq requested incompatible QoS (acts on a reader) + * | sl sample lost (acts on a reader) + * | sr sample rejected (acts on a reader) + * | sm subscription matched (acts on a reader) + * + * QOS ::= ad={y|n} auto-dispose unregistered instances + * | d={v|tl|t|p} durability + * | dl={inf|DT} deadline (infinite or DT seconds) + * | ds=DT/H/RL durability service: cleanup delay, history, + * resource limits + * | do={r|s} by-reception or by-source destination order + * | h={N|all} history keep-last-N or keep-all + * | lb={inf|DT} latency budget + * | ll={a[:DT]|p:DT|w:DT} liveliness (automatic, manual by + * participant, manual by topic) + * | ls={inf|DT} lifespan + * | o={s|x[:N]} ownership shared or exclusive (strength N) + * | p={i|t|g} presentation: instance, coherent-topic or + * coherent-group + * | r={be|r[:DT]} best-effort or reliable (with max blocking time) + * | rl=N[/N[/N]] resource limits (sample, instances, samples per + * instance; "inf" is allowed, ommitted ones are + * unlimited) + * | tp=N transport-priority + * | ud=... user data (with escape sequences and hex/octal + * input allowed) + * + * All entities share the listeners with their global state. Only the latest invocation is visible. + * + * @param[in] ops Program to execute. + * + * @return > 0 success, 0 failure, < 0 invalid input + */ +int test_oneliner (const char *ops); + +union oneliner_tokval { + int i; + int64_t d; + char n[32]; +}; + +struct oneliner_lex { + const char *inp; + dds_time_t tref; + int tok; + union oneliner_tokval v; +}; + +struct oneliner_ctx; + +struct oneliner_cb { + struct oneliner_ctx *ctx; + dds_listener_t *list; + uint32_t cb_called[DDS_STATUS_ID_MAX + 1]; + dds_entity_t cb_topic, cb_writer, cb_reader, cb_subscriber; + dds_inconsistent_topic_status_t cb_inconsistent_topic_status; + dds_liveliness_changed_status_t cb_liveliness_changed_status; + dds_liveliness_lost_status_t cb_liveliness_lost_status; + dds_offered_deadline_missed_status_t cb_offered_deadline_missed_status; + dds_offered_incompatible_qos_status_t cb_offered_incompatible_qos_status; + dds_publication_matched_status_t cb_publication_matched_status; + dds_requested_deadline_missed_status_t cb_requested_deadline_missed_status; + dds_requested_incompatible_qos_status_t cb_requested_incompatible_qos_status; + dds_sample_lost_status_t cb_sample_lost_status; + dds_sample_rejected_status_t cb_sample_rejected_status; + dds_subscription_matched_status_t cb_subscription_matched_status; +}; + +struct oneliner_ctx { + struct oneliner_lex l; + + dds_entity_t es[3 * 9]; + dds_entity_t tps[3]; + dds_entity_t doms[3]; + dds_instance_handle_t esi[3 * 9]; + // built-in topic readers for cross-referencing instance handles + dds_entity_t pubrd[3]; + dds_entity_t subrd[3]; + // topic name used for data + char topicname[100]; + + const dds_qos_t *qos; + dds_qos_t *rwqos; + + int result; + char msg[256]; + + jmp_buf jb; + + ddsrt_mutex_t g_mutex; + ddsrt_cond_t g_cond; + struct oneliner_cb cb[3]; +}; + +/** @brief Initialize a "oneliner test" context + * + * @param[out] ctx context to initialize + */ +void test_oneliner_init (struct oneliner_ctx *ctx); + +/** @brief Run a sequence of operations in an initialized context + * + * If the context indicates a preceding step has failed, this is a + * no-op and the previous result is propagated to the return value. + * + * @param[in,out] ctx context to operate in + * @param[in] ops sequence of operations to execute (@ref test_oneliner) + * + * @return integer indicating success or failure + * + * @retval 1 success + * @retval 0 test failure + * @retval <0 syntax error unexpected error + */ +int test_oneliner_step (struct oneliner_ctx *ctx, const char *ops); + +/** @brief Get a pointer to the error message from a "oneliner test" + * + * If a preceding step has failed, this returns a pointer to a message + * containing some information about the failure. If no error + * occurred, the message is meaningless. + * + * + * @param[in] ctx context to retrieve message from + * + * @return pointer to null-terminated string aliasing a string in ctx + */ +const char *test_oneliner_message (const struct oneliner_ctx *ctx); + +/** @brief Deinitialize a "oneliner test" context + * + * This releases all resources used by the context. + * + * @param[in,out] ctx context to operate in + * + * @return integer indicating success or failure in any of the + * preceding steps. If no steps were taken, the result is success. + * + * @retval 1 success + * @retval 0 test failure + * @retval <0 syntax error unexpected error + */ +int test_oneliner_fini (struct oneliner_ctx *ctx); + +#endif diff --git a/src/core/ddsc/tests/topic.c b/src/core/ddsc/tests/topic.c index ee90a12..013bf22 100644 --- a/src/core/ddsc/tests/topic.c +++ b/src/core/ddsc/tests/topic.c @@ -170,7 +170,7 @@ CU_Test(ddsc_topic_create, desc_null, .init=ddsc_topic_init, .fini=ddsc_topic_fi CU_TheoryDataPoints(ddsc_topic_create, invalid_names) = { - CU_DataPoints(char *, NULL, "", "mi-dle", "-start", "end-", "1st", "Thus$", "pl+s", "t(4)"), + CU_DataPoints(char *, NULL, "", "mi-dle", "-start", "end-", "1st", "Thus$", "pl+s", "t(4)", "DCPSmytopic"), }; CU_Theory((char *name), ddsc_topic_create, invalid_names, .init=ddsc_topic_init, .fini=ddsc_topic_fini) { diff --git a/src/core/ddsi/CMakeLists.txt b/src/core/ddsi/CMakeLists.txt index 60d91dd..e20181a 100644 --- a/src/core/ddsi/CMakeLists.txt +++ b/src/core/ddsi/CMakeLists.txt @@ -18,11 +18,18 @@ 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 ddsi_serdata.c ddsi_serdata_default.c + ddsi_serdata_pserop.c + ddsi_serdata_plist.c ddsi_sertopic.c ddsi_sertopic_default.c + ddsi_sertopic_pserop.c + ddsi_sertopic_plist.c ddsi_iid.c ddsi_tkmap.c ddsi_vendor.c @@ -81,10 +88,15 @@ 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 ddsi_serdata.h ddsi_sertopic.h ddsi_serdata_default.h + ddsi_serdata_pserop.h + ddsi_serdata_plist.h ddsi_iid.h ddsi_tkmap.h ddsi_vendor.h @@ -92,6 +104,7 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi" ddsi_builtin_topic_if.h ddsi_rhc.h ddsi_guid.h + ddsi_keyhash.h ddsi_entity_index.h ddsi_deadline.h ddsi_deliver_locally.h @@ -142,6 +155,19 @@ endif() target_sources(ddsc PRIVATE ${srcs_ddsi} ${hdrs_private_ddsi}) +if(ENABLE_SECURITY) + PREPEND(security_srcs "${CMAKE_CURRENT_LIST_DIR}/src" + ddsi_security_msg.c + ddsi_security_exchange.c) + + PREPEND(security_hdrs "${CMAKE_CURRENT_LIST_DIR}/include/dds/ddsi" + ddsi_security_msg.h + ddsi_security_exchange.h) + + target_sources(ddsc + PRIVATE ${security_srcs} ${security_hdrs}) +endif() + target_include_directories(ddsc PRIVATE "${CMAKE_CURRENT_LIST_DIR}/include") diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_domaingv.h b/src/core/ddsi/include/dds/ddsi/ddsi_domaingv.h index 4c96ef1..8446aaf 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_domaingv.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_domaingv.h @@ -46,6 +46,9 @@ struct ddsi_tran_factory; 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; @@ -258,6 +261,12 @@ struct ddsi_domaingv { dds_qos_t spdp_endpoint_xqos; dds_qos_t builtin_endpoint_xqos_rd; dds_qos_t builtin_endpoint_xqos_wr; +#ifdef DDSI_INCLUDE_SECURITY + dds_qos_t builtin_volatile_xqos_rd; + dds_qos_t builtin_volatile_xqos_wr; + dds_qos_t builtin_stateless_xqos_rd; + dds_qos_t builtin_stateless_xqos_wr; +#endif /* SPDP packets get very special treatment (they're the only packets we accept from writers we don't know) and have their very own @@ -285,8 +294,18 @@ struct ddsi_domaingv { transmit queue*/ struct serdatapool *serpool; struct nn_xmsgpool *xmsgpool; - struct ddsi_sertopic *plist_topic; /* used for all discovery data */ - struct ddsi_sertopic *rawcdr_topic; /* used for participant message data */ + struct ddsi_sertopic *spdp_topic; /* key = participant GUID */ + struct ddsi_sertopic *sedp_reader_topic; /* key = endpoint GUID */ + struct ddsi_sertopic *sedp_writer_topic; /* key = endpoint GUID */ + struct ddsi_sertopic *pmd_topic; /* participant message data */ +#ifdef DDSI_INCLUDE_SECURITY + struct ddsi_sertopic *spdp_secure_topic; /* key = participant GUID */ + struct ddsi_sertopic *sedp_reader_secure_topic; /* key = endpoint GUID */ + struct ddsi_sertopic *sedp_writer_secure_topic; /* key = endpoint GUID */ + struct ddsi_sertopic *pmd_secure_topic; /* participant message data */ + struct ddsi_sertopic *pgm_stateless_topic; /* participant generic message */ + struct ddsi_sertopic *pgm_volatile_topic; /* participant generic message */ +#endif ddsrt_mutex_t sendq_lock; ddsrt_cond_t sendq_cond; @@ -306,6 +325,14 @@ struct ddsi_domaingv { ddsrt_mutex_t sertopics_lock; struct ddsrt_hh *sertopics; + + /* security globals */ +#ifdef DDSI_INCLUDE_SECURITY + struct dds_security_context *security_context; + struct ddsi_hsadmin *hsadmin; + bool handshake_include_optional; +#endif + }; #if defined (__cplusplus) diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_entity_index.h b/src/core/ddsi/include/dds/ddsi/ddsi_entity_index.h index 54b6d59..bedf8e8 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_entity_index.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_entity_index.h @@ -112,6 +112,7 @@ struct entidx_enum_proxy_reader { struct entidx_enum st; }; void entidx_enum_init (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind) ddsrt_nonnull_all; void entidx_enum_init_topic (struct entidx_enum *st, const struct entity_index *gh, enum entity_kind kind, const char *topic, struct match_entities_range_key *max) ddsrt_nonnull_all; +void entidx_enum_init_topic_w_prefix (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind, const char *topic, const ddsi_guid_prefix_t *prefix, struct match_entities_range_key *max) ddsrt_nonnull_all; void *entidx_enum_next_max (struct entidx_enum *st, const struct match_entities_range_key *max) ddsrt_nonnull_all; void *entidx_enum_next (struct entidx_enum *st) ddsrt_nonnull_all; void entidx_enum_fini (struct entidx_enum *st) ddsrt_nonnull_all; diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_handshake.h b/src/core/ddsi/include/dds/ddsi/ddsi_handshake.h new file mode 100644 index 0000000..a76f009 --- /dev/null +++ b/src/core/ddsi/include/dds/ddsi/ddsi_handshake.h @@ -0,0 +1,226 @@ +/* + * 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_HANDSHAKE_H +#define DDSI_HANDSHAKE_H + +#include "dds/ddsi/q_entity.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +struct participant; +struct proxy_participant; +struct ddsi_handshake; +struct dssi_hsadmin; + +enum ddsi_handshake_state { + STATE_HANDSHAKE_IN_PROGRESS, + STATE_HANDSHAKE_TIMED_OUT, + STATE_HANDSHAKE_FAILED, + STATE_HANDSHAKE_PROCESSED, + STATE_HANDSHAKE_SEND_TOKENS, + STATE_HANDSHAKE_OK +}; + +/* 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_handshake *handshake, + struct participant *pp, + struct proxy_participant *proxypp, + enum ddsi_handshake_state result); + +#ifdef DDSI_INCLUDE_SECURITY + +#include "dds/ddsi/ddsi_security_msg.h" + +/** + * @brief Release the handshake. + * + * This function will decrement the refcount associated with the handshake + * and delete the handshake when the refcount becomes 0. + * + * @param[in] handshake The handshake. + */ +void ddsi_handshake_release(struct ddsi_handshake *handshake); + +/** + * @brief Handle an authentication handshake message received from the remote participant. + * + * During the authentication phase handshake messages are being exchanged between the local and + * the remote participant. THis function will handle a handshake message received from a remote + * participant. + * + * @param[in] handshake The handshake. + * @param[in] pp The local participant. + * @param[in] proxypp The remote participant. + * @param[in] msg The handshake message received. + */ +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); + +/** + * @brief Notify the handshake that crypto tokens have been received. + * + * The handshake could be finished at one end while the other side has not yet processed the + * final handshake messages. The arrival of crypto tokens signals that the other side has also finished + * processing the handshake. This function is used to signal the handshake that crypto tokens have been + * received. + * + * @param[in] handshake The handshake. + */ +void ddsi_handshake_crypto_tokens_received(struct ddsi_handshake *handshake); + +/** + * @brief Get the shared secret handle. + * + * During the handshake a shared secret is established which is used to encrypt + * and decrypt the crypto token exchange messages. This function will return a + * handle to the shared secret which will be passed to the crypto plugin to + * determine the session keys used for the echange of the the crypto tokens. + * + * @param[in] handshake The handshake. + * + * @returns handle to the shared sercet. + */ +int64_t ddsi_handshake_get_shared_secret(const struct ddsi_handshake *handshake); + +/** + * @brief Get the handshake handle + * + * This function returns the handshake handle that was returned by the authentication plugin + * when starting the handshake. + * + * @param[in] handshake The handshake. + * + * @returns The handshake handle. + */ +int64_t ddsi_handshake_get_handle(const struct ddsi_handshake *handshake); + +/** + * @brief Create and start the handshake for the participants + * + * This function will create a handshake for the specified local + * and remote participants when it does not yet exists. It will start the + * handshake procedure by calling the corresponding functions of the authentication plugin. + * The callback function is called by the handshake when to report events, + * for example to indicate that the handshake has finished or has failed. + * + * @param[in] pp The local participant. + * @param[in] proxypp The remote participant. + * @param[in] callback The callback function. + * + */ +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. + * + * This function will remove the handshake from the handshake administation and release + * the handshake. When the handshake argument is not specified the handshake is searched + * in the handshake administation. + * + * @param[in] pp The local participant. + * @param[in] proxypp The remote participant. + * + */ +void ddsi_handshake_remove(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 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 Stop handshake background processing. +* +* @param[in] gv The global parameters +*/ +void ddsi_handshake_admin_stop(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)) +{ +} + +inline void ddsi_handshake_crypto_tokens_received(UNUSED_ARG(struct ddsi_handshake *handshake)) +{ +} + +inline int64_t ddsi_handshake_get_shared_secret(UNUSED_ARG(const struct ddsi_handshake *handshake)) +{ + return 0; +} + +inline int64_t ddsi_handshake_get_handle(UNUSED_ARG(const struct ddsi_handshake *handshake)) +{ + return 0; +} + +inline void ddsi_handshake_remove(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp), UNUSED_ARG(struct ddsi_handshake *handshake)) +{ +} + +inline struct ddsi_handshake * ddsi_handshake_find(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp)) +{ + return NULL; +} + +#endif /* DDSI_INCLUDE_SECURITY */ + +#if defined (__cplusplus) +} +#endif + +#endif /* DDSI_HANDSHAKE_H */ diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_keyhash.h b/src/core/ddsi/include/dds/ddsi/ddsi_keyhash.h new file mode 100644 index 0000000..bbb60a1 --- /dev/null +++ b/src/core/ddsi/include/dds/ddsi/ddsi_keyhash.h @@ -0,0 +1,27 @@ +/* + * Copyright(c) 2020 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_KEYHASH_H +#define DDSI_KEYHASH_H + +#if defined (__cplusplus) +extern "C" { +#endif + +typedef struct ddsi_keyhash { + unsigned char value[16]; +} ddsi_keyhash_t; + +#if defined (__cplusplus) +} +#endif + +#endif diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_plist.h b/src/core/ddsi/include/dds/ddsi/ddsi_plist.h index f027865..3f8c283 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_plist.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_plist.h @@ -14,6 +14,7 @@ #include "dds/ddsi/q_feature_check.h" #include "dds/ddsi/ddsi_xqos.h" +#include "dds/ddsi/ddsi_keyhash.h" #include "dds/ddsi/ddsi_tran.h" /* FIXME: eliminate */ #if defined (__cplusplus) @@ -51,11 +52,15 @@ extern "C" { #ifdef DDSI_INCLUDE_SSM #define PP_READER_FAVOURS_SSM ((uint64_t)1 << 29) #endif +#define PP_DOMAIN_ID ((uint64_t)1 << 30) +#define PP_DOMAIN_TAG ((uint64_t)1 << 31) /* Security extensions. */ -#define PP_IDENTITY_TOKEN ((uint64_t)1 << 30) -#define PP_PERMISSIONS_TOKEN ((uint64_t)1 << 31) -#define PP_DOMAIN_ID ((uint64_t)1 << 32) -#define PP_DOMAIN_TAG ((uint64_t)1 << 33) +#define PP_IDENTITY_TOKEN ((uint64_t)1 << 32) +#define PP_PERMISSIONS_TOKEN ((uint64_t)1 << 33) +#define PP_ENDPOINT_SECURITY_INFO ((uint64_t)1 << 34) +#define PP_PARTICIPANT_SECURITY_INFO ((uint64_t)1 << 35) +#define PP_IDENTITY_STATUS_TOKEN ((uint64_t)1 << 36) +#define PP_DATA_TAGS ((uint64_t)1 << 37) /* Set for unrecognized parameters that are in the reserved space or in our own vendor-specific space that have the PID_UNRECOGNIZED_INCOMPATIBLE_FLAG set (see DDSI 2.1 9.6.2.2.1) */ @@ -93,10 +98,21 @@ typedef uint32_t nn_ipv4address_t; typedef uint32_t nn_port_t; -typedef struct nn_keyhash { - unsigned char value[16]; -} nn_keyhash_t; +#ifdef DDSI_INCLUDE_SECURITY +typedef struct nn_tag { + char *name; + char *value; +} nn_tag_t; +typedef struct nn_tagseq { + uint32_t n; + nn_tag_t *tags; +} nn_tagseq_t; + +typedef struct nn_datatags { + nn_tagseq_t tags; +} nn_datatags_t; +#endif #ifdef DDSI_INCLUDE_SSM typedef struct nn_reader_favours_ssm { @@ -104,6 +120,57 @@ typedef struct nn_reader_favours_ssm { } nn_reader_favours_ssm_t; #endif +#ifdef DDSI_INCLUDE_SECURITY +typedef struct nn_dataholder +{ + char *class_id; + dds_propertyseq_t properties; + dds_binarypropertyseq_t binary_properties; +} nn_dataholder_t; + +typedef struct nn_dataholderseq { + uint32_t n; + nn_dataholder_t *tags; +} nn_dataholderseq_t; + +typedef nn_dataholder_t nn_token_t; + +/* Used for both nn_participant_security_info and nn_endpoint_security_info. */ +typedef struct nn_security_info +{ + uint32_t security_attributes; + uint32_t plugin_security_attributes; +} nn_security_info_t; + +#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_READ_PROTECTED (1u << 0) +#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_WRITE_PROTECTED (1u << 1) +#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_DISCOVERY_PROTECTED (1u << 2) +#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_PROTECTED (1u << 3) +#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_PAYLOAD_PROTECTED (1u << 4) +#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_KEY_PROTECTED (1u << 5) +#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_LIVELINESS_PROTECTED (1u << 6) +#define NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID (1u << 31) + +#define NN_PLUGIN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED (1u << 0) +#define NN_PLUGIN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED (1u << 1) +#define NN_PLUGIN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED (1u << 2) + +#define NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_RTPS_PROTECTED (1u << 0) +#define NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_DISCOVERY_PROTECTED (1u << 1) +#define NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_LIVELINESS_PROTECTED (1u << 2) +#define NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_VALID (1u << 31) + +#define NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED (1u << 0) +#define NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_DISCOVERY_ENCRYPTED (1u << 1) +#define NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_LIVELINESS_ENCRYPTED (1u << 2) +#define NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED (1u << 3) +#define NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_DISCOVERY_AUTHENTICATED (1u << 4) +#define NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_LIVELINESS_AUTHENTICATED (1u << 5) +#else +struct nn_security_info; +typedef struct nn_security_info nn_security_info_t; +#endif + typedef struct nn_adlink_participant_version_info { uint32_t version; @@ -142,11 +209,19 @@ typedef struct ddsi_plist { uint32_t builtin_endpoint_set; /* int type_max_size_serialized; */ char *entity_name; - nn_keyhash_t keyhash; + ddsi_keyhash_t keyhash; uint32_t statusinfo; nn_adlink_participant_version_info_t adlink_participant_version_info; char *type_description; nn_sequence_number_t coherent_set_seqno; +#ifdef DDSI_INCLUDE_SECURITY + nn_token_t identity_token; + nn_token_t permissions_token; + nn_security_info_t endpoint_security_info; + nn_security_info_t participant_security_info; + nn_token_t identity_status_token; + nn_datatags_t data_tags; +#endif #ifdef DDSI_INCLUDE_SSM nn_reader_favours_ssm_t reader_favours_ssm; #endif @@ -225,6 +300,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); @@ -235,7 +311,7 @@ struct nn_rsample_info; struct nn_rdata; DDS_EXPORT unsigned char *ddsi_plist_quickscan (struct nn_rsample_info *dest, const struct nn_rmsg *rmsg, const ddsi_plist_src_t *src); -DDS_EXPORT const unsigned char *ddsi_plist_findparam_native_unchecked (const void *src, nn_parameterid_t pid); +DDS_EXPORT dds_return_t ddsi_plist_findparam_checking (const void *buf, size_t bufsz, uint16_t encoding, nn_parameterid_t needle, void **needlep, size_t *needlesz); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_plist_generic.h b/src/core/ddsi/include/dds/ddsi/ddsi_plist_generic.h index 8853ef7..6408942 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_plist_generic.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_plist_generic.h @@ -19,6 +19,7 @@ #include "dds/export.h" #include "dds/ddsrt/attributes.h" +#include "dds/ddsrt/retcode.h" #if defined (__cplusplus) extern "C" { @@ -34,6 +35,7 @@ enum pserop { Xi, Xix2, Xix3, Xix4, /* int32_t, 1 .. 4 in a row */ Xu, Xux2, Xux3, Xux4, Xux5, /* uint32_t, 1 .. 5 in a row */ XD, XDx2, /* duration, 1 .. 2 in a row */ + Xl, /* int64_t */ Xo, Xox2, /* octet, 1 .. 2 in a row */ Xb, Xbx2, /* boolean, 1 .. 2 in a row */ XbCOND, /* boolean: compare to ignore remainder if false (for use_... flags) */ @@ -44,21 +46,14 @@ enum pserop { Xopt, /* remainder is optional on deser, 0-init if not present */ } ddsrt_attribute_packed; -inline bool pserop_seralign_is_1 (enum pserop op) { - /* NB: XbPROP is never serialized, so its alignment is irrelevant. If ever there - is a need to allow calling this function when op = XbPROP, it needs to be changed - to taking the address of the pserop, and in that case inspect the following - operator */ - assert (op != XbPROP && op != Xopt && op != XSTOP); - return (op >= Xo && op <= XK); -} - DDS_EXPORT void plist_fini_generic (void * __restrict dst, const enum pserop *desc, bool aliased); DDS_EXPORT dds_return_t plist_deser_generic (void * __restrict dst, const void * __restrict src, size_t srcsize, bool bswap, const enum pserop * __restrict desc); DDS_EXPORT dds_return_t plist_ser_generic (void **dst, size_t *dstsize, const void *src, const enum pserop * __restrict desc); +DDS_EXPORT dds_return_t plist_ser_generic_be (void **dst, size_t *dstsize, const void *src, const enum pserop * __restrict desc); DDS_EXPORT dds_return_t plist_unalias_generic (void * __restrict dst, const enum pserop * __restrict desc); DDS_EXPORT bool plist_equal_generic (const void *srcx, const void *srcy, const enum pserop * __restrict desc); DDS_EXPORT size_t plist_memsize_generic (const enum pserop * __restrict desc); +DDS_EXPORT size_t plist_print_generic (char * __restrict buf, size_t bufsize, const void * __restrict src, const enum pserop * __restrict desc); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_pmd.h b/src/core/ddsi/include/dds/ddsi/ddsi_pmd.h index 0948247..40cf62a 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_pmd.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_pmd.h @@ -12,7 +12,12 @@ #ifndef DDSI_PMD_H #define DDSI_PMD_H +#include #include "dds/ddsrt/time.h" +#include "dds/ddsi/ddsi_serdata.h" +#include "dds/ddsi/ddsi_plist_generic.h" +#include "dds/ddsi/ddsi_guid.h" +#include "dds/ddsi/ddsi_xqos.h" #if defined (__cplusplus) extern "C" { @@ -25,9 +30,20 @@ struct nn_xpack; struct participant; struct receiver_state; +typedef struct ParticipantMessageData { + ddsi_guid_prefix_t participantGuidPrefix; + uint32_t kind; /* really 4 octets */ + ddsi_octetseq_t value; +} ParticipantMessageData_t; + +extern const enum pserop participant_message_data_ops[]; +extern size_t participant_message_data_nops; +extern const enum pserop participant_message_data_ops_key[]; +extern size_t participant_message_data_nops_key; + void write_pmd_message_guid (struct ddsi_domaingv * const gv, struct ddsi_guid *pp_guid, unsigned pmd_kind); void write_pmd_message (struct thread_state1 * const ts1, struct nn_xpack *xp, struct participant *pp, unsigned pmd_kind); -void handle_pmd_message (const struct receiver_state *rst, ddsrt_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len); +void handle_pmd_message (const struct receiver_state *rst, struct ddsi_serdata *sample_common); #if defined (__cplusplus) } 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..07268d0 --- /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, struct ddsi_serdata *sample); +void handle_crypto_exchange_message(const struct receiver_state *rst, struct ddsi_serdata *sample); +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 new file mode 100644 index 0000000..99c5c31 --- /dev/null +++ b/src/core/ddsi/include/dds/ddsi/ddsi_security_msg.h @@ -0,0 +1,112 @@ +/* + * 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_MSG_H +#define DDSI_SECURITY_MSG_H + +#ifdef DDSI_INCLUDE_SECURITY + +#include "dds/ddsi/ddsi_plist.h" +#include "dds/ddsi/ddsi_guid.h" +#include "dds/ddsrt/retcode.h" +#include "dds/ddsi/ddsi_plist_generic.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +struct participant; +struct writer; +struct proxy_reader; +struct ddsi_serdata; + +#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; + int64_t sequence_number; +} nn_message_identity_t; + +typedef struct nn_participant_generic_message { + nn_message_identity_t message_identity; + nn_message_identity_t related_message_identity; + ddsi_guid_t destination_participant_guid; + ddsi_guid_t destination_endpoint_guid; + ddsi_guid_t source_endpoint_guid; + const char *message_class_id; + nn_dataholderseq_t message_data; +} nn_participant_generic_message_t; + + +/* + * The arguments are aliased in the resulting message structure. + * This means that the lifecycle of the arguments should be longer + * then that of the message. + */ +DDS_EXPORT void +nn_participant_generic_message_init( + nn_participant_generic_message_t *msg, + const ddsi_guid_t *wrguid, + int64_t wrseq, + const ddsi_guid_t *dstpguid, + const ddsi_guid_t *dsteguid, + const ddsi_guid_t *srceguid, + const char *classid, + const nn_dataholderseq_t *mdata, + const nn_message_identity_t *rmid); + +/* + * Aliased struct variables will not be freed. + */ +DDS_EXPORT void +nn_participant_generic_message_deinit( + nn_participant_generic_message_t *msg); + +/* + * Some struct variables are aliased to the given buffer. + * This means that the lifecycle of the data buffer should be + * longer then that of the message. + */ +DDS_EXPORT dds_return_t +nn_participant_generic_message_deseralize( + nn_participant_generic_message_t *msg, + const unsigned char *data, + size_t len, + bool bswap); + +DDS_EXPORT dds_return_t +nn_participant_generic_message_serialize( + const nn_participant_generic_message_t *msg, + unsigned char **data, + size_t *len); + +DDS_EXPORT extern const enum pserop pserop_participant_generic_message[]; +DDS_EXPORT extern const size_t pserop_participant_generic_message_nops; + +DDS_EXPORT int +volatile_secure_data_filter( + struct writer *wr, + struct proxy_reader *prd, + struct ddsi_serdata *serdata); + +#if defined (__cplusplus) +} +#endif + +#endif + +#endif /* DDSI_SECURITY_MSG_H */ diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_security_omg.h b/src/core/ddsi/include/dds/ddsi/ddsi_security_omg.h new file mode 100644 index 0000000..bcf81ec --- /dev/null +++ b/src/core/ddsi/include/dds/ddsi/ddsi_security_omg.h @@ -0,0 +1,1418 @@ +/* + * 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_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" +#include "dds/ddsi/q_radmin.h" +#include "dds/ddsi/q_xmsg.h" +#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" { +#endif + +typedef enum { + NN_RTPS_MSG_STATE_ERROR, + NN_RTPS_MSG_STATE_PLAIN, + NN_RTPS_MSG_STATE_ENCODED +} nn_rtps_msg_state_t; + +#ifdef DDSI_INCLUDE_SECURITY + +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; +} nn_msg_sec_info_t; + + + + + + +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; + bool authenticated; +}; + +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; +}; + +DDS_EXPORT struct dds_security_access_control *q_omg_participant_get_access_control(const struct participant *pp); +DDS_EXPORT struct dds_security_authentication *q_omg_participant_get_authentication(const struct participant *pp); +DDS_EXPORT struct dds_security_cryptography *q_omg_participant_get_cryptography(const struct participant *pp); + +void q_omg_vlog_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, va_list ap); +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 True if participant is secure + */ +bool q_omg_participant_is_secure(const struct participant *pp); + +/** + * @brief Check if security is enabled for the proxy participant. + * + * @param[in] proxypp Proxy participant to check if it is secure. + * + * @returns bool True if proxy participant is secure + */ +bool q_omg_proxy_participant_is_secure(const struct proxy_participant *proxypp); + +/** + * @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 dds_return_t + * @retval DDS_RETCODE_OK Participant is allowed + * @retval DDS_RETCODE_NOT_ALLOWED_BY_SECURITY + * Participant is not allowed + */ +dds_return_t 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 !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(const struct participant *pp); + +/** + * @brief Get security info flags of the given participant. + * + * @param[in] pp Participant to get the security info from. + * @param[out] info The security info. + * + * @returns bool + * @retval true Security info set. + * @retval false Security info not set. + */ +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. + * + * @param[in] wr Writer to get the security info from. + * @param[out] info The security info. + * + * @returns bool + * @retval true Security info set. + * @retval false Security info not set (probably unsecure writer). + */ +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. + * + * @param[in] rd Reader to get the security info from. + * @param[out] info The security info. + * + * @returns bool + * @retval true Security info set. + * @retval false Security info not set (probably unsecure reader). + */ +bool q_omg_get_reader_security_info(const struct reader *rd, nn_security_info_t *info); + +/** + * @brief Return the builtin writer id for this readers' discovery. + * + * Return builtin entity id of the writer to use for the subscription + * discovery information. + * Depending on whether the discovery is protected or not (for the + * given reader), either the default writer or protected writer needs + * to be used. + * + * @param[in] rd Reader to determine the subscription writer from. + * + * @returns unsigned + * @retval NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER + * @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 Register the reader with security. + * + * 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] rd The reader to register. + */ +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 + * by the given writer. + * + * If an proxy participant is authenticated, it is only allowed to + * to deleted when a dispose is received from the proper protected + * discovery writer. + * + * @param[in] gv Used for tracing. + * @param[in] guid Guid of the proxy participant to be deleted. + * @param[in] pwr_entityid Writer that send the dispose. + * + * @returns bool + * @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); + +/** + * @brief Determine if the messages, related to the given remote + * entity, are RTPS protected or not. + * + * @param[in] proxy_pp Related proxy 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_remote_rtps_protected(const struct proxy_participant *proxy_pp, ddsi_entityid_t entityid); + +/** + * @brief Set security information, depending on plist, into the given + * proxy participant. + * + * @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); + +/** + * @brief Determine if the messages, related to the given remote + * entity, are RTPS protected or not. + * + * @param[in] pp The 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); + +/** + * @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 Sets the matching participant and proxy participant as authorized. + * + * When the authentication handshake has finished successfully and the + * volatile secure readers and writers are matched then with this function + * the matching local and remote participant are set to authenticated which + * allows the crypto tokens to be exchanged and the corresponding entities + * be matched. + * + * @param[in] pp The participant. + * @param[in] proxypp The proxy participant. + */ +void q_omg_security_set_remote_participant_authenticated(struct participant *pp, struct proxy_participant *proxypp); + +/** + * @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 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 Release all the security resources associated with the remote writer. + * + * Cleanup security resource associated with the remote writer. + * + * @param[in] pwr The remote writer. + */ +void q_omg_security_deregister_remote_writer(const struct proxy_writer *pwr); + +/** + * @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. + * @param[out] relay_only The "relay_only" value returned by the access control + * operation check_remote_datareader() + * + * @returns bool + * @retval true The remote reader is allowed to communicate. + * @retval false Otherwise; relay_only is unspecified. + */ +bool q_omg_security_check_remote_reader_permissions(const struct proxy_reader *prd, uint32_t domain_id, struct participant *pp, bool *relay_only); + + +/** + * @brief Set security information, depending on plist and proxy participant, + * into the given proxy endpoint. + * + * @param[in] entity The endpoint common attributes. + * @param[in] proxypp_sec_info The security info of the proxy participant + * @param[in] plist Paramater list which may contain security info. + * @param[in] info The proxy endpoint security info to be set. + */ +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); + +/** + * @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[in] relay_only The "relay_only" returned by access control + * operation check_remote_datareader() + * @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, bool relay_only, 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 Release all the security resources associated with the remote reader. + * + * Cleanup security resource associated with the remote reader. + * + * @param[in] prd The remote reader. + */ +void q_omg_security_deregister_remote_reader(const struct proxy_reader *prd); + +/** + * @brief Encode RTPS message. + * + * @param[in] src_handle Security handle of data source. + * @param[in] src_guid GUID of the entity data source. + * @param[in] src_buf Original RTPS message. + * @param[in] src_len Original RTPS message size. + * @param[out] dst_buf Encoded RTPS message. + * @param[out] dst_len Encoded RTPS message size. + * @param[in] dst_handle Security handle of data destination. + * + * @returns bool + * @retval true Encoding succeeded. + * @retval false Encoding failed. + */ +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); + +/** + * @brief Encode payload when necessary. + * + * When encoding is necessary, *buf will be allocated and the vec contents + * will change to point to that buffer. + * It is expected that the vec contents is always aliased. + * + * If no encoding is necessary, nothing changes. + * + * encoding( not needed) -> return( true), vec(untouched), buf(NULL) + * encoding(needed&success) -> return( true), vec( buf(new)) + * encoding(needed&failure) -> return(false), vec(untouched), buf(NULL) + * + * @param[in] wr Writer that writes the payload. + * @param[in,out] vec An iovec that contains the payload. + * @param[out] buf Buffer to contain the encoded payload. + * + * @returns bool + * @retval true Encoding succeeded or not necessary. Either way, vec + * 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); + +/** + * @brief Decode the payload of a Data submessage. + * + * When decoding is necessary, the payloadp memory will be replaced + * by the decoded payload. This means that the original submessage + * now contains payload that can be deserialized. + * + * If no decoding is necessary, nothing changes. + * + * @param[in] gv Global information. + * @param[in] sampleinfo Sample information. + * @param[in,out] payloadp Pointer to payload memory. + * @param[in] payloadsz Size of payload. + * @param[in,out] submsg_len Size of submessage. + * + * @returns bool + * @retval true Decoding succeeded or not necessary. Either way, payloadp + * 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); + +/** + * @brief Decode the payload of a DataFrag submessage. + * + * When decoding is necessary, the payloadp memory will be replaced + * by the decoded payload. This means that the original submessage + * now contains payload that can be deserialized. + * + * If no decoding is necessary, nothing changes. + * + * @param[in] gv Global information. + * @param[in] sampleinfo Sample information. + * @param[in,out] payloadp Pointer to payload memory. + * @param[in] payloadsz Size of payload. + * @param[in,out] submsg_len Size of submessage. + * + * @returns bool + * @retval true Decoding succeeded or not necessary. Either way, payloadp + * 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); + +/** + * @brief Encode datareader submessage when necessary. + * + * When encoding is necessary, the original submessage will be replaced + * by a new encoded submessage. + * If the encoding fails, the original submessage will be removed. + * + * If no encoding is necessary, nothing changes. + * + * @param[in,out] msg Complete message. + * @param[in,out] sm_marker Submessage location within message. + * @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); + +/** + * @brief Encode datawriter submessage when necessary. + * + * When encoding is necessary, the original submessage will be replaced + * by a new encoded submessage. + * If the encoding fails, the original submessage will be removed. + * + * If no encoding is necessary, nothing changes. + * + * @param[in,out] msg Complete message. + * @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); + +/** + * @brief Check if given submessage is properly decoded. + * + * When decoding is necessary, it should be checked if a plain submessage was + * actually decoded. Otherwise data can be injected just by inserting a plain + * submessage directly. + * + * @param[in] e Entity information. + * @param[in] c Proxy endpoint information. + * @param[in] proxypp Related proxy participant. + * @param[in] rst Receiver information. + * @param[in] prev_smid Previously handled submessage ID. + * + * @returns bool + * @retval true Decoding succeeded or was not necessary. + * @retval false Decoding was necessary, but not detected. + */ +bool +validate_msg_decoding( + const struct entity_common *e, + const struct proxy_endpoint_common *c, + const struct proxy_participant *proxypp, + const struct receiver_state *rst, + SubmessageKind_t prev_smid); + +/** + * @brief Decode not only SecPrefix, but also the SecBody and SecPostfix + * sub-messages. + * + * When encrypted, the original SecBody will be replaced by the decrypted + * submessage. Then the normal sequence can continue as if there was no + * encrypted data. + * + * @param[in] rst Receiver information. + * @param[in,out] submsg Pointer to SecPrefix/(SecBody|Submsg)/SecPostfix. + * @param[in] submsg_size Size of SecPrefix submessage. + * @param[in] msg_end End of the complete message. + * @param[in] src_prefix Prefix of the source entity. + * @param[in] dst_prefix Prefix of the destination entity. + * @param[in] byteswap Do the bytes need swapping? + * + * @returns bool + * @retval true Decoding succeeded. + * @retval false Decoding failed. + */ +bool +decode_SecPrefix( + const struct receiver_state *rst, + unsigned char *submsg, + size_t submsg_size, + unsigned char * const msg_end, + const ddsi_guid_prefix_t * const src_prefix, + const ddsi_guid_prefix_t * const dst_prefix, + int byteswap); + +/** + * @brief Decode the RTPS message. + * + * When encrypted, the original buffers and information will be replaced + * by the decrypted RTPS message. Then the normal sequence can continue + * as if there was no encrypted data. + * + * @param[in] ts1 Thread information. + * @param[in] gv Global information. + * @param[in,out] rmsg Message information. + * @param[in,out] hdr Message header. + * @param[in,out] buff Message buffer. + * @param[in,out] sz Message size. + * @param[in] rbpool Buffers pool. + * @param[in] isstream Is message a stream variant? + * + * @returns nn_rtps_msg_state_t + * @retval NN_RTPS_MSG_STATE_PLAIN No decoding was necessary. + * @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); + +/** + * @brief Send the RTPS message securely. + * + * @param[in] conn Connection to use. + * @param[in] dst Possible destination information. + * @param[in] niov Number of io vectors. + * @param[in] iov Array of io vectors. + * @param[in] flags Connection write flags. + * @param[in,out] msg_len Submessage containing length. + * @param[in] dst_one Is there only one specific destination? + * @param[in] sec_info Security information for handles. + * @param[in] conn_write_cb Function to call to do the actual writing. + * + * @returns ssize_t + * @retval negative/zero Something went wrong. + * @retval positive Secure writing succeeded. + */ +ssize_t +secure_conn_write( + const struct ddsi_domaingv *gv, + ddsi_tran_conn_t conn, + const nn_locator_t *dst, + size_t niov, + const ddsrt_iovec_t *iov, + uint32_t flags, + MsgLen_t *msg_len, + bool dst_one, + nn_msg_sec_info_t *sec_info, + ddsi_tran_write_fn_t conn_write_cb); + + +/** + * @brief Loads the security plugins with the given configuration. + * This function tries to load the plugins only once. Returns the same + * result on subsequent calls. + * It logs the reason and returns error if can not load a plugin. + * + * @param[in] qos Participant qos which owns the Property list + * that contains security configurations and + * plugin properties that are required for loading libraries + * @returns dds_return_t + * @retval DDS_RETCODE_OK All plugins are successfully loaded + * @retval DDS_RETCODE_ERROR One or more security plugins are not loaded. + */ +dds_return_t q_omg_security_load( struct dds_security_context *security_context, const dds_qos_t *qos, struct ddsi_domaingv *gv ); + + +void q_omg_security_init( struct ddsi_domaingv *gv ); + +void q_omg_security_stop (struct ddsi_domaingv *gv); + +void q_omg_security_deinit (struct dds_security_context *sc ); + +void q_omg_security_free (struct ddsi_domaingv *gv); + +bool q_omg_is_security_loaded( struct dds_security_context *sc ); + +#else /* DDSI_INCLUDE_SECURITY */ + +#include "dds/ddsi/q_unused.h" + +inline bool q_omg_security_enabled(void) +{ + return false; +} + +inline bool q_omg_participant_is_access_protected(UNUSED_ARG(const struct participant *pp)) +{ + return false; +} + +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)) +{ + 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)) +{ + return true; +} + +inline bool q_omg_is_similar_participant_security_info(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp)) +{ + return true; +} + +inline bool q_omg_participant_allow_unauthenticated(UNUSED_ARG(struct participant *pp)) +{ + return true; +} + +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)) +{ +} + +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)) +{ + return 0LL; +} + +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)) +{ +} + +inline void q_omg_security_participant_send_tokens(UNUSED_ARG(struct participant *pp), UNUSED_ARG(struct proxy_participant *proxypp)) +{ +} + +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), UNUSED_ARG(bool relay_only), UNUSED_ARG(int64_t *crypto_handle)) +{ + return true; +} + +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 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), UNUSED_ARG(bool *relay_only)) +{ + *relay_only = false; + 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_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 bool +decode_Data( + UNUSED_ARG(const struct ddsi_domaingv *gv), + UNUSED_ARG(struct nn_rsample_info *sampleinfo), + UNUSED_ARG(unsigned char *payloadp), + UNUSED_ARG(uint32_t payloadsz), + UNUSED_ARG(size_t *submsg_len)) +{ + return true; +} + +inline bool +decode_DataFrag( + UNUSED_ARG(const struct ddsi_domaingv *gv), + UNUSED_ARG(struct nn_rsample_info *sampleinfo), + UNUSED_ARG(unsigned char *payloadp), + UNUSED_ARG(uint32_t payloadsz), + UNUSED_ARG(size_t *submsg_len)) +{ + return true; +} + +inline void +encode_datareader_submsg( + UNUSED_ARG(struct nn_xmsg *msg), + UNUSED_ARG(struct nn_xmsg_marker sm_marker), + UNUSED_ARG(struct proxy_writer *pwr), + UNUSED_ARG(const struct ddsi_guid *rd_guid)) +{ +} + +inline void +encode_datawriter_submsg( + UNUSED_ARG(struct nn_xmsg *msg), + UNUSED_ARG(struct nn_xmsg_marker sm_marker), + UNUSED_ARG(struct writer *wr)) +{ +} + +inline bool +validate_msg_decoding( + UNUSED_ARG(const struct entity_common *e), + UNUSED_ARG(const struct proxy_endpoint_common *c), + UNUSED_ARG(struct proxy_participant *proxypp), + UNUSED_ARG(struct receiver_state *rst), + UNUSED_ARG(SubmessageKind_t prev_smid)) +{ + return true; +} + +inline int +decode_SecPrefix( + UNUSED_ARG(struct receiver_state *rst), + UNUSED_ARG(unsigned char *submsg), + UNUSED_ARG(size_t submsg_size), + UNUSED_ARG(unsigned char * const msg_end), + UNUSED_ARG(const ddsi_guid_prefix_t * const src_prefix), + UNUSED_ARG(const ddsi_guid_prefix_t * const dst_prefix), + UNUSED_ARG(int byteswap)) +{ + /* Just let the parsing ignore the security sub-messages. */ + return true; +} + +inline nn_rtps_msg_state_t +decode_rtps_message( + UNUSED_ARG(struct thread_state1 * const ts1), + UNUSED_ARG(struct ddsi_domaingv *gv), + UNUSED_ARG(struct nn_rmsg **rmsg), + UNUSED_ARG(Header_t **hdr), + UNUSED_ARG(unsigned char **buff), + UNUSED_ARG(ssize_t *sz), + UNUSED_ARG(struct nn_rbufpool *rbpool), + UNUSED_ARG(bool isstream)) +{ + return NN_RTPS_MSG_STATE_PLAIN; +} + +inline dds_return_t q_omg_security_load( UNUSED_ARG( struct dds_security_context *security_context ), UNUSED_ARG( const dds_qos_t *property_seq), UNUSED_ARG ( struct ddsi_domaingv *gv ) ) +{ + return DDS_RETCODE_ERROR; +} + +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) +} +#endif + +#endif /* DDSI_OMG_SECURITY_H */ 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..188675e --- /dev/null +++ b/src/core/ddsi/include/dds/ddsi/ddsi_security_util.h @@ -0,0 +1,64 @@ +/* + * 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); +void q_omg_shallow_copy_TopicBuiltinTopicData(DDS_Security_TopicBuiltinTopicData *dst, const char *topic_name, const char *type_name); +void q_omg_shallow_free_TopicBuiltinTopicData(DDS_Security_TopicBuiltinTopicData *obj); + +#if defined (__cplusplus) +} +#endif + + +#endif /* DDSI_INCLUDE_SECURITY */ + +#endif /* DDSI_SECURITY_UTIL_H */ diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_serdata.h b/src/core/ddsi/include/dds/ddsi/ddsi_serdata.h index 7b9559b..1343c23 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_serdata.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_serdata.h @@ -14,13 +14,13 @@ #include "dds/ddsrt/sockets.h" #include "dds/ddsi/ddsi_sertopic.h" +#include "dds/ddsi/ddsi_keyhash.h" #if defined (__cplusplus) extern "C" { #endif struct nn_rdata; -struct nn_keyhash; enum ddsi_serdata_kind { SDK_EMPTY, @@ -64,7 +64,7 @@ typedef struct ddsi_serdata * (*ddsi_serdata_from_ser_t) (const struct ddsi_sert typedef struct ddsi_serdata * (*ddsi_serdata_from_ser_iov_t) (const struct ddsi_sertopic *topic, enum ddsi_serdata_kind kind, ddsrt_msg_iovlen_t niov, const ddsrt_iovec_t *iov, size_t size); /* Construct a serdata from a keyhash (an SDK_KEY by definition) */ -typedef struct ddsi_serdata * (*ddsi_serdata_from_keyhash_t) (const struct ddsi_sertopic *topic, const struct nn_keyhash *keyhash); +typedef struct ddsi_serdata * (*ddsi_serdata_from_keyhash_t) (const struct ddsi_sertopic *topic, const struct ddsi_keyhash *keyhash); /* Construct a serdata from an application sample - "kind" is KEY or DATA depending on the operation invoked by the application; @@ -134,7 +134,10 @@ typedef bool (*ddsi_serdata_eqkey_t) (const struct ddsi_serdata *a, const struct returning bufsize-1) if it had to truncate) */ typedef size_t (*ddsi_serdata_print_t) (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, char *buf, size_t size); -#define DDSI_SERDATA_HAS_FROM_SER_IOV 1 +/* Add keyhash (from serdata) to buffer (forcing md5 when necessary). + - key needs to be set within serdata (can already be md5) + - buf needs to be at least 16 bytes large */ +typedef void (*ddsi_serdata_get_keyhash_t) (const struct ddsi_serdata *d, struct ddsi_keyhash *buf, bool force_md5); struct ddsi_serdata_ops { ddsi_serdata_eqkey_t eqkey; @@ -151,9 +154,12 @@ struct ddsi_serdata_ops { ddsi_serdata_topicless_to_sample_t topicless_to_sample; ddsi_serdata_free_t free; ddsi_serdata_print_t print; + ddsi_serdata_get_keyhash_t get_keyhash; }; #define DDSI_SERDATA_HAS_PRINT 1 +#define DDSI_SERDATA_HAS_FROM_SER_IOV 1 +#define DDSI_SERDATA_HAS_GET_KEYHASH 1 DDS_EXPORT void ddsi_serdata_init (struct ddsi_serdata *d, const struct ddsi_sertopic *tp, enum ddsi_serdata_kind kind); @@ -180,7 +186,7 @@ DDS_EXPORT inline struct ddsi_serdata *ddsi_serdata_from_ser_iov (const struct d return topic->serdata_ops->from_ser_iov (topic, kind, niov, iov, size); } -DDS_EXPORT inline struct ddsi_serdata *ddsi_serdata_from_keyhash (const struct ddsi_sertopic *topic, const struct nn_keyhash *keyhash) { +DDS_EXPORT inline struct ddsi_serdata *ddsi_serdata_from_keyhash (const struct ddsi_sertopic *topic, const struct ddsi_keyhash *keyhash) { return topic->serdata_ops->from_keyhash (topic, keyhash); } @@ -230,6 +236,10 @@ DDS_EXPORT inline bool ddsi_serdata_print_topicless (const struct ddsi_sertopic } } +DDS_EXPORT inline void ddsi_serdata_get_keyhash (const struct ddsi_serdata *d, struct ddsi_keyhash *buf, bool force_md5) { + d->ops->get_keyhash (d, buf, force_md5); +} + #if defined (__cplusplus) } #endif diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_serdata_default.h b/src/core/ddsi/include/dds/ddsi/ddsi_serdata_default.h index 27a155b..50c9744 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_serdata_default.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_serdata_default.h @@ -18,6 +18,7 @@ #include "dds/ddsrt/avl.h" #include "dds/ddsi/ddsi_serdata.h" #include "dds/ddsi/ddsi_sertopic.h" +#include "dds/ddsi/ddsi_plist_generic.h" #include "dds/dds.h" @@ -46,6 +47,7 @@ typedef struct dds_keyhash { unsigned char m_hash [16]; /* Key hash value. Also possibly key. Suitably aligned for accessing as uint32_t's */ unsigned m_set : 1; /* has it been initialised? */ unsigned m_iskey : 1; /* m_hash is key value */ + unsigned m_keysize : 5; /* size of the key within the hash buffer */ } dds_keyhash_t; /* Debug builds may want to keep some additional state */ @@ -135,8 +137,6 @@ extern DDS_EXPORT const struct ddsi_sertopic_ops ddsi_sertopic_ops_default; extern DDS_EXPORT const struct ddsi_serdata_ops ddsi_serdata_ops_cdr; extern DDS_EXPORT const struct ddsi_serdata_ops ddsi_serdata_ops_cdr_nokey; -extern DDS_EXPORT const struct ddsi_serdata_ops ddsi_serdata_ops_plist; -extern DDS_EXPORT const struct ddsi_serdata_ops ddsi_serdata_ops_rawcdr; struct serdatapool * ddsi_serdatapool_new (void); void ddsi_serdatapool_free (struct serdatapool * pool); diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_serdata_plist.h b/src/core/ddsi/include/dds/ddsi/ddsi_serdata_plist.h new file mode 100644 index 0000000..1ceee87 --- /dev/null +++ b/src/core/ddsi/include/dds/ddsi/ddsi_serdata_plist.h @@ -0,0 +1,76 @@ +/* + * 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_SERDATA_PLIST_H +#define DDSI_SERDATA_PLIST_H + +#include "dds/ddsi/q_protocol.h" /* for nn_parameterid_t */ +#include "dds/ddsi/ddsi_keyhash.h" +#include "dds/ddsi/ddsi_serdata.h" +#include "dds/ddsi/ddsi_sertopic.h" + +#include "dds/dds.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +/* There is an alignment requirement on the raw data (it must be at + offset mod 8 for the conversion to/from a dds_stream to work). + So we define two types: one without any additional padding, and + one where the appropriate amount of padding is inserted */ +#define DDSI_SERDATA_PLIST_PREPAD \ + struct ddsi_serdata c; \ + uint32_t pos; \ + uint32_t size; \ + nn_vendorid_t vendorid; \ + nn_protocol_version_t protoversion; \ + ddsi_keyhash_t keyhash +#define DDSI_SERDATA_PLIST_POSTPAD \ + uint16_t identifier; \ + uint16_t options; \ + char data[] + +struct ddsi_serdata_plist_unpadded { + DDSI_SERDATA_PLIST_PREPAD; + DDSI_SERDATA_PLIST_POSTPAD; +}; + +#ifdef __GNUC__ +#define DDSI_SERDATA_PLIST_PAD(n) ((n) % 8) +#else +#define DDSI_SERDATA_PLIST_PAD(n) (n) +#endif + +struct ddsi_serdata_plist { + DDSI_SERDATA_PLIST_PREPAD; + char pad[DDSI_SERDATA_PLIST_PAD (8 - (offsetof (struct ddsi_serdata_plist_unpadded, data) % 8))]; + DDSI_SERDATA_PLIST_POSTPAD; +}; + +#undef DDSI_SERDATA_PLIST_PAD +#undef DDSI_SERDATA_PLIST_POSTPAD +#undef DDSI_SERDATA_PLIST_PREPAD + +struct ddsi_sertopic_plist { + struct ddsi_sertopic c; + uint16_t native_encoding_identifier; /* PL_CDR_(LE|BE) */ + nn_parameterid_t keyparam; +}; + +extern DDS_EXPORT const struct ddsi_sertopic_ops ddsi_sertopic_ops_plist; +extern DDS_EXPORT const struct ddsi_serdata_ops ddsi_serdata_ops_plist; + +#if defined (__cplusplus) +} +#endif + +#endif diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_serdata_pserop.h b/src/core/ddsi/include/dds/ddsi/ddsi_serdata_pserop.h new file mode 100644 index 0000000..6771a07 --- /dev/null +++ b/src/core/ddsi/include/dds/ddsi/ddsi_serdata_pserop.h @@ -0,0 +1,78 @@ +/* + * 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_SERDATA_PSEROP_H +#define DDSI_SERDATA_PSEROP_H + +#include "dds/ddsi/ddsi_serdata.h" +#include "dds/ddsi/ddsi_sertopic.h" +#include "dds/ddsi/ddsi_plist_generic.h" + +#include "dds/dds.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +/* There is an alignment requirement on the raw data (it must be at + offset mod 8 for the conversion to/from a dds_stream to work). + So we define two types: one without any additional padding, and + one where the appropriate amount of padding is inserted */ +#define DDSI_SERDATA_PSEROP_PREPAD \ + struct ddsi_serdata c; \ + void *sample; \ + bool keyless; /*cached from topic*/ \ + uint32_t pos; \ + uint32_t size +#define DDSI_SERDATA_PSEROP_POSTPAD \ + uint16_t identifier; \ + uint16_t options; \ + char data[] + +struct ddsi_serdata_pserop_unpadded { + DDSI_SERDATA_PSEROP_PREPAD; + DDSI_SERDATA_PSEROP_POSTPAD; +}; + +#ifdef __GNUC__ +#define DDSI_SERDATA_PSEROP_PAD(n) ((n) % 8) +#else +#define DDSI_SERDATA_PSEROP_PAD(n) (n) +#endif + +struct ddsi_serdata_pserop { + DDSI_SERDATA_PSEROP_PREPAD; + char pad[DDSI_SERDATA_PSEROP_PAD (8 - (offsetof (struct ddsi_serdata_pserop_unpadded, data) % 8))]; + DDSI_SERDATA_PSEROP_POSTPAD; +}; + +#undef DDSI_SERDATA_PSEROP_PAD +#undef DDSI_SERDATA_PSEROP_POSTPAD +#undef DDSI_SERDATA_PSEROP_PREPAD + +struct ddsi_sertopic_pserop { + struct ddsi_sertopic c; + uint16_t native_encoding_identifier; /* CDR_(LE|BE) */ + size_t memsize; + size_t nops; + const enum pserop *ops; + size_t nops_key; + const enum pserop *ops_key; /* NULL <=> no key; != NULL <=> 16-byte key at offset 0 */ +}; + +extern DDS_EXPORT const struct ddsi_sertopic_ops ddsi_sertopic_ops_pserop; +extern DDS_EXPORT const struct ddsi_serdata_ops ddsi_serdata_ops_pserop; + +#if defined (__cplusplus) +} +#endif + +#endif diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_xqos.h b/src/core/ddsi/include/dds/ddsi/ddsi_xqos.h index 9161a70..b7e803a 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_xqos.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_xqos.h @@ -322,6 +322,13 @@ DDS_EXPORT void ddsi_xqos_addtomsg (struct nn_xmsg *m, const dds_qos_t *xqos, ui DDS_EXPORT void ddsi_xqos_log (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos); DDS_EXPORT size_t ddsi_xqos_print (char * __restrict buf, size_t bufsize, const dds_qos_t *xqos); DDS_EXPORT dds_qos_t *ddsi_xqos_dup (const dds_qos_t *src); +DDS_EXPORT bool ddsi_xqos_has_prop_prefix (const dds_qos_t *xqos, const char *nameprefix); +DDS_EXPORT bool ddsi_xqos_find_prop (const dds_qos_t *xqos, const char *name, const char **value); + +#ifdef DDSI_INCLUDE_SECURITY +struct omg_security_configuration_type; +DDS_EXPORT void ddsi_xqos_mergein_security_config (dds_qos_t *xqos, const struct omg_security_configuration_type *cfg); +#endif #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_bswap.h b/src/core/ddsi/include/dds/ddsi/q_bswap.h index 93a3706..2a2dded 100644 --- a/src/core/ddsi/include/dds/ddsi/q_bswap.h +++ b/src/core/ddsi/include/dds/ddsi/q_bswap.h @@ -33,8 +33,8 @@ ddsi_guid_prefix_t nn_hton_guid_prefix (ddsi_guid_prefix_t p); ddsi_guid_prefix_t nn_ntoh_guid_prefix (ddsi_guid_prefix_t p); ddsi_entityid_t nn_hton_entityid (ddsi_entityid_t e); ddsi_entityid_t nn_ntoh_entityid (ddsi_entityid_t e); -ddsi_guid_t nn_hton_guid (ddsi_guid_t g); -ddsi_guid_t nn_ntoh_guid (ddsi_guid_t g); +DDS_EXPORT ddsi_guid_t nn_hton_guid (ddsi_guid_t g); +DDS_EXPORT ddsi_guid_t nn_ntoh_guid (ddsi_guid_t g); void bswap_sequence_number_set_hdr (nn_sequence_number_set_header_t *snset); void bswap_sequence_number_set_bitmap (nn_sequence_number_set_header_t *snset, uint32_t *bits); diff --git a/src/core/ddsi/include/dds/ddsi/q_config.h b/src/core/ddsi/include/dds/ddsi/q_config.h index fd66ad2..3c78e28 100644 --- a/src/core/ddsi/include/dds/ddsi/q_config.h +++ b/src/core/ddsi/include/dds/ddsi/q_config.h @@ -161,6 +161,42 @@ enum many_sockets_mode { MSM_MANY_UNICAST }; +#ifdef DDSI_INCLUDE_SECURITY +typedef struct plugin_library_properties_type{ + char *library_path; + char *library_init; + char *library_finalize; +} plugin_library_properties_type; + +typedef struct authentication_properties_type{ + char *identity_certificate; + char *identity_ca; + char *private_key; + char *password; + char *trusted_ca_dir; + int include_optional_fields; +} authentication_properties_type; + +typedef struct access_control_properties_type{ + char *permissions; + char *permissions_ca; + char *governance; +} access_control_properties_type; + +typedef struct omg_security_configuration_type { + authentication_properties_type authentication_properties; + access_control_properties_type access_control_properties; + plugin_library_properties_type authentication_plugin; + plugin_library_properties_type access_control_plugin; + plugin_library_properties_type cryptography_plugin; +} omg_security_configuration_type; + +struct config_omg_security_listelem { + struct config_omg_security_listelem *next; + omg_security_configuration_type cfg; +}; +#endif /* DDSI_INCLUDE_SECURITY */ + #ifdef DDSI_INCLUDE_SSL struct ssl_min_version { int major; @@ -226,8 +262,6 @@ struct config unsigned delivery_queue_maxsamples; - int do_topic_discovery; - uint32_t max_msg_size; uint32_t fragment_size; @@ -333,6 +367,10 @@ struct config int use_multicast_if_mreqn; struct prune_deleted_ppant prune_deleted_ppant; + +#ifdef DDSI_INCLUDE_SECURITY + struct config_omg_security_listelem *omg_security_configuration; +#endif }; struct cfgst; 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..3b71125 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,12 @@ struct nn_rsample_info; struct nn_rdata; struct ddsi_plist; +struct participant_builtin_topic_data_locators { + struct nn_locators_one def_uni_loc_one, def_multi_loc_one, meta_uni_loc_one, meta_multi_loc_one; +}; + +void get_participant_builtin_topic_data (const struct participant *pp, ddsi_plist_t *dst, struct participant_builtin_topic_data_locators *locs); + int spdp_write (struct participant *pp); int spdp_dispose_unregister (struct participant *pp); @@ -33,8 +39,6 @@ int sedp_write_reader (struct reader *rd); int sedp_dispose_unregister_writer (struct writer *wr); int sedp_dispose_unregister_reader (struct reader *rd); -int sedp_write_topic (struct participant *pp, const struct ddsi_plist *datap); - int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, void *qarg); #if defined (__cplusplus) diff --git a/src/core/ddsi/include/dds/ddsi/q_entity.h b/src/core/ddsi/include/dds/ddsi/q_entity.h index 956c908..ce1c7c3 100644 --- a/src/core/ddsi/include/dds/ddsi/q_entity.h +++ b/src/core/ddsi/include/dds/ddsi/q_entity.h @@ -18,11 +18,14 @@ #include "dds/ddsrt/fibheap.h" #include "dds/ddsrt/sync.h" #include "dds/ddsi/q_rtps.h" +#include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/q_protocol.h" #include "dds/ddsi/q_lat_estim.h" #include "dds/ddsi/q_hbcontrol.h" #include "dds/ddsi/q_feature_check.h" #include "dds/ddsi/q_inverse_uint32_set.h" +#include "dds/ddsi/ddsi_serdata_default.h" +#include "dds/ddsi/ddsi_handshake.h" #include "dds/ddsi/ddsi_tran.h" @@ -42,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; @@ -80,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 { @@ -91,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 { @@ -115,6 +128,7 @@ struct wr_prd_match { seqno_t min_seq; /* smallest ack'd seq nr in subtree */ seqno_t max_seq; /* sort-of highest ack'd seq nr in subtree (see augment function) */ seqno_t seq; /* highest acknowledged seq nr */ + seqno_t last_seq; /* highest seq send to this reader used when filter is applied */ int32_t num_reliable_readers_where_seq_equals_max; ddsi_guid_t arbitrary_unacked_reader; nn_count_t next_acknack; /* next acceptable acknack sequence number */ @@ -124,6 +138,9 @@ struct wr_prd_match { ddsrt_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 { @@ -142,14 +159,19 @@ struct pwr_rd_match { ddsrt_etime_t t_heartbeat_accepted; /* (local) time a heartbeat was last accepted */ ddsrt_mtime_t t_last_nack; /* (local) time we last sent a NACK */ /* FIXME: probably elapsed time is better */ seqno_t seq_last_nack; /* last seq for which we requested a retransmit */ + seqno_t last_seq; /* last known sequence number from this writer */ struct xevent *acknack_xevent; /* entry in xevent queue for sending acknacks */ enum pwr_rd_match_syncstate in_sync; /* whether in sync with the proxy writer */ + unsigned filtered:1; union { struct { seqno_t end_of_tl_seq; /* when seq >= end_of_tl_seq, it's in sync, =0 when not tl */ 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; @@ -209,8 +231,12 @@ struct participant int32_t builtin_refc; /* number of built-in endpoints in this participant [refc_lock] */ int builtins_deleted; /* whether deletion of built-in endpoints has been initiated [refc_lock] */ ddsrt_fibheap_t ldur_auto_wr; /* Heap that contains lease duration for writers with automatic liveliness in this participant */ - ddsrt_atomic_voidp_t minl_man; /* lease object for shortest manual-by-participant liveliness writer's lease */ + ddsrt_atomic_voidp_t minl_man; /* clone of min(leaseheap_man) */ ddsrt_fibheap_t leaseheap_man; /* keeps leases for this participant's writers (with liveliness manual-by-participant) */ +#ifdef DDSI_INCLUDE_SECURITY + struct participant_sec_attributes *sec_attr; + nn_security_info_t security_info; +#endif }; struct endpoint_common { @@ -257,6 +283,7 @@ struct writer unsigned reliable: 1; /* iff 1, writer is reliable <=> heartbeat_xevent != NULL */ unsigned handle_as_transient_local: 1; /* controls whether data is retained in WHC */ unsigned include_keyhash: 1; /* iff 1, this writer includes a keyhash; keyless topics => include_keyhash = 0 */ + unsigned force_md5_keyhash: 1; /* iff 1, when keyhash has to be hashed, no matter the size */ unsigned retransmitting: 1; /* iff 1, this writer is currently retransmitting */ unsigned alive: 1; /* iff 1, the writer is alive (lease for this writer is not expired); field may be modified only when holding both wr->e.lock and wr->c.pp->e.lock */ #ifdef DDSI_INCLUDE_SSM @@ -264,7 +291,7 @@ struct writer struct addrset *ssm_as; #endif uint32_t alive_vclock; /* virtual clock counting transitions between alive/not-alive */ - const struct ddsi_sertopic * topic; /* topic, but may be NULL for built-ins */ + const struct ddsi_sertopic * topic; /* topic */ struct addrset *as; /* set of addresses to publish to */ struct addrset *as_group; /* alternate case, used for SPDP, when using Cloud with multiple bootstrap locators */ struct xevent *heartbeat_xevent; /* timed event for "periodically" publishing heartbeats when unack'd data present, NULL <=> unreliable */ @@ -273,6 +300,7 @@ struct writer uint32_t whc_low, whc_high; /* watermarks for WHC in bytes (counting only unack'd data) */ ddsrt_etime_t t_rexmit_end; /* time of last 1->0 transition of "retransmitting" */ ddsrt_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 */ @@ -288,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) { @@ -319,11 +350,15 @@ struct reader #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS struct addrset *as; #endif - const struct ddsi_sertopic * topic; /* topic is NULL for built-in readers */ + const struct ddsi_sertopic * topic; /* topic */ + 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 @@ -334,9 +369,9 @@ struct proxy_participant unsigned bes; /* built-in endpoint set */ ddsi_guid_t privileged_pp_guid; /* if this PP depends on another PP for its SEDP writing */ struct ddsi_plist *plist; /* settings/QoS for this participant */ - ddsrt_atomic_voidp_t minl_auto; /* lease object for shortest automatic liveliness pwr's lease (includes this proxypp's lease) */ + ddsrt_atomic_voidp_t minl_auto; /* clone of min(leaseheap_auto) */ ddsrt_fibheap_t leaseheap_auto; /* keeps leases for this proxypp and leases for pwrs (with liveliness automatic) */ - ddsrt_atomic_voidp_t minl_man; /* lease object for shortest manual-by-participant liveliness pwr's lease */ + ddsrt_atomic_voidp_t minl_man; /* clone of min(leaseheap_man) */ ddsrt_fibheap_t leaseheap_man; /* keeps leases for this proxypp and leases for pwrs (with liveliness manual-by-participant) */ struct lease *lease; /* lease for this proxypp */ struct addrset *as_default; /* default address set to use for user data traffic */ @@ -344,7 +379,6 @@ struct proxy_participant struct proxy_endpoint_common *endpoints; /* all proxy endpoints can be reached from here */ ddsrt_avl_tree_t groups; /* table of all groups (publisher, subscriber), see struct proxy_group */ seqno_t seq; /* sequence number of most recent SPDP message */ - unsigned kernel_sequence_numbers : 1; /* whether this proxy participant generates OSPL kernel sequence numbers */ unsigned implicitly_created : 1; /* participants are implicitly created for Cloud/Fog discovered endpoints */ unsigned is_ddsi2_pp: 1; /* if this is the federation-leader on the remote node */ unsigned minimal_bes_mode: 1; @@ -352,6 +386,10 @@ struct proxy_participant unsigned deleting: 1; unsigned proxypp_have_spdp: 1; unsigned owns_lease: 1; +#ifdef DDSI_INCLUDE_SECURITY + nn_security_info_t security_info; + struct proxy_participant_sec_attributes *sec_attr; +#endif }; /* Representing proxy subscriber & publishers as "groups": until DDSI2 @@ -379,6 +417,9 @@ struct proxy_endpoint_common ddsi_guid_t group_guid; /* 0:0:0:0 if not available */ nn_vendorid_t vendor; /* cached from proxypp->vendor */ seqno_t seq; /* sequence number of most recent SEDP message */ +#ifdef DDSI_INCLUDE_SECURITY + nn_security_info_t security_info; +#endif }; struct generic_proxy_endpoint { @@ -401,6 +442,7 @@ struct proxy_writer { unsigned have_seen_heartbeat: 1; /* iff 1, we have received at least on heartbeat from this proxy writer */ unsigned local_matching_inprogress: 1; /* iff 1, we are still busy matching local readers; this is so we don't deliver incoming data to some but not all readers initially */ unsigned alive: 1; /* iff 1, the proxy writer is alive (lease for this proxy writer is not expired); field may be modified only when holding both pwr->e.lock and pwr->c.proxypp->e.lock */ + unsigned filtered: 1; /* iff 1, builtin proxy writer uses content filter, which affects heartbeats and gaps. */ #ifdef DDSI_INCLUDE_SSM unsigned supports_ssm: 1; /* iff 1, this proxy writer supports SSM */ #endif @@ -415,6 +457,9 @@ struct proxy_writer { struct lease *lease; }; + +typedef int (*filter_fn_t)(struct writer *wr, struct proxy_reader *prd, struct ddsi_serdata *serdata); + struct proxy_reader { struct entity_common e; struct proxy_endpoint_common c; @@ -424,6 +469,7 @@ struct proxy_reader { unsigned favours_ssm: 1; /* iff 1, this proxy reader favours SSM when available */ #endif ddsrt_avl_tree_t writers; /* matching LOCAL writers */ + filter_fn_t filter; }; DDS_EXPORT extern const ddsrt_avl_treedef_t wr_readers_treedef; @@ -507,8 +553,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 @@ -529,7 +575,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. @@ -596,9 +642,8 @@ DDS_EXPORT struct writer *get_builtin_writer (const struct participant *pp, unsi GUID "ppguid". May return NULL if participant unknown or writer/reader already known. */ -dds_return_t new_writer (struct writer **wr_out, struct ddsi_domaingv *gv, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg); - -dds_return_t new_reader (struct reader **rd_out, struct ddsi_domaingv *gv, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc * rhc, status_cb_t status_cb, void *status_cb_arg); +dds_return_t new_writer (struct writer **wr_out, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg); +dds_return_t new_reader (struct reader **rd_out, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc * rhc, status_cb_t status_cb, void *status_cb_arg); void update_reader_qos (struct reader *rd, const struct dds_qos *xqos); void update_writer_qos (struct writer *wr, const struct dds_qos *xqos); @@ -610,7 +655,7 @@ seqno_t writer_max_drop_seq (const struct writer *wr); int writer_must_have_hb_scheduled (const struct writer *wr, const struct whc_state *whcst); void writer_set_retransmitting (struct writer *wr); void writer_clear_retransmitting (struct writer *wr); -dds_return_t writer_wait_for_acks (struct writer *wr, dds_time_t abstimeout); +dds_return_t writer_wait_for_acks (struct writer *wr, const ddsi_guid_t *rdguid, dds_time_t abstimeout); dds_return_t unblock_throttled_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *guid); dds_return_t delete_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *guid); @@ -638,22 +683,20 @@ int writer_set_notalive (struct writer *wr, bool notify); XX -- */ -/* Set this custom flag when using nn_adlink_writer_info_t iso nn_adlink_writer_info_old_t */ -#define CF_INC_KERNEL_SEQUENCE_NUMBERS (1 << 0) /* Set when this proxy participant is created implicitly and has to be deleted upon disappearance of its last endpoint. FIXME: Currently there is a potential race with adding a new endpoint in parallel to deleting the last remaining one. The endpoint will then be created, added to the proxy participant and then both are deleted. With the current single-threaded discovery this can only happen when it is all triggered by lease expiry. */ -#define CF_IMPLICITLY_CREATED_PROXYPP (1 << 1) +#define CF_IMPLICITLY_CREATED_PROXYPP (1 << 0) /* Set when this proxy participant is a DDSI2 participant, to help Cloud figure out whom to send discovery data when used in conjunction with the networking bridge */ -#define CF_PARTICIPANT_IS_DDSI2 (1 << 2) +#define CF_PARTICIPANT_IS_DDSI2 (1 << 1) /* Set when this proxy participant is not to be announced on the built-in topics yet */ -#define CF_PROXYPP_NO_SPDP (1 << 3) +#define CF_PROXYPP_NO_SPDP (1 << 2) -void new_proxy_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *guid, uint32_t bes, const struct ddsi_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const struct ddsi_plist *plist, dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, ddsrt_wctime_t timestamp, seqno_t seq); -int delete_proxy_participant_by_guid (struct ddsi_domaingv *gv, const struct ddsi_guid *guid, ddsrt_wctime_t timestamp, int isimplicit); +bool new_proxy_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *guid, uint32_t bes, const struct ddsi_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const struct ddsi_plist *plist, dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, ddsrt_wctime_t timestamp, seqno_t seq); +DDS_EXPORT int delete_proxy_participant_by_guid (struct ddsi_domaingv *gv, const struct ddsi_guid *guid, ddsrt_wctime_t timestamp, int isimplicit); int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, seqno_t seq, const struct ddsi_plist *datap, ddsrt_wctime_t timestamp); int update_proxy_participant_plist (struct proxy_participant *proxypp, seqno_t seq, const struct ddsi_plist *datap, ddsrt_wctime_t timestamp); @@ -696,6 +739,10 @@ 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, ddsrt_mtime_t tnow, int64_t crypto_handle); +void connect_reader_with_proxy_writer_secure(struct reader *rd, struct proxy_writer *pwr, ddsrt_mtime_t tnow, int64_t crypto_handle); + + struct ddsi_writer_info; DDS_EXPORT void ddsi_make_writer_info(struct ddsi_writer_info *wrinfo, const struct entity_common *e, const struct dds_qos *xqos, uint32_t statusinfo); diff --git a/src/core/ddsi/include/dds/ddsi/q_hbcontrol.h b/src/core/ddsi/include/dds/ddsi/q_hbcontrol.h index 389e29a..0860196 100644 --- a/src/core/ddsi/include/dds/ddsi/q_hbcontrol.h +++ b/src/core/ddsi/include/dds/ddsi/q_hbcontrol.h @@ -18,6 +18,7 @@ extern "C" { struct writer; struct whc_state; +struct proxy_reader; struct hbcontrol { ddsrt_mtime_t t_of_last_write; @@ -36,6 +37,11 @@ struct nn_xmsg *writer_hbcontrol_piggyback (struct writer *wr, const struct whc_ int writer_hbcontrol_must_send (const struct writer *wr, const struct whc_state *whcst, ddsrt_mtime_t tnow); struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const struct whc_state *whcst, ddsrt_mtime_t tnow, int hbansreq, int issync); +#ifdef DDSI_INCLUDE_SECURITY +struct nn_xmsg *writer_hbcontrol_p2p(struct writer *wr, const struct whc_state *whcst, int hbansreq, struct proxy_reader *prd); +#endif + + #if defined (__cplusplus) } #endif diff --git a/src/core/ddsi/include/dds/ddsi/q_lease.h b/src/core/ddsi/include/dds/ddsi/q_lease.h index e427cc0..9614386 100644 --- a/src/core/ddsi/include/dds/ddsi/q_lease.h +++ b/src/core/ddsi/include/dds/ddsi/q_lease.h @@ -28,8 +28,8 @@ struct ddsi_domaingv; /* FIXME: make a special for the lease admin */ struct lease { ddsrt_fibheap_node_t heapnode; ddsrt_fibheap_node_t pp_heapnode; - ddsrt_etime_t tsched; /* access guarded by leaseheap_lock */ - ddsrt_atomic_uint64_t tend; /* really an nn_etime_t */ + ddsrt_etime_t tsched; /* access guarded by leaseheap_lock */ + ddsrt_atomic_uint64_t tend; /* really an ddsrt_etime_t */ dds_duration_t tdur; /* constant (renew depends on it) */ struct entity_common *entity; /* constant */ }; diff --git a/src/core/ddsi/include/dds/ddsi/q_misc.h b/src/core/ddsi/include/dds/ddsi/q_misc.h index cb67ef5..98a7457 100644 --- a/src/core/ddsi/include/dds/ddsi/q_misc.h +++ b/src/core/ddsi/include/dds/ddsi/q_misc.h @@ -35,7 +35,10 @@ unsigned char normalize_data_datafrag_flags (const SubmessageHeader_t *smhdr); int WildcardOverlap(char * p1, char * p2); #endif -int ddsi2_patmatch (const char *pat, const char *str); +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); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_protocol.h b/src/core/ddsi/include/dds/ddsi/q_protocol.h index 4556ee1..688a8a1 100644 --- a/src/core/ddsi/include/dds/ddsi/q_protocol.h +++ b/src/core/ddsi/include/dds/ddsi/q_protocol.h @@ -89,13 +89,21 @@ typedef struct { #define NN_DISC_BUILTIN_ENDPOINT_TOPIC_ANNOUNCER (1u << 12) #define NN_DISC_BUILTIN_ENDPOINT_TOPIC_DETECTOR (1u << 13) -/* Adlink extensions: */ -#define NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_WRITER (1u << 0) -#define NN_DISC_BUILTIN_ENDPOINT_CM_PARTICIPANT_READER (1u << 1) -#define NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_WRITER (1u << 2) -#define NN_DISC_BUILTIN_ENDPOINT_CM_PUBLISHER_READER (1u << 3) -#define NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_WRITER (1u << 4) -#define NN_DISC_BUILTIN_ENDPOINT_CM_SUBSCRIBER_READER (1u << 5) +/* Security extensions: */ +#define NN_BUILTIN_ENDPOINT_PUBLICATION_MESSAGE_SECURE_ANNOUNCER (1u<<16) +#define NN_BUILTIN_ENDPOINT_PUBLICATION_MESSAGE_SECURE_DETECTOR (1u<<17) +#define NN_BUILTIN_ENDPOINT_SUBSCRIPTION_MESSAGE_SECURE_ANNOUNCER (1u<<18) +#define NN_BUILTIN_ENDPOINT_SUBSCRIPTION_MESSAGE_SECURE_DETECTOR (1u<<19) +#define NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_SECURE_ANNOUNCER (1u<<20) +#define NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_SECURE_DETECTOR (1u<<21) +#define NN_BUILTIN_ENDPOINT_PARTICIPANT_STATELESS_MESSAGE_ANNOUNCER (1u<<22) +#define NN_BUILTIN_ENDPOINT_PARTICIPANT_STATELESS_MESSAGE_DETECTOR (1u<<23) +#define NN_BUILTIN_ENDPOINT_PARTICIPANT_VOLATILE_SECURE_ANNOUNCER (1u<<24) +#define NN_BUILTIN_ENDPOINT_PARTICIPANT_VOLATILE_SECURE_DETECTOR (1u<<25) +#define NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_SECURE_ANNOUNCER (1u << 26) +#define NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_SECURE_DETECTOR (1u << 27) + +#define NN_BES_MASK_NON_SECURITY 0xf000ffffu #define NN_LOCATOR_KIND_INVALID -1 #define NN_LOCATOR_KIND_RESERVED 0 @@ -149,6 +157,12 @@ typedef enum SubmessageKind { SMID_HEARTBEAT_FRAG = 0x13, SMID_DATA = 0x15, SMID_DATA_FRAG = 0x16, + /* security-specific sub messages */ + SMID_SEC_BODY = 0x30, + SMID_SEC_PREFIX = 0x31, + SMID_SEC_POSTFIX = 0x32, + SMID_SRTPS_PREFIX = 0x33, + SMID_SRTPS_POSTFIX = 0x34, /* vendor-specific sub messages (0x80 .. 0xff) */ SMID_ADLINK_MSG_LEN = 0x81, SMID_ADLINK_ENTITY_ID = 0x82 @@ -189,7 +203,7 @@ typedef uint16_t nn_parameterid_t; /* spec says short */ typedef struct nn_parameter { nn_parameterid_t parameterid; uint16_t length; /* spec says signed short */ - /* char value[]; O! how I long for C99 */ + /* char value[] */ } nn_parameter_t; typedef struct Data_DataFrag_common { @@ -304,18 +318,10 @@ typedef union Submessage { NackFrag_t nackfrag; } Submessage_t; -DDSRT_WARNING_MSVC_OFF(4200) -typedef struct ParticipantMessageData { - ddsi_guid_prefix_t participantGuidPrefix; - uint32_t kind; /* really 4 octets */ - uint32_t length; - char value[]; -} ParticipantMessageData_t; -DDSRT_WARNING_MSVC_ON(4200) #define PARTICIPANT_MESSAGE_DATA_KIND_UNKNOWN 0x0u #define PARTICIPANT_MESSAGE_DATA_KIND_AUTOMATIC_LIVELINESS_UPDATE 0x1u #define PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE 0x2u -#define PARTICIPANT_MESSAGE_DATA_VENDER_SPECIFIC_KIND_FLAG 0x8000000u +#define PARTICIPANT_MESSAGE_DATA_VENDOR_SPECIFIC_KIND_FLAG 0x8000000u #define PID_VENDORSPECIFIC_FLAG 0x8000u #define PID_UNRECOGNIZED_INCOMPATIBLE_FLAG 0x4000u @@ -384,6 +390,10 @@ DDSRT_WARNING_MSVC_ON(4200) /* Security related PID values. */ #define PID_IDENTITY_TOKEN 0x1001u #define PID_PERMISSIONS_TOKEN 0x1002u +#define PID_DATA_TAGS 0x1003u +#define PID_ENDPOINT_SECURITY_INFO 0x1004u +#define PID_PARTICIPANT_SECURITY_INFO 0x1005u +#define PID_IDENTITY_STATUS_TOKEN 0x1006u #ifdef DDSI_INCLUDE_SSM /* To indicate whether a reader favours the use of SSM. Iff the diff --git a/src/core/ddsi/include/dds/ddsi/q_radmin.h b/src/core/ddsi/include/dds/ddsi/q_radmin.h index 1cdeace..d32168a 100644 --- a/src/core/ddsi/include/dds/ddsi/q_radmin.h +++ b/src/core/ddsi/include/dds/ddsi/q_radmin.h @@ -110,10 +110,11 @@ whichever is larger. */ #define ALIGNOF_RMSG (sizeof(void *) > 8 ? sizeof(void *) : 8) struct receiver_state { - ddsi_guid_prefix_t src_guid_prefix; /* 12 */ - ddsi_guid_prefix_t dst_guid_prefix; /* 12 */ + ddsi_guid_prefix_t src_guid_prefix; /* 12 */ + ddsi_guid_prefix_t dst_guid_prefix; /* 12 */ struct addrset *reply_locators; /* 4/8 */ - int forme; /* 4 */ + uint32_t forme:1; /* 4 */ + uint32_t rtps_encoded:1; /* - */ nn_vendorid_t vendor; /* 2 */ nn_protocol_version_t protocol_version; /* 2 => 44/48 */ ddsi_tran_conn_t conn; /* Connection for request */ @@ -223,6 +224,7 @@ void nn_defrag_free (struct nn_defrag *defrag); struct nn_rsample *nn_defrag_rsample (struct nn_defrag *defrag, struct nn_rdata *rdata, const struct nn_rsample_info *sampleinfo); void nn_defrag_notegap (struct nn_defrag *defrag, seqno_t min, seqno_t maxp1); int nn_defrag_nackmap (struct nn_defrag *defrag, seqno_t seq, uint32_t maxfragnum, struct nn_fragment_number_set_header *map, uint32_t *mapbits, uint32_t maxsz); +void nn_defrag_prune (struct nn_defrag *defrag, ddsi_guid_prefix_t *dst, seqno_t min); struct nn_reorder *nn_reorder_new (const struct ddsrt_log_cfg *logcfg, enum nn_reorder_mode mode, uint32_t max_samples, bool late_ack_mode); void nn_reorder_free (struct nn_reorder *r); @@ -233,6 +235,7 @@ nn_reorder_result_t nn_reorder_gap (struct nn_rsample_chain *sc, struct nn_reord int nn_reorder_wantsample (struct nn_reorder *reorder, seqno_t seq); unsigned nn_reorder_nackmap (struct nn_reorder *reorder, seqno_t base, seqno_t maxseq, struct nn_sequence_number_set_header *map, uint32_t *mapbits, uint32_t maxsz, int notail); seqno_t nn_reorder_next_seq (const struct nn_reorder *reorder); +void nn_reorder_set_next_seq (struct nn_reorder *reorder, seqno_t seq); struct nn_dqueue *nn_dqueue_new (const char *name, const struct ddsi_domaingv *gv, uint32_t max_samples, nn_dqueue_handler_t handler, void *arg); void nn_dqueue_free (struct nn_dqueue *q); diff --git a/src/core/ddsi/include/dds/ddsi/q_receive.h b/src/core/ddsi/include/dds/ddsi/q_receive.h index 617b563..bc6942e 100644 --- a/src/core/ddsi/include/dds/ddsi/q_receive.h +++ b/src/core/ddsi/include/dds/ddsi/q_receive.h @@ -21,11 +21,25 @@ struct nn_rsample_info; struct nn_rdata; struct ddsi_tran_listener; struct recv_thread_arg; +struct writer; +struct proxy_reader; + +struct nn_gap_info { + int64_t gapstart; + int64_t gapend; + unsigned gapnumbits; + unsigned gapbits[256 / 32]; +}; + +void nn_gap_info_init(struct nn_gap_info *gi); +void nn_gap_info_update(struct ddsi_domaingv *gv, struct nn_gap_info *gi, int64_t seqnr); +struct nn_xmsg * nn_gap_info_create_gap(struct writer *wr, struct proxy_reader *prd, struct nn_gap_info *gi); void trigger_recv_threads (const struct ddsi_domaingv *gv); uint32_t recv_thread (void *vrecv_thread_arg); uint32_t listen_thread (struct ddsi_tran_listener * listener); int user_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, const ddsi_guid_t *rdguid, void *qarg); +int add_Gap (struct nn_xmsg *msg, struct writer *wr, struct proxy_reader *prd, seqno_t start, seqno_t base, uint32_t numbits, const uint32_t *bits); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_rtps.h b/src/core/ddsi/include/dds/ddsi/q_rtps.h index 47dc332..a75cf28 100644 --- a/src/core/ddsi/include/dds/ddsi/q_rtps.h +++ b/src/core/ddsi/include/dds/ddsi/q_rtps.h @@ -45,6 +45,20 @@ typedef int64_t seqno_t; #define NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER 0x100c7 #define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER 0x200c2 #define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER 0x200c7 + +#define NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER 0xff0003c2 +#define NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_READER 0xff0003c7 +#define NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER 0xff0004c2 +#define NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER 0xff0004c7 +#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER 0x201c3 +#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER 0x201c4 +#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER 0xff0200c2 +#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER 0xff0200c7 +#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER 0xff0202c3 +#define NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER 0xff0202c4 +#define NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER 0xff0101c2 +#define NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_READER 0xff0101c7 + #define NN_ENTITYID_SOURCE_MASK 0xc0 #define NN_ENTITYID_SOURCE_USER 0x00 #define NN_ENTITYID_SOURCE_BUILTIN 0xc0 diff --git a/src/core/ddsi/include/dds/ddsi/q_transmit.h b/src/core/ddsi/include/dds/ddsi/q_transmit.h index d2610a5..62feeda 100644 --- a/src/core/ddsi/include/dds/ddsi/q_transmit.h +++ b/src/core/ddsi/include/dds/ddsi/q_transmit.h @@ -44,6 +44,7 @@ dds_return_t create_fragment_message (struct writer *wr, seqno_t seq, const stru int enqueue_sample_wrlock_held (struct writer *wr, seqno_t seq, const struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct proxy_reader *prd, int isnew); void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, int hbliveliness, ddsi_entityid_t dst, int issync); dds_return_t write_hb_liveliness (struct ddsi_domaingv * const gv, struct ddsi_guid *wr_guid, struct nn_xpack *xp); +int write_sample_p2p_wrlock_held(struct writer *wr, seqno_t seq, struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk, struct proxy_reader *prd); #if defined (__cplusplus) } diff --git a/src/core/ddsi/include/dds/ddsi/q_xevent.h b/src/core/ddsi/include/dds/ddsi/q_xevent.h index 41bd5b1..96b9345 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, ddsi_guid_prefix_t * id); -DDS_EXPORT void qxev_prd_entityid (struct proxy_reader * prd, ddsi_guid_prefix_t * id); + +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 af2b937..0a282fe 100644 --- a/src/core/ddsi/include/dds/ddsi/q_xmsg.h +++ b/src/core/ddsi/include/dds/ddsi/q_xmsg.h @@ -26,6 +26,8 @@ struct ddsi_serdata; struct addrset; struct proxy_reader; struct proxy_writer; +struct writer; +struct participant; struct nn_adlink_participant_version_info; struct nn_xmsgpool; @@ -41,7 +43,8 @@ struct nn_xmsg_marker { enum nn_xmsg_kind { NN_XMSG_KIND_CONTROL, NN_XMSG_KIND_DATA, - NN_XMSG_KIND_DATA_REXMIT + NN_XMSG_KIND_DATA_REXMIT, + NN_XMSG_KIND_DATA_REXMIT_NOMERGE }; /* XMSGPOOL */ @@ -54,10 +57,11 @@ void nn_xmsgpool_free (struct nn_xmsgpool *pool); /* To allocate a new xmsg from the pool; if expected_size is NOT exceeded, no reallocs will be performed, else the address of the xmsg may change because of reallocing when appending to it. */ -struct nn_xmsg *nn_xmsg_new (struct nn_xmsgpool *pool, const ddsi_guid_prefix_t *src_guid_prefix, size_t expected_size, enum nn_xmsg_kind kind); +struct nn_xmsg *nn_xmsg_new (struct nn_xmsgpool *pool, const ddsi_guid_t *src_guid, struct participant *pp, size_t expected_size, enum nn_xmsg_kind kind); /* For sending to a particular destination (participant) */ -void nn_xmsg_setdst1 (struct nn_xmsg *m, const ddsi_guid_prefix_t *gp, const nn_locator_t *addr); +void nn_xmsg_setdst1 (struct ddsi_domaingv *gv, struct nn_xmsg *m, const ddsi_guid_prefix_t *gp, const nn_locator_t *addr); +bool nn_xmsg_getdst1prefix (struct nn_xmsg *m, ddsi_guid_prefix_t *gp); /* For sending to a particular proxy reader; this is a convenience routine that extracts a suitable address from the proxy reader's @@ -114,15 +118,23 @@ void nn_xmsg_guid_seq_fragid (const struct nn_xmsg *m, ddsi_guid_t *wrguid, seqn void *nn_xmsg_submsg_from_marker (struct nn_xmsg *msg, struct nn_xmsg_marker marker); void *nn_xmsg_append (struct nn_xmsg *m, struct nn_xmsg_marker *marker, size_t sz); void nn_xmsg_shrink (struct nn_xmsg *m, struct nn_xmsg_marker marker, size_t sz); -void nn_xmsg_serdata (struct nn_xmsg *m, struct ddsi_serdata *serdata, size_t off, size_t len); +void nn_xmsg_serdata (struct nn_xmsg *m, struct ddsi_serdata *serdata, size_t off, size_t len, struct writer *wr); +#ifdef DDSI_INCLUDE_SECURITY +size_t nn_xmsg_submsg_size (struct nn_xmsg *msg, struct nn_xmsg_marker marker); +void nn_xmsg_submsg_remove (struct nn_xmsg *msg, struct nn_xmsg_marker sm_marker); +void nn_xmsg_submsg_replace (struct nn_xmsg *msg, struct nn_xmsg_marker sm_marker, unsigned char *new_submsg, size_t new_len); +void nn_xmsg_submsg_append_refd_payload (struct nn_xmsg *msg, struct nn_xmsg_marker sm_marker); +#endif 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, ddsrt_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); +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_cdrstream.c b/src/core/ddsi/src/ddsi_cdrstream.c index 9fffea9..9556766 100644 --- a/src/core/ddsi/src/ddsi_cdrstream.c +++ b/src/core/ddsi/src/ddsi_cdrstream.c @@ -364,7 +364,8 @@ static void dds_stream_countops1 (const uint32_t * __restrict ops, const uint32_ break; } case DDS_OP_JSR: { - dds_stream_countops1 (ops + DDS_OP_JUMP (insn), ops_end); + if (DDS_OP_JUMP (insn) > 0) + dds_stream_countops1 (ops + DDS_OP_JUMP (insn), ops_end); ops++; break; } @@ -1909,7 +1910,10 @@ void dds_stream_extract_keyhash (dds_istream_t * __restrict is, dds_keyhash_t * const struct ddsi_sertopic_default_desc *desc = &topic->type; kh->m_set = 1; if (desc->m_nkeys == 0) + { kh->m_iskey = 1; + kh->m_keysize = 0; + } else if (desc->m_flagset & DDS_TOPIC_FIXED_KEY) { dds_ostreamBE_t os; @@ -1922,12 +1926,14 @@ void dds_stream_extract_keyhash (dds_istream_t * __restrict is, dds_keyhash_t * else dds_stream_extract_keyBE_from_data (is, &os, topic); assert (os.x.m_index <= 16); + kh->m_keysize = (unsigned)os.x.m_index & 0x1f; } else { dds_ostreamBE_t os; ddsrt_md5_state_t md5st; kh->m_iskey = 0; + kh->m_keysize = 16; dds_ostreamBE_init (&os, 0); if (just_key) dds_stream_extract_keyBE_from_key (is, &os, topic); @@ -1990,14 +1996,42 @@ static size_t isprint_runlen (const unsigned char *s, size_t n) return m; } -static bool prtf_simple (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, enum dds_stream_typecode type) +static bool prtf_simple (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, enum dds_stream_typecode type, unsigned flags) { switch (type) { - case DDS_OP_VAL_1BY: return prtf (buf, bufsize, "%"PRIu8, dds_is_get1 (is)); - case DDS_OP_VAL_2BY: return prtf (buf, bufsize, "%"PRIu16, dds_is_get2 (is)); - case DDS_OP_VAL_4BY: return prtf (buf, bufsize, "%"PRIu32, dds_is_get4 (is)); - case DDS_OP_VAL_8BY: return prtf (buf, bufsize, "%"PRIu64, dds_is_get8 (is)); + case DDS_OP_VAL_1BY: { + const union { int8_t s; uint8_t u; } x = { .u = dds_is_get1 (is) }; + if (flags & DDS_OP_FLAG_SGN) + return prtf (buf, bufsize, "%"PRId8, x.s); + else + return prtf (buf, bufsize, "%"PRIu8, x.u); + } + case DDS_OP_VAL_2BY: { + const union { int16_t s; uint16_t u; } x = { .u = dds_is_get2 (is) }; + if (flags & DDS_OP_FLAG_SGN) + return prtf (buf, bufsize, "%"PRId16, x.s); + else + return prtf (buf, bufsize, "%"PRIu16, x.u); + } + case DDS_OP_VAL_4BY: { + const union { int32_t s; uint32_t u; float f; } x = { .u = dds_is_get4 (is) }; + if (flags & DDS_OP_FLAG_FP) + return prtf (buf, bufsize, "%g", x.f); + else if (flags & DDS_OP_FLAG_SGN) + return prtf (buf, bufsize, "%"PRId32, x.s); + else + return prtf (buf, bufsize, "%"PRIu32, x.u); + } + case DDS_OP_VAL_8BY: { + const union { int64_t s; uint64_t u; double f; } x = { .u = dds_is_get8 (is) }; + if (flags & DDS_OP_FLAG_FP) + return prtf (buf, bufsize, "%g", x.f); + else if (flags & DDS_OP_FLAG_SGN) + return prtf (buf, bufsize, "%"PRId64, x.s); + else + return prtf (buf, bufsize, "%"PRIu64, x.u); + } case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: return prtf_str (buf, bufsize, is); case DDS_OP_VAL_ARR: case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: abort (); @@ -2005,7 +2039,7 @@ static bool prtf_simple (char * __restrict *buf, size_t * __restrict bufsize, dd return false; } -static bool prtf_simple_array (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, uint32_t num, enum dds_stream_typecode type) +static bool prtf_simple_array (char * __restrict *buf, size_t * __restrict bufsize, dds_istream_t * __restrict is, uint32_t num, enum dds_stream_typecode type, unsigned flags) { bool cont = prtf (buf, bufsize, "{"); switch (type) @@ -2028,7 +2062,7 @@ static bool prtf_simple_array (char * __restrict *buf, size_t * __restrict bufsi { if (i != 0) (void) prtf (buf, bufsize, ","); - cont = prtf_simple (buf, bufsize, is, type); + cont = prtf_simple (buf, bufsize, is, type, flags); i++; } } @@ -2040,7 +2074,7 @@ static bool prtf_simple_array (char * __restrict *buf, size_t * __restrict bufsi { if (i != 0) (void) prtf (buf, bufsize, ","); - cont = prtf_simple (buf, bufsize, is, type); + cont = prtf_simple (buf, bufsize, is, type, flags); } break; default: @@ -2065,10 +2099,10 @@ static const uint32_t *prtf_seq (char * __restrict *buf, size_t *bufsize, dds_is switch (subtype) { case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: - (void) prtf_simple_array (buf, bufsize, is, num, subtype); + (void) prtf_simple_array (buf, bufsize, is, num, subtype, DDS_OP_FLAGS (insn)); return ops + 2; case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: - (void) prtf_simple_array (buf, bufsize, is, num, subtype); + (void) prtf_simple_array (buf, bufsize, is, num, subtype, DDS_OP_FLAGS (insn)); return ops + (subtype == DDS_OP_VAL_STR ? 2 : 3); case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: { const uint32_t jmp = DDS_OP_ADR_JMP (ops[3]); @@ -2093,10 +2127,10 @@ static const uint32_t *prtf_arr (char * __restrict *buf, size_t *bufsize, dds_is switch (subtype) { case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: - (void) prtf_simple_array (buf, bufsize, is, num, subtype); + (void) prtf_simple_array (buf, bufsize, is, num, subtype, DDS_OP_FLAGS (insn)); return ops + 3; case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: - (void) prtf_simple_array (buf, bufsize, is, num, subtype); + (void) prtf_simple_array (buf, bufsize, is, num, subtype, DDS_OP_FLAGS (insn)); return ops + (subtype == DDS_OP_VAL_STR ? 3 : 5); case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: { const uint32_t *jsr_ops = ops + DDS_OP_ADR_JSR (ops[3]); @@ -2127,7 +2161,7 @@ static const uint32_t *prtf_uni (char * __restrict *buf, size_t *bufsize, dds_is { case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: - (void) prtf_simple (buf, bufsize, is, valtype); + (void) prtf_simple (buf, bufsize, is, valtype, DDS_OP_FLAGS (jeq_op[0])); break; case DDS_OP_VAL_SEQ: case DDS_OP_VAL_ARR: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: (void) dds_stream_print_sample1 (buf, bufsize, is, jeq_op + DDS_OP_ADR_JSR (jeq_op[0]), valtype == DDS_OP_VAL_STU); @@ -2156,11 +2190,11 @@ static bool dds_stream_print_sample1 (char * __restrict *buf, size_t * __restric { case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: case DDS_OP_VAL_STR: - cont = prtf_simple (buf, bufsize, is, DDS_OP_TYPE (insn)); + cont = prtf_simple (buf, bufsize, is, DDS_OP_TYPE (insn), DDS_OP_FLAGS (insn)); ops += 2; break; case DDS_OP_VAL_BST: - cont = prtf_simple (buf, bufsize, is, DDS_OP_TYPE (insn)); + cont = prtf_simple (buf, bufsize, is, DDS_OP_TYPE (insn), DDS_OP_FLAGS (insn)); ops += 3; break; case DDS_OP_VAL_SEQ: @@ -2212,10 +2246,10 @@ size_t dds_stream_print_key (dds_istream_t * __restrict is, const struct ddsi_se { case DDS_OP_VAL_1BY: case DDS_OP_VAL_2BY: case DDS_OP_VAL_4BY: case DDS_OP_VAL_8BY: case DDS_OP_VAL_STR: case DDS_OP_VAL_BST: - cont = prtf_simple (&buf, &bufsize, is, DDS_OP_TYPE (*op)); + cont = prtf_simple (&buf, &bufsize, is, DDS_OP_TYPE (*op), DDS_OP_FLAGS (*op)); break; case DDS_OP_VAL_ARR: - cont = prtf_simple_array (&buf, &bufsize, is, op[2], DDS_OP_SUBTYPE (*op)); + cont = prtf_simple_array (&buf, &bufsize, is, op[2], DDS_OP_SUBTYPE (*op), DDS_OP_FLAGS (*op)); break; case DDS_OP_VAL_SEQ: case DDS_OP_VAL_UNI: case DDS_OP_VAL_STU: abort (); diff --git a/src/core/ddsi/src/ddsi_deadline.c b/src/core/ddsi/src/ddsi_deadline.c index 3c07034..9871462 100644 --- a/src/core/ddsi/src/ddsi_deadline.c +++ b/src/core/ddsi/src/ddsi_deadline.c @@ -25,8 +25,8 @@ static void instance_deadline_missed_cb (struct xevent *xev, void *varg, ddsrt_m /* Gets the instance from the list in deadline admin that has the earliest missed deadline and * removes the instance element from the list. If no more instances with missed deadline exist - * in the list, the deadline (nn_mtime_t) for the first instance to 'expire' is returned. If the - * list is empty, DDSRT_MTIME_NEVER is returned */ + * in the list, the deadline (ddsrt_mtime_t) for the first instance to 'expire' is returned. If + * the list is empty, DDSRT_MTIME_NEVER is returned */ ddsrt_mtime_t deadline_next_missed_locked (struct deadline_adm *deadline_adm, ddsrt_mtime_t tnow, void **instance) { struct deadline_elem *elem = NULL; diff --git a/src/core/ddsi/src/ddsi_entity_index.c b/src/core/ddsi/src/ddsi_entity_index.c index 7183a30..fd40aae 100644 --- a/src/core/ddsi/src/ddsi_entity_index.c +++ b/src/core/ddsi/src/ddsi_entity_index.c @@ -70,20 +70,6 @@ static int entity_guid_eq_wrapper (const void *a, const void *b) return entity_guid_eq (a, b); } -static int all_entities_compare_isbuiltin (const struct entity_common *e, nn_vendorid_t vendor) -{ - const unsigned char *guid_bytes = (const unsigned char *) &e->guid; - if (guid_bytes[0] != 0 && guid_bytes[0] != 0xff) - return is_builtin_endpoint (e->guid.entityid, vendor); - else - { - for (size_t i = 1; i < sizeof (e->guid); i++) - if (guid_bytes[i] != guid_bytes[0]) - return is_builtin_endpoint (e->guid.entityid, vendor) && !is_local_orphan_endpoint (e); - return 0; - } -} - static int all_entities_compare (const void *va, const void *vb) { const struct entity_common *a = va; @@ -104,28 +90,20 @@ static int all_entities_compare (const void *va, const void *vb) case EK_WRITER: { const struct writer *wra = va; const struct writer *wrb = vb; - if (!all_entities_compare_isbuiltin (a, NN_VENDORID_ECLIPSE)) { - assert ((wra->xqos->present & QP_TOPIC_NAME) && wra->xqos->topic_name); - tp_a = wra->xqos->topic_name; - } - if (!all_entities_compare_isbuiltin (b, NN_VENDORID_ECLIPSE)) { - assert ((wrb->xqos->present & QP_TOPIC_NAME) && wrb->xqos->topic_name); - tp_b = wrb->xqos->topic_name; - } + assert ((wra->xqos->present & QP_TOPIC_NAME) && wra->xqos->topic_name); + assert ((wrb->xqos->present & QP_TOPIC_NAME) && wrb->xqos->topic_name); + tp_a = wra->xqos->topic_name; + tp_b = wrb->xqos->topic_name; break; } case EK_READER: { const struct reader *rda = va; const struct reader *rdb = vb; - if (!all_entities_compare_isbuiltin (a, NN_VENDORID_ECLIPSE)) { - assert ((rda->xqos->present & QP_TOPIC_NAME) && rda->xqos->topic_name); - tp_a = rda->xqos->topic_name; - } - if (!all_entities_compare_isbuiltin (b, NN_VENDORID_ECLIPSE)) { - assert ((rdb->xqos->present & QP_TOPIC_NAME) && rdb->xqos->topic_name); - tp_b = rdb->xqos->topic_name; - } + assert ((rda->xqos->present & QP_TOPIC_NAME) && rda->xqos->topic_name); + assert ((rdb->xqos->present & QP_TOPIC_NAME) && rdb->xqos->topic_name); + tp_a = rda->xqos->topic_name; + tp_b = rdb->xqos->topic_name; break; } @@ -133,14 +111,11 @@ static int all_entities_compare (const void *va, const void *vb) case EK_PROXY_READER: { const struct generic_proxy_endpoint *ga = va; const struct generic_proxy_endpoint *gb = vb; - if (!all_entities_compare_isbuiltin (a, ga->c.vendor)) { - assert ((ga->c.xqos->present & QP_TOPIC_NAME) && ga->c.xqos->topic_name); + /* built-in reader/writer proxies don't have topic name set */ + if (ga->c.xqos->present & QP_TOPIC_NAME) tp_a = ga->c.xqos->topic_name; - } - if (!all_entities_compare_isbuiltin (b, gb->c.vendor)) { - assert ((gb->c.xqos->present & QP_TOPIC_NAME) && gb->c.xqos->topic_name); + if (gb->c.xqos->present & QP_TOPIC_NAME) tp_b = gb->c.xqos->topic_name; - } break; } } @@ -439,6 +414,18 @@ void entidx_enum_init_topic (struct entidx_enum *st, const struct entity_index * st->cur = NULL; } +void entidx_enum_init_topic_w_prefix (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind, const char *topic, const ddsi_guid_prefix_t *prefix, struct match_entities_range_key *max) +{ + assert (kind == EK_READER || kind == EK_WRITER || kind == EK_PROXY_READER || kind == EK_PROXY_WRITER); + struct match_entities_range_key min; + match_endpoint_range (kind, topic, &min, max); + min.entity.e.guid.prefix = *prefix; + max->entity.e.guid.prefix = *prefix; + entidx_enum_init_minmax_int (st, ei, &min); + if (st->cur && all_entities_compare (st->cur, &max->entity) > 0) + st->cur = NULL; +} + void entidx_enum_init (struct entidx_enum *st, const struct entity_index *ei, enum entity_kind kind) { struct match_entities_range_key min; diff --git a/src/core/ddsi/src/ddsi_handshake.c b/src/core/ddsi/src/ddsi_handshake.c new file mode 100644 index 0000000..72da225 --- /dev/null +++ b/src/core/ddsi/src/ddsi_handshake.c @@ -0,0 +1,1302 @@ +/* + * 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 + */ + +#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/ddsi/q_gc.h" +#include "dds/security/dds_security_api_types.h" +#include "dds/security/dds_security_api.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; + 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; + DDS_Security_HandshakeMessageToken *handshake_message_out; + DDS_Security_AuthRequestMessageToken local_auth_request_token; + DDS_Security_AuthRequestMessageToken *remote_auth_request_token; + DDS_Security_OctetSeq pdata; + int64_t shared_secret; +}; + +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) +#define INITIAL_DELAY DDS_MSECS(10) + +static void func_validate_remote_and_begin_reply (struct dds_security_fsm *fsm, void *arg); +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_initial_delay = { NULL, INITIAL_DELAY }; +static dds_security_fsm_state state_validate_remote_and_begin_reply = { func_validate_remote_and_begin_reply, 0 }; +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_initial_delay) state = "state_initial_delay"; + else if (current == &state_validate_remote_and_begin_reply) state = "state_validate_remote_and_begin_reply"; + 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 + + +/************************************************************************************************************ + [START] + | + .---------------------. .----------------------------------------. + | state_initial_delay | | state_validate_remote_and_begin_reply | + |---------------------|------------------------------->|----------------------------------------|------------------. + | initial_delay | RECEIVED_MESSAGE_REQUEST | func_validate_remote_and_begin_reply() | | + '---------------------' '----------------------------------------' | + | VALIDATION_PENDING_RETRY + TIMEOUT VALIDATION_PENDING_HANDSHAKE_MESSAGE + | VALIDATION_OK + v VALIDATION_FAILED + .---------------------------------. | + | 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_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 | | | | VALIDATION_PENDING_HANDSHAKE_MESSAGE | + | | | | | '-----------------------------------------------------| + | | 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 | VALIDATION_OK | + [END] | [END] | | + | | | + | VALIDATION_FAILED | | + '---------------------------------------------------------------------------------------------------' + + .----------------------------------------. + | state_begin_handshake_reply_retry_wait | + |----------------------------------------| + | retry_timeout | + '----------------------------------------' + + +*************************************************************************************************************/ +static const dds_security_fsm_transition handshake_transistions [] = +{ /* Start */ + { NULL, EVENT_AUTO, NULL, + &state_initial_delay }, + /* initial delay: a short delay to give the remote node some time for matching the + BuiltinParticipantStatelessMessageWriter, so that it won't drop the auth_request + we're sending (that would result in a time-out and the handshake taking longer + than required). For the node that receives the auth_request, the transition for + the event EVENT_RECEIVED_MESSAGE_REQUEST is added, because that node may receive the + auth_request during this delay and can continue immediately (as the sender already + waited for this delay before sending the request) */ + { &state_initial_delay, EVENT_TIMEOUT, NULL, + &state_validate_remote_identity }, + { &state_initial_delay, EVENT_RECEIVED_MESSAGE_REQUEST, NULL, + &state_validate_remote_and_begin_reply }, + /* validate remote and begin reply */ + { &state_validate_remote_and_begin_reply, EVENT_VALIDATION_PENDING_RETRY, NULL, + &state_begin_handshake_reply_retry_wait }, + { &state_validate_remote_and_begin_reply, EVENT_VALIDATION_FAILED, NULL, + &state_handshake_init_message_resend }, + { &state_validate_remote_and_begin_reply, EVENT_VALIDATION_OK, NULL, + &state_validation_ok }, + { &state_validate_remote_and_begin_reply, EVENT_VALIDATION_PENDING_HANDSHAKE_MESSAGE, NULL, + &state_handshake_message_wait }, + /* 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 DDS_Security_ValidationResult_t validate_remote_identity_impl(struct ddsi_handshake *handshake, dds_security_authentication *auth, + struct participant *pp, struct proxy_participant *proxypp) +{ + DDS_Security_ValidationResult_t ret; + DDS_Security_IdentityToken remote_identity_token; + int64_t remote_identity_handle; + ddsi_guid_t remote_guid; + DDS_Security_SecurityException exception = {0}; + + 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); + +ident_token_missing: +validation_failed: + return ret; +} + +static void func_validate_remote_identity(struct dds_security_fsm *fsm, void *arg) +{ + DDS_Security_ValidationResult_t ret; + struct ddsi_handshake *handshake = (struct ddsi_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); + + ret = validate_remote_identity_impl(handshake, auth, pp, proxypp); + 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 DDS_Security_ValidationResult_t begin_handshake_reply_impl(struct ddsi_handshake *handshake, dds_security_authentication *auth, + struct participant *pp, struct proxy_participant *proxypp) +{ + DDS_Security_ValidationResult_t ret; + DDS_Security_SecurityException exception = {0}; + + 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"); + goto handshake_failed; + } + + if (ret == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) + { + if (!send_handshake_message(handshake, handshake->handshake_message_out, pp, proxypp, 0)) + 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 + 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"); + goto handshake_failed; + } + } + return ret; + +handshake_failed: + DDS_Security_DataHolder_free(handshake->handshake_message_out); + handshake->handshake_message_out = NULL; + return DDS_SECURITY_VALIDATION_FAILED; +} + +static void func_begin_handshake_reply(struct dds_security_fsm *fsm, void *arg) +{ + DDS_Security_ValidationResult_t ret; + 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); + + ret = begin_handshake_reply_impl(handshake, auth, pp, proxypp); + dds_security_fsm_dispatch(fsm, (int32_t)ret, true); +} + +static void func_validate_remote_and_begin_reply(struct dds_security_fsm *fsm, void *arg) +{ + DDS_Security_ValidationResult_t ret; + 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); + + ret = validate_remote_identity_impl(handshake, auth, pp, proxypp); + /* In the only path to this state an auth_request is received so the result + of validate_remote_identity should be PENDING_HANDSHAKE_MESSAGE, or failed + in case of an error. */ + if (ret != DDS_SECURITY_VALIDATION_FAILED) + { + if (ret != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) + { + HSWARNING("func_validate_remote_and_begin_reply: invalid result %d from validate_remote_identity", ret); + ret = DDS_SECURITY_VALIDATION_FAILED; + } + else + ret = begin_handshake_reply_impl(handshake, auth, pp, proxypp); + } + 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); + dds_security_fsm_free(handshake->fsm); + 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) +{ + handshake_event_t event = EVENT_VALIDATION_FAILED; + + DDSRT_UNUSED_ARG(pp); + DDSRT_UNUSED_ARG(proxypp); + + 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)); + 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) +{ + 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) +{ + return handshake->shared_secret; +} + +int64_t ddsi_handshake_get_handle(const struct ddsi_handshake *handshake) +{ + return handshake->handshake_handle; +} + +static struct ddsi_hsadmin * ddsi_handshake_admin_create(void) +{ + 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; +} + +static void release_handshake(void *arg) +{ + ddsi_handshake_release((struct ddsi_handshake *)arg); +} + +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); +} + +static void gc_delete_handshale (struct gcreq *gcreq) +{ + struct ddsi_handshake *handshake = gcreq->arg; + + ddsi_handshake_release(handshake); + gcreq_free(gcreq); +} + +void ddsi_handshake_remove(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) + { + struct gcreq *gcreq = gcreq_new (pp->e.gv->gcreq_queue, gc_delete_handshale); + ddsrt_avl_delete(&handshake_treedef, &hsadmin->handshakes, handshake); + ddsrt_atomic_st32(&handshake->deleting, 1); + dds_security_fsm_stop(handshake->fsm); + gcreq->arg = handshake; + gcreq_enqueue (gcreq); + } + ddsrt_mutex_unlock(&hsadmin->lock); +} + +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) +{ + struct ddsi_hsadmin *hsadmin = gv->hsadmin; + if (hsadmin) + { + ddsrt_mutex_destroy(&hsadmin->lock); + ddsrt_avl_free(&handshake_treedef, &hsadmin->handshakes, release_handshake); + if (hsadmin->fsm_control) + dds_security_fsm_control_free(hsadmin->fsm_control); + ddsrt_free(hsadmin); + } +} + +void ddsi_handshake_admin_stop(struct ddsi_domaingv *gv) +{ + struct ddsi_hsadmin *hsadmin = gv->hsadmin; + if (hsadmin && hsadmin->fsm_control) + dds_security_fsm_control_stop(hsadmin->fsm_control); +} + +#else + +extern inline void ddsi_handshake_release(UNUSED_ARG(struct ddsi_handshake *handshake)); +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(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_lifespan.c b/src/core/ddsi/src/ddsi_lifespan.c index ddd0224..e261769 100644 --- a/src/core/ddsi/src/ddsi_lifespan.c +++ b/src/core/ddsi/src/ddsi_lifespan.c @@ -34,7 +34,7 @@ static void lifespan_rhc_node_exp (struct xevent *xev, void *varg, ddsrt_mtime_t /* Gets the sample from the fibheap in lifespan admin that was expired first. If no more - * expired samples exist in the fibheap, the expiry time (nn_mtime_t) for the next sample to + * expired samples exist in the fibheap, the expiry time (ddsrt_mtime_t) for the next sample to * expire is returned. If the fibheap contains no more samples, DDSRT_MTIME_NEVER is returned */ ddsrt_mtime_t lifespan_next_expired_locked (const struct lifespan_adm *lifespan_adm, ddsrt_mtime_t tnow, void **sample) { diff --git a/src/core/ddsi/src/ddsi_mcgroup.c b/src/core/ddsi/src/ddsi_mcgroup.c index cd49444..b01b33e 100644 --- a/src/core/ddsi/src/ddsi_mcgroup.c +++ b/src/core/ddsi/src/ddsi_mcgroup.c @@ -203,7 +203,7 @@ static int joinleave_mcgroups (const struct ddsi_domaingv *gv, ddsi_tran_conn_t { if (gv->recvips_mode == RECVIPS_MODE_ALL || interface_in_recvips_p (gv->recvips, &gv->interfaces[i])) { - if ((rc = joinleave_mcgroup (conn, join, srcloc, mcloc, &gv->interfaces[i])) < 0) + if (joinleave_mcgroup (conn, join, srcloc, mcloc, &gv->interfaces[i]) < 0) fails++; else oks++; diff --git a/src/core/ddsi/src/ddsi_ownip.c b/src/core/ddsi/src/ddsi_ownip.c index d53fe85..4b181fb 100644 --- a/src/core/ddsi/src/ddsi_ownip.c +++ b/src/core/ddsi/src/ddsi_ownip.c @@ -103,10 +103,10 @@ int find_own_ip (struct ddsi_domaingv *gv, const char *requested_address) switch (ifa->type) { case DDSRT_IFTYPE_WIFI: - DDS_LOG(DDS_LC_CONFIG, " wireless"); + GVLOG (DDS_LC_CONFIG, " wireless"); break; case DDSRT_IFTYPE_WIRED: - DDS_LOG(DDS_LC_CONFIG, " wired"); + GVLOG (DDS_LC_CONFIG, " wired"); break; case DDSRT_IFTYPE_UNKNOWN: break; diff --git a/src/core/ddsi/src/ddsi_plist.c b/src/core/ddsi/src/ddsi_plist.c index a4e21b4..cd91486 100644 --- a/src/core/ddsi/src/ddsi_plist.c +++ b/src/core/ddsi/src/ddsi_plist.c @@ -27,6 +27,7 @@ #include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/ddsi_time.h" #include "dds/ddsi/q_xmsg.h" +#include "dds/ddsi/ddsi_xqos.h" #include "dds/ddsi/ddsi_vendor.h" #include "dds/ddsi/ddsi_udp.h" /* nn_mc4gen_address_t */ @@ -39,6 +40,7 @@ #include "dds/ddsi/q_misc.h" /* for vendor_is_... */ #include "dds/ddsi/ddsi_plist_generic.h" +#include "dds/ddsi/ddsi_security_omg.h" /* I am tempted to change LENGTH_UNLIMITED to 0 in the API (with -1 supported for backwards compatibility) ... on the wire however @@ -104,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); @@ -115,8 +117,6 @@ struct piddesc { dds_return_t (*deser_validate_xform) (void * __restrict dst, const struct dd * __restrict dd); }; -extern inline bool pserop_seralign_is_1 (enum pserop op); - static dds_return_t validate_history_qospolicy (const dds_history_qospolicy_t *q); static dds_return_t validate_resource_limits_qospolicy (const dds_resource_limits_qospolicy_t *q); static dds_return_t validate_history_and_resource_limits (const dds_history_qospolicy_t *qh, const dds_resource_limits_qospolicy_t *qr); @@ -127,26 +127,70 @@ static dds_return_t final_validation_qos (const dds_qos_t *dest, nn_protocol_ver static int partitions_equal (const void *srca, const void *srcb, size_t off); static dds_return_t ddsi_xqos_valid_strictness (const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos, bool strict); -static size_t align4size (size_t x) +static size_t pserop_seralign(enum pserop op) { - return (x + 3) & ~(size_t)3; + switch(op) + { + case XSTOP: + case XbPROP: + case Xopt: + /* NB: XbPROP is never serialized, so its alignment is irrelevant. If ever there + is a need to allow calling this function when op = XbPROP, it needs to be changed + to taking the address of the pserop, and in that case inspect the following + operator */ + assert(false); + return 1; + case Xo: case Xox2: + case Xb: case Xbx2: + case XbCOND: + case XG: + case XK: + return 1; + case XO: + case XS: + case XE1: case XE2: case XE3: + case Xi: case Xix2: case Xix3: case Xix4: + case Xu: case Xux2: case Xux3: case Xux4: case Xux5: + case XD: case XDx2: + case XQ: + return 4; + case Xl: + return 8; + } + assert(false); + return 1; } -static void *deser_generic_dst (void * __restrict dst, size_t *dstoff, size_t align) +static size_t alignN(const size_t off, const size_t align) { - *dstoff = (*dstoff + align - 1) & ~(align - 1); + return (off + align - 1) & ~(align - 1); +} + +static size_t align4(const size_t off) +{ + return alignN(off, 4); +} + +static size_t align8(const size_t off) +{ + return alignN(off, 8); +} + +static void *deser_generic_dst (void * __restrict dst, size_t *dstoff, const size_t align) +{ + *dstoff = alignN(*dstoff, align); return (char *) dst + *dstoff; } -static const void *deser_generic_src (const void * __restrict src, size_t *srcoff, size_t align) +static const void *deser_generic_src (const void * __restrict src, size_t *srcoff, const size_t align) { - *srcoff = (*srcoff + align - 1) & ~(align - 1); + *srcoff = alignN(*srcoff, align); return (const char *) src + *srcoff; } -static void *ser_generic_align4 (char * __restrict p, size_t * __restrict off) +static void *ser_generic_aligned (char * __restrict p, size_t * __restrict off, const size_t align) { - const size_t off1 = align4size (*off); + const size_t off1 = alignN(*off, align); size_t pad = off1 - *off; char *dst = p + *off; *off = off1; @@ -155,6 +199,16 @@ static void *ser_generic_align4 (char * __restrict p, size_t * __restrict off) return dst; } +static void *ser_generic_align4(char * __restrict p, size_t * __restrict off) +{ + return ser_generic_aligned(p, off, 4); +} + +static void *ser_generic_align8(char * __restrict p, size_t * __restrict off) +{ + return ser_generic_aligned(p, off, 8); +} + static dds_return_t deser_uint32 (uint32_t *dst, const struct dd * __restrict dd, size_t * __restrict off) { size_t off1 = (*off + 3) & ~(size_t)3; @@ -169,6 +223,20 @@ static dds_return_t deser_uint32 (uint32_t *dst, const struct dd * __restrict dd return 0; } +static dds_return_t deser_int64 (int64_t *dst, const struct dd * __restrict dd, size_t * __restrict off) +{ + size_t off1 = (*off + 7) & ~(size_t)7; + int64_t tmp; + if (off1 + 8 > dd->bufsz) + return DDS_RETCODE_BAD_PARAMETER; + tmp = *((int64_t *) (dd->buf + off1)); + if (dd->bswap) + tmp = ddsrt_bswap8 (tmp); + *dst = tmp; + *off = off1 + 8; + return 0; +} + /* Returns true if buffer not yet exhausted, false otherwise */ static bool prtf (char * __restrict *buf, size_t * __restrict bufsize, const char *fmt, ...) { @@ -221,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 = ddsi_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) @@ -272,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; } @@ -306,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; @@ -352,6 +424,28 @@ static dds_return_t fini_locator (void * __restrict dst, size_t * __restrict dst return 0; } +static const enum pserop* pserop_advance (const enum pserop * __restrict desc) +{ + /* Should not start on an end. */ + assert(*desc != XSTOP); + + /* If not a sequence, return next. */ + if (*desc != XQ) return (desc + 1); + + /* Jump over this sequence (ignoring nested ones). */ + int scope = 1; + do + { + desc++; + if (*desc == XQ) scope++; + if (*desc == XSTOP) scope--; + } + while (scope != 0); + + /* We're on the stop, return next. */ + return (desc + 1); +} + static bool print_locator (char * __restrict *buf, size_t * __restrict bufsize, const void *src, size_t srcoff) { nn_locators_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_locators_t)); @@ -387,17 +481,18 @@ static size_t ser_generic_srcsize (const enum pserop * __restrict desc) case XE1: case XE2: case XE3: SIMPLE (*desc, unsigned); break; case Xi: case Xix2: case Xix3: case Xix4: SIMPLE (Xi, int32_t); break; case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE (Xu, uint32_t); break; + case Xl: SIMPLE (Xl, int64_t); break; case XD: case XDx2: SIMPLE (XD, dds_duration_t); break; case Xo: case Xox2: SIMPLE (Xo, unsigned char); break; case Xb: case Xbx2: SIMPLE (Xb, unsigned char); break; case XbCOND: SIMPLE (XbCOND, unsigned char); break; case XG: SIMPLE (XG, ddsi_guid_t); break; - case XK: SIMPLE (XK, nn_keyhash_t); break; + case XK: SIMPLE (XK, ddsi_keyhash_t); break; case XbPROP: SIMPLE (XbPROP, unsigned char); break; - case XQ: SIMPLE (XQ, ddsi_octetseq_t); while (*++desc != XSTOP) { } break; + case XQ: SIMPLE (XQ, ddsi_octetseq_t); break; case Xopt: break; } - desc++; + desc = pserop_advance(desc); } #undef SIMPLE } @@ -407,8 +502,9 @@ size_t plist_memsize_generic (const enum pserop * __restrict desc) return ser_generic_srcsize (desc); } -static void fini_generic_embeddable (void * __restrict dst, size_t * __restrict dstoff, const enum pserop *desc, const enum pserop * const desc_end, bool aliased) +static bool fini_generic_embeddable (void * __restrict dst, size_t * __restrict dstoff, const enum pserop *desc, const enum pserop * const desc_end, bool aliased) { + bool freed = false; #define COMPLEX(basecase_, type_, cleanup_unaliased_, cleanup_always_) do { \ type_ *x = deser_generic_dst (dst, dstoff, alignof (type_)); \ const uint32_t cnt = 1 + (uint32_t) (*desc - (basecase_)); \ @@ -419,41 +515,46 @@ static void fini_generic_embeddable (void * __restrict dst, size_t * __restrict *dstoff += cnt * sizeof (*x); \ } while (0) #define SIMPLE(basecase_, type_) COMPLEX (basecase_, type_, (void) 0, (void) 0) - while (desc != desc_end) + while ((desc_end == NULL) || (desc < desc_end)) { switch (*desc) { - case XSTOP: return; - case XO: COMPLEX (XO, ddsi_octetseq_t, ddsrt_free (x->value), (void) 0); break; - case XS: COMPLEX (XS, char *, ddsrt_free (*x), (void) 0); break; + case XSTOP: return freed; + case XO: COMPLEX (XO, ddsi_octetseq_t, { ddsrt_free (x->value); freed = true; }, (void) 0); break; + case XS: COMPLEX (XS, char *, { ddsrt_free (*x); freed = true; }, (void) 0); break; case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, (void) 0, (void) 0); break; case Xi: case Xix2: case Xix3: case Xix4: SIMPLE (Xi, int32_t); break; case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE (Xu, uint32_t); break; + case Xl: SIMPLE (Xl, int64_t); break; case XD: case XDx2: SIMPLE (XD, dds_duration_t); break; case Xo: case Xox2: SIMPLE (Xo, unsigned char); break; case Xb: case Xbx2: SIMPLE (Xb, unsigned char); break; case XbCOND: SIMPLE (XbCOND, unsigned char); break; case XG: SIMPLE (XG, ddsi_guid_t); break; - case XK: SIMPLE (XK, nn_keyhash_t); break; + case XK: SIMPLE (XK, ddsi_keyhash_t); break; case XbPROP: SIMPLE (XbPROP, unsigned char); break; case XQ: - /* non-nested, so never a need to deallocate only some of the entries and no complications - in locating the end of the sequence element description */ - COMPLEX (XQ, ddsi_octetseq_t, { - const size_t elem_size = ser_generic_srcsize (desc + 1); - for (uint32_t i = 0; i < x->length; i++) { - size_t elem_off = i * elem_size; - fini_generic_embeddable (x->value, &elem_off, desc + 1, desc_end, aliased); - } - }, ddsrt_free (x->value)); - while (desc + 1 != desc_end && *++desc != XSTOP) { } - break; + { + ddsi_octetseq_t *x = deser_generic_dst (dst, dstoff, alignof (ddsi_octetseq_t)); + const size_t elem_size = ser_generic_srcsize (desc + 1); + bool elem_freed = true; + for (uint32_t i = 0; (i < x->length) && elem_freed; i++) + { + size_t elem_off = i * elem_size; + elem_freed = fini_generic_embeddable (x->value, &elem_off, desc + 1, desc_end, aliased); + } + ddsrt_free (x->value); + freed = true; + *dstoff += sizeof (ddsi_octetseq_t); + } + break; case Xopt: break; } - desc++; + desc = pserop_advance(desc); } #undef SIMPLE #undef COMPLEX + return freed; } static size_t pserop_memalign (enum pserop op) @@ -463,20 +564,21 @@ static size_t pserop_memalign (enum pserop op) case XO: case XQ: return alignof (ddsi_octetseq_t); case XS: return alignof (char *); case XG: return alignof (ddsi_guid_t); - case XK: return alignof (nn_keyhash_t); + case XK: return alignof (ddsi_keyhash_t); case Xb: case Xbx2: return 1; case Xo: case Xox2: return 1; case XbCOND: case XbPROP: return 1; case XE1: case XE2: case XE3: return sizeof (uint32_t); case Xi: case Xix2: case Xix3: case Xix4: return sizeof (int32_t); case Xu: case Xux2: case Xux3: case Xux4: case Xux5: return sizeof (uint32_t); + case Xl: return alignof (int64_t); case XD: case XDx2: return alignof (dds_duration_t); case XSTOP: case Xopt: assert (0); } return 0; } -static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff, const enum pserop * __restrict desc) +static dds_return_t deser_generic_r (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff, const enum pserop * __restrict desc) { enum pserop const * const desc_in = desc; size_t dstoff_in = *dstoff; @@ -505,7 +607,7 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds char ** const x = deser_generic_dst (dst, dstoff, alignof (char *)); ddsi_octetseq_t tmp; size_t tmpoff = 0; - if (deser_generic (&tmp, &tmpoff, flagset, flag, dd, srcoff, (enum pserop []) { XO, XSTOP }) < 0) + if (deser_generic_r (&tmp, &tmpoff, flagset, flag, dd, srcoff, (enum pserop []) { XO, XSTOP }) < 0) goto fail; if (tmp.length < 1 || tmp.value[tmp.length - 1] != 0) goto fail; @@ -541,6 +643,13 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds *dstoff += cnt * sizeof (*x); break; } + case Xl: { /* int64_t */ + int64_t * const x = deser_generic_dst (dst, dstoff, alignof (int64_t)); + if (deser_int64(x, dd, srcoff) < 0) + goto fail; + *dstoff += sizeof (*x); + break; + } case XD: case XDx2: { /* duration(s): int64_t <=> int32_t.uint32_t (seconds.fraction) */ dds_duration_t * const x = deser_generic_dst (dst, dstoff, alignof (dds_duration_t)); const uint32_t cnt = 1 + (uint32_t) (*desc - XD); @@ -596,7 +705,7 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds break; } case XK: { /* keyhash */ - nn_keyhash_t * const x = deser_generic_dst (dst, dstoff, alignof (nn_keyhash_t)); + ddsi_keyhash_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_keyhash_t)); if (dd->bufsz - *srcoff < sizeof (*x)) goto fail; memcpy (x, dd->buf + *srcoff, sizeof (*x)); @@ -604,7 +713,7 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds *dstoff += sizeof (*x); break; } - case XQ: { /* non-nested but otherwise arbitrary sequence, so no nested mallocs */ + case XQ: { /* arbitrary sequence */ ddsi_octetseq_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_octetseq_t)); if (deser_uint32 (&x->length, dd, srcoff) < 0 || x->length > dd->bufsz - *srcoff) goto fail; @@ -613,25 +722,26 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds for (uint32_t i = 0; i < x->length; i++) { size_t elem_off = i * elem_size; - if (deser_generic (x->value, &elem_off, flagset, flag, dd, srcoff, desc + 1) < 0) + if (deser_generic_r (x->value, &elem_off, flagset, flag, dd, srcoff, desc + 1) < 0) { + bool elem_freed = true; + for (uint32_t f = 0; (f < i) && (elem_freed); f++) + { + size_t free_off = f * elem_size; + elem_freed = fini_generic_embeddable (x->value, &free_off, desc + 1, NULL, *flagset->aliased & flag); + } ddsrt_free (x->value); goto fail; } } *dstoff += sizeof (*x); - while (*++desc != XSTOP) { } break; } case Xopt: { /* remainder is optional; alignment is very nearly always 4 */ bool end_of_input; - if (pserop_seralign_is_1 (desc[1])) - end_of_input = (*srcoff + 1 > dd->bufsz); - else - { - *srcoff = (*srcoff + 3) & ~(size_t)3; - end_of_input = (*srcoff + 4 > dd->bufsz); - } + size_t align = pserop_seralign(desc[1]); + *srcoff = alignN(*srcoff, align); + end_of_input = (*srcoff + align > dd->bufsz); if (end_of_input) { void * const x = deser_generic_dst (dst, dstoff, pserop_memalign (desc[1])); @@ -641,19 +751,29 @@ static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict ds } } } - desc++; + desc = pserop_advance(desc); } success: *flagset->present |= flag; return 0; fail: - fini_generic_embeddable (dst, &dstoff_in, desc_in, desc, *flagset->aliased & flag); - *flagset->present &= ~flag; - *flagset->aliased &= ~flag; + (void)fini_generic_embeddable (dst, &dstoff_in, desc_in, desc, *flagset->aliased & flag); return DDS_RETCODE_BAD_PARAMETER; } +static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff, const enum pserop * __restrict desc) +{ + dds_return_t ret; + ret = deser_generic_r (dst, dstoff, flagset, flag, dd, srcoff, desc); + if (ret != 0) + { + *flagset->present &= ~flag; + *flagset->aliased &= ~flag; + } + return ret; +} + dds_return_t plist_deser_generic (void * __restrict dst, const void * __restrict src, size_t srcsize, bool bswap, const enum pserop * __restrict desc) { struct dd dd = { @@ -679,35 +799,38 @@ static void ser_generic_size_embeddable (size_t *dstoff, const void *src, size_t srcoff += cnt * sizeof (*x); \ } while (0) #define SIMPLE1(basecase_, type_) COMPLEX (basecase_, type_, *dstoff = *dstoff + sizeof (*x)) -#define SIMPLE4(basecase_, type_) COMPLEX (basecase_, type_, *dstoff = align4size (*dstoff) + sizeof (*x)) +#define SIMPLE4(basecase_, type_) COMPLEX (basecase_, type_, *dstoff = align4 (*dstoff) + sizeof (*x)) +#define SIMPLE8(basecase_, type_) COMPLEX (basecase_, type_, *dstoff = align8 (*dstoff) + sizeof (*x)) while (true) { switch (*desc) { case XSTOP: return; - case XO: COMPLEX (XO, ddsi_octetseq_t, *dstoff = align4size (*dstoff) + 4 + x->length); break; - case XS: COMPLEX (XS, const char *, *dstoff = align4size (*dstoff) + 4 + strlen (*x) + 1); break; - case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, *dstoff = align4size (*dstoff) + 4); break; + case XO: COMPLEX (XO, ddsi_octetseq_t, *dstoff = align4 (*dstoff) + 4 + x->length); break; + case XS: COMPLEX (XS, const char *, *dstoff = align4 (*dstoff) + 4 + strlen (*x) + 1); break; + case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, *dstoff = align4 (*dstoff) + 4); break; case Xi: case Xix2: case Xix3: case Xix4: SIMPLE4 (Xi, int32_t); break; case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE4 (Xu, uint32_t); break; + case Xl: SIMPLE8 (Xl, int64_t); break; case XD: case XDx2: SIMPLE4 (XD, dds_duration_t); break; case Xo: case Xox2: SIMPLE1 (Xo, unsigned char); break; case Xb: case Xbx2: SIMPLE1 (Xb, unsigned char); break; case XbCOND: SIMPLE1 (XbCOND, unsigned char); break; case XG: SIMPLE1 (XG, ddsi_guid_t); break; - case XK: SIMPLE1 (XK, nn_keyhash_t); break; + case XK: SIMPLE1 (XK, ddsi_keyhash_t); break; case XbPROP: /* "propagate" boolean: when 'false'; no serialisation; no size; force early out */ COMPLEX (XbPROP, unsigned char, if (! *x) return); break; case XQ: COMPLEX (XQ, ddsi_octetseq_t, { const size_t elem_size = ser_generic_srcsize (desc + 1); - *dstoff = align4size (*dstoff) + 4; + *dstoff = align4 (*dstoff) + 4; for (uint32_t i = 0; i < x->length; i++) ser_generic_size_embeddable (dstoff, x->value, i * elem_size, desc + 1); - }); while (*++desc != XSTOP) { } break; + }); break; case Xopt: break; } - desc++; + desc = pserop_advance(desc); } +#undef SIMPLE8 #undef SIMPLE4 #undef SIMPLE1 #undef COMPLEX @@ -735,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) @@ -746,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); @@ -756,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); @@ -765,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; @@ -775,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; @@ -785,11 +912,19 @@ 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; } + 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 = BO8(*x); + *dstoff += sizeof (*x); + srcoff += sizeof (*x); + break; + } case XD: case XDx2: { /* duration(s): int64_t <=> int32_t.uint32_t (seconds.fraction) */ dds_duration_t const * const x = deser_generic_src (src, &srcoff, alignof (dds_duration_t)); const uint32_t cnt = 1 + (uint32_t) (*desc - XD); @@ -797,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 = ddsi_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); @@ -838,14 +973,14 @@ static dds_return_t ser_generic_embeddable (char * const data, size_t *dstoff, c break; } case XK: { /* keyhash */ - nn_keyhash_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_keyhash_t)); + ddsi_keyhash_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_keyhash_t)); char * const p = data + *dstoff; memcpy (p, x, sizeof (*x)); *dstoff += sizeof (*x); srcoff += sizeof (*x); break; } - case XQ: { + case XQ: { /* arbitrary sequence */ ddsi_octetseq_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_octetseq_t)); char * const p = ser_generic_align4 (data, dstoff); *dstoff += 4; @@ -854,26 +989,30 @@ 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); - while (*++desc != XSTOP) { } break; } case Xopt: break; } - desc++; + 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) @@ -884,7 +1023,20 @@ 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; +} + +dds_return_t plist_ser_generic_be (void **dst, size_t *dstsize, const void *src, const enum pserop * __restrict desc) +{ + const size_t srcoff = 0; + size_t dstoff = 0; + dds_return_t ret; + *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, true); assert (dstoff == *dstsize); return ret; } @@ -909,13 +1061,14 @@ static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, (void) 0); break; case Xi: case Xix2: case Xix3: case Xix4: SIMPLE (Xi, int32_t); break; case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE (Xu, uint32_t); break; + case Xl: SIMPLE(Xl, int64_t); break; case XD: case XDx2: SIMPLE (XD, dds_duration_t); break; case Xo: case Xox2: SIMPLE (Xo, unsigned char); break; case Xb: case Xbx2: SIMPLE (Xb, unsigned char); break; case XbCOND: SIMPLE (XbCOND, unsigned char); break; case XbPROP: SIMPLE (XbPROP, unsigned char); break; case XG: SIMPLE (XG, ddsi_guid_t); break; - case XK: SIMPLE (XK, nn_keyhash_t); break; + case XK: SIMPLE (XK, ddsi_keyhash_t); break; case XQ: COMPLEX (XQ, ddsi_octetseq_t, if (x->length) { const size_t elem_size = ser_generic_srcsize (desc + 1); if (gen_seq_aliased) @@ -934,10 +1087,10 @@ static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict size_t elem_off = i * elem_size; unalias_generic (x->value, &elem_off, gen_seq_aliased, desc + 1); } - }); while (*++desc != XSTOP) { } break; + }); break; case Xopt: break; } - desc++; + desc = pserop_advance(desc); } #undef SIMPLE #undef COMPLEX @@ -972,14 +1125,14 @@ static bool fini_generic_required (const enum pserop * __restrict desc) static dds_return_t fini_generic (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const enum pserop * __restrict desc) { - fini_generic_embeddable (dst, dstoff, desc, NULL, *flagset->aliased & flag); + (void)fini_generic_embeddable (dst, dstoff, desc, NULL, *flagset->aliased & flag); return 0; } void plist_fini_generic (void * __restrict dst, const enum pserop *desc, bool aliased) { size_t dstoff = 0; - fini_generic_embeddable (dst, &dstoff, desc, NULL, aliased); + (void)fini_generic_embeddable (dst, &dstoff, desc, NULL, aliased); } static dds_return_t valid_generic (const void *src, size_t srcoff, const enum pserop * __restrict desc) @@ -1002,13 +1155,14 @@ static dds_return_t valid_generic (const void *src, size_t srcoff, const enum ps case XE1: case XE2: case XE3: SIMPLE (*desc, unsigned, *x <= 1 + (unsigned) *desc - XE1); break; case Xi: case Xix2: case Xix3: case Xix4: TRIVIAL (Xi, int32_t); break; case Xu: case Xux2: case Xux3: case Xux4: case Xux5: TRIVIAL (Xu, uint32_t); break; + case Xl: TRIVIAL(Xl, int64_t); break; case XD: case XDx2: SIMPLE (XD, dds_duration_t, *x >= 0); break; case Xo: case Xox2: TRIVIAL (Xo, unsigned char); break; case Xb: case Xbx2: SIMPLE (Xb, unsigned char, *x == 0 || *x == 1); break; case XbCOND: SIMPLE (XbCOND, unsigned char, *x == 0 || *x == 1); break; case XbPROP: SIMPLE (XbPROP, unsigned char, *x == 0 || *x == 1); break; case XG: TRIVIAL (XG, ddsi_guid_t); break; - case XK: TRIVIAL (XK, nn_keyhash_t); break; + case XK: TRIVIAL (XK, ddsi_keyhash_t); break; case XQ: COMPLEX (XQ, ddsi_octetseq_t, { if ((x->length == 0) != (x->value == NULL)) return DDS_RETCODE_BAD_PARAMETER; @@ -1020,10 +1174,10 @@ static dds_return_t valid_generic (const void *src, size_t srcoff, const enum ps return ret; } } - }); while (*++desc != XSTOP) { } break; + }); break; case Xopt: break; } - desc++; + desc = pserop_advance(desc); } #undef TRIVIAL #undef SIMPLE @@ -1058,6 +1212,7 @@ static bool equal_generic (const void *srcx, const void *srcy, size_t srcoff, co case XE1: case XE2: case XE3: TRIVIAL (*desc, unsigned); break; case Xi: case Xix2: case Xix3: case Xix4: TRIVIAL (Xi, int32_t); break; case Xu: case Xux2: case Xux3: case Xux4: case Xux5: TRIVIAL (Xu, uint32_t); break; + case Xl: TRIVIAL (Xl, int64_t); break; case XD: case XDx2: TRIVIAL (XD, dds_duration_t); break; case Xo: case Xox2: TRIVIAL (Xo, unsigned char); break; case Xb: case Xbx2: TRIVIAL (Xb, unsigned char); break; @@ -1071,7 +1226,7 @@ static bool equal_generic (const void *srcx, const void *srcy, size_t srcoff, co break; case XbPROP: TRIVIAL (XbPROP, unsigned char); break; case XG: SIMPLE (XG, ddsi_guid_t, memcmp (x, y, sizeof (*x)) == 0); break; - case XK: SIMPLE (XK, nn_keyhash_t, memcmp (x, y, sizeof (*x)) == 0); break; + case XK: SIMPLE (XK, ddsi_keyhash_t, memcmp (x, y, sizeof (*x)) == 0); break; case XQ: COMPLEX (XQ, ddsi_octetseq_t, { if (x->length != y->length) return false; @@ -1082,10 +1237,10 @@ static bool equal_generic (const void *srcx, const void *srcy, size_t srcoff, co return false; } } - }); while (*++desc != XSTOP) { } break; + }); break; case Xopt: break; } - desc++; + desc = pserop_advance(desc); } #undef TRIVIAL #undef SIMPLE @@ -1107,7 +1262,14 @@ static uint32_t isprint_runlen (uint32_t n, const unsigned char *xs) static bool prtf_octetseq (char * __restrict *buf, size_t * __restrict bufsize, uint32_t n, const unsigned char *xs) { + /* Truncate octet sequences: 100 is arbitrary but experience suggests it is + usually enough, and truncating it helps a lot when printing handshake + messages during authentication. */ + const uint32_t lim = 100; + bool trunc = (n > lim); uint32_t i = 0; + if (trunc) + n = lim; while (i < n) { uint32_t m = isprint_runlen (n - i, xs); @@ -1130,7 +1292,7 @@ static bool prtf_octetseq (char * __restrict *buf, size_t * __restrict bufsize, } } } - return true; + return trunc ? prtf (buf, bufsize, "...") : true; } static bool print_generic1 (char * __restrict *buf, size_t * __restrict bufsize, const void *src, size_t srcoff, const enum pserop * __restrict desc, const char *sep) @@ -1188,6 +1350,18 @@ static bool print_generic1 (char * __restrict *buf, size_t * __restrict bufsize, srcoff += cnt * sizeof (*x); break; } + case Xl: { + int64_t const * const x = deser_generic_src (src, &srcoff, alignof (int64_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xl); + for (uint32_t i = 0; i < cnt; i++) + { + if (!prtf (buf, bufsize, "%s%"PRId64, sep, x[i])) + return false; + sep = ":"; + } + srcoff += cnt * sizeof (*x); + break; + } case XD: case XDx2: { /* duration(s): int64_t <=> int32_t.uint32_t (seconds.fraction) */ dds_duration_t const * const x = deser_generic_src (src, &srcoff, alignof (dds_duration_t)); const uint32_t cnt = 1 + (uint32_t) (*desc - XD); @@ -1233,13 +1407,13 @@ static bool print_generic1 (char * __restrict *buf, size_t * __restrict bufsize, } case XG: { /* GUID */ ddsi_guid_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_guid_t)); - if (!prtf (buf, bufsize, "%s"PGUIDFMT, sep, PGUID (*x))) + if (!prtf (buf, bufsize, "%s{"PGUIDFMT"}", sep, PGUID (*x))) return false; srcoff += sizeof (*x); break; } case XK: { /* keyhash */ - nn_keyhash_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_keyhash_t)); + ddsi_keyhash_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_keyhash_t)); if (!prtf (buf, bufsize, "%s{%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x}", sep, x->value[0], x->value[1], x->value[2], x->value[3], x->value[4], x->value[5], x->value[6], x->value[7], x->value[8], x->value[9], x->value[10], x->value[11], x->value[12], x->value[13], x->value[14], x->value[15])) @@ -1261,14 +1435,13 @@ static bool print_generic1 (char * __restrict *buf, size_t * __restrict bufsize, if (!prtf (buf, bufsize, "}")) return false; srcoff += sizeof (*x); - while (*++desc != XSTOP) { } break; } case Xopt: break; } sep = ":"; - desc++; + desc = pserop_advance(desc); } } @@ -1408,6 +1581,14 @@ static const struct piddesc piddesc_omg[] = { PPV (ENDPOINT_GUID, endpoint_guid, XG), #ifdef DDSI_INCLUDE_SSM PPV (READER_FAVOURS_SSM, reader_favours_ssm, Xu), +#endif +#ifdef DDSI_INCLUDE_SECURITY + PP (ENDPOINT_SECURITY_INFO, endpoint_security_info, Xu, Xu), + PP (PARTICIPANT_SECURITY_INFO, participant_security_info, Xu, Xu), + PP (IDENTITY_TOKEN, identity_token, XS, XQ, XbPROP, XS, XS, XSTOP, XQ, XbPROP, XS, XO, XSTOP), + PP (PERMISSIONS_TOKEN, permissions_token, XS, XQ, XbPROP, XS, XS, XSTOP, XQ, XbPROP, XS, XO, XSTOP), + PP (IDENTITY_STATUS_TOKEN, identity_status_token, XS, XQ, XbPROP, XS, XS, XSTOP, XQ, XbPROP, XS, XO, XSTOP), + PP (DATA_TAGS, data_tags, XQ, XS, XS, XSTOP), #endif PP (DOMAIN_ID, domain_id, Xu), PP (DOMAIN_TAG, domain_tag, XS), @@ -1518,11 +1699,21 @@ struct piddesc_index { ddsi_plist_init_tables. FIXME: should compute them at build-time */ +#define DEFAULT_PROC_ARRAY_SIZE 20 #ifdef DDSI_INCLUDE_SSM -static const struct piddesc *piddesc_omg_index[115]; -#else /* status info is the highest */ -static const struct piddesc *piddesc_omg_index[114]; +#define DEFAULT_OMG_PIDS_ARRAY_SIZE (PID_READER_FAVOURS_SSM + 1) +#else +#define DEFAULT_OMG_PIDS_ARRAY_SIZE (PID_STATUSINFO + 1) #endif +#ifdef DDSI_INCLUDE_SECURITY +#define SECURITY_OMG_PIDS_ARRAY_SIZE (PID_IDENTITY_STATUS_TOKEN - PID_IDENTITY_TOKEN + 1) +#define SECURITY_PROC_ARRAY_SIZE 4 +#else +#define SECURITY_OMG_PIDS_ARRAY_SIZE 0 +#define SECURITY_PROC_ARRAY_SIZE 0 +#endif + +static const struct piddesc *piddesc_omg_index[DEFAULT_OMG_PIDS_ARRAY_SIZE + SECURITY_OMG_PIDS_ARRAY_SIZE]; static const struct piddesc *piddesc_eclipse_index[19]; static const struct piddesc *piddesc_adlink_index[19]; @@ -1548,13 +1739,22 @@ static const struct piddesc_index piddesc_vendor_index[] = { /* List of entries that require unalias, fini processing; initialized by ddsi_plist_init_tables; will assert when table too small or too large */ -static const struct piddesc *piddesc_unalias[18]; -static const struct piddesc *piddesc_fini[18]; +static const struct piddesc *piddesc_unalias[18 + SECURITY_PROC_ARRAY_SIZE]; +static const struct piddesc *piddesc_fini[18 + SECURITY_PROC_ARRAY_SIZE]; static ddsrt_once_t table_init_control = DDSRT_ONCE_INIT; -static nn_parameterid_t pid_without_flags (nn_parameterid_t pid) +static size_t pid_to_index (nn_parameterid_t pid) { - return (nn_parameterid_t) (pid & ~(PID_VENDORSPECIFIC_FLAG | PID_UNRECOGNIZED_INCOMPATIBLE_FLAG)); + /* pid without flags. */ + size_t idx = (size_t)(pid & ~(PID_VENDORSPECIFIC_FLAG | PID_UNRECOGNIZED_INCOMPATIBLE_FLAG)); +#ifdef DDSI_INCLUDE_SECURITY + if ((idx >= PID_IDENTITY_TOKEN) && (idx <= PID_IDENTITY_STATUS_TOKEN)) + { + /* Security PIDs start after the 'normal' PIDs. */ + idx = (idx - PID_IDENTITY_TOKEN) + DEFAULT_OMG_PIDS_ARRAY_SIZE; + } +#endif + return idx; } static int piddesc_cmp_qos_addr (const void *va, const void *vb) @@ -1578,12 +1778,13 @@ static void ddsi_plist_init_tables_real (void) continue; struct piddesc const **index = piddesc_vendor_index[i].index; #ifndef NDEBUG - nn_parameterid_t maxpid = 0; + size_t maxpididx = 0; bool only_qos_seen = true; #endif for (size_t j = 0; table[j].pid != PID_SENTINEL; j++) { - nn_parameterid_t pid = pid_without_flags (table[j].pid); + nn_parameterid_t pid = table[j].pid; + size_t pididx = pid_to_index(pid); #ifndef NDEBUG /* Table must first list QoS, then other parameters */ assert (only_qos_seen || !(table[j].flags & PDF_QOS)); @@ -1591,19 +1792,19 @@ static void ddsi_plist_init_tables_real (void) only_qos_seen = false; /* Track max PID so we can verify the table is no larger than necessary */ - if (pid > maxpid) - maxpid = pid; + if (pididx > maxpididx) + maxpididx = pididx; #endif /* PAD is used for entries that are never visible on the wire and the decoder assumes the PAD entries will be skipped because they don't map to an entry */ if (pid == PID_PAD) continue; - assert (pid <= piddesc_vendor_index[i].index_max); - assert (index[pid] == NULL || index[pid] == &table[j]); - index[pid] = &table[j]; + assert (pididx <= piddesc_vendor_index[i].index_max); + assert (index[pididx] == NULL || index[pididx] == &table[j]); + index[pididx] = &table[j]; } - assert (maxpid == piddesc_vendor_index[i].index_max); + assert (maxpididx == piddesc_vendor_index[i].index_max); } /* PIDs requiring unalias; there is overlap between the tables @@ -1818,7 +2019,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; @@ -1848,9 +2049,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); } } } @@ -2364,9 +2565,10 @@ static dds_return_t init_one_parameter (ddsi_plist_t *plist, nn_ipaddress_params index = &piddesc_vendor_index[dd->vendorid.id[1]]; const struct piddesc *entry; - if (pid_without_flags (pid) > index->index_max || (entry = index->index[pid_without_flags (pid)]) == NULL) + size_t pididx = pid_to_index(pid); + if (pididx > index->index_max || (entry = index->index[pididx]) == NULL) return return_unrecognized_pid (plist, pid); - assert (pid_without_flags (pid) == pid_without_flags (entry->pid)); + assert (pid_to_index (pid) == pid_to_index (entry->pid)); if (pid != entry->pid) return return_unrecognized_pid (plist, pid); assert (pid != PID_PAD); @@ -2662,20 +2864,47 @@ dds_return_t ddsi_plist_init_frommsg (ddsi_plist_t *dest, char **nextafterplist, return DDS_RETCODE_BAD_PARAMETER; } -const unsigned char *ddsi_plist_findparam_native_unchecked (const void *src, nn_parameterid_t pid) +dds_return_t ddsi_plist_findparam_checking (const void *buf, size_t bufsz, uint16_t encoding, nn_parameterid_t needle, void **needlep, size_t *needlesz) { - /* Scans the parameter list starting at src looking just for pid, returning NULL if not found; - no further checking is done and the input is assumed to valid and in native format. Clearly - this is only to be used for internally generated data -- to precise, for grabbing the key - value from discovery data that is being sent out. */ - const nn_parameter_t *par = src; - while (par->parameterid != pid) + /* set needle to PID_SENTINEL if all you want to do is scan the structure */ + assert (needle == PID_SENTINEL || (needlep != NULL && needlesz != NULL)); + bool bswap; + if (needlep) + *needlep = NULL; + switch (encoding) { - if (par->parameterid == PID_SENTINEL) - return NULL; - par = (const nn_parameter_t *) ((const char *) (par + 1) + par->length); + case PL_CDR_LE: + bswap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + break; + case PL_CDR_BE: + bswap = (DDSRT_ENDIAN != DDSRT_BIG_ENDIAN); + break; + default: + return DDS_RETCODE_BAD_PARAMETER; } - return (unsigned char *) (par + 1); + const unsigned char *pl = buf; + const unsigned char *endp = pl + bufsz; + while (pl + sizeof (nn_parameter_t) <= endp) + { + const nn_parameter_t *par = (const nn_parameter_t *) pl; + nn_parameterid_t pid; + uint16_t length; + pid = (nn_parameterid_t) (bswap ? ddsrt_bswap2u (par->parameterid) : par->parameterid); + length = (uint16_t) (bswap ? ddsrt_bswap2u (par->length) : par->length); + pl += sizeof (*par); + + if (pid == PID_SENTINEL) + return (needlep && *needlep == NULL) ? DDS_RETCODE_NOT_FOUND : DDS_RETCODE_OK; + else if (length > (size_t) (endp - pl) || (length % 4) != 0 /* DDSI 9.4.2.11 */) + return DDS_RETCODE_BAD_PARAMETER; + else if (pid == needle) + { + *needlep = (void *) pl; + *needlesz = length; + } + pl += length; + } + return DDS_RETCODE_BAD_PARAMETER; } unsigned char *ddsi_plist_quickscan (struct nn_rsample_info *dest, const struct nn_rmsg *rmsg, const ddsi_plist_src_t *src) @@ -2996,6 +3225,87 @@ dds_qos_t * ddsi_xqos_dup (const dds_qos_t *src) return dst; } +bool ddsi_xqos_has_prop_prefix (const dds_qos_t *xqos, const char *nameprefix) +{ + if (!(xqos->present & QP_PROPERTY_LIST)) + return false; + const size_t len = strlen (nameprefix); + for (uint32_t i = 0; i < xqos->property.value.n; i++) + { + if (strncmp (xqos->property.value.props[i].name, nameprefix, len) == 0) + return true; + } + return false; +} + +bool ddsi_xqos_find_prop (const dds_qos_t *xqos, const char *name, const char **value) +{ + if (!(xqos->present & QP_PROPERTY_LIST)) + return false; + for (uint32_t i = 0; i < xqos->property.value.n; i++) + { + if (strcmp (xqos->property.value.props[i].name, name) == 0) + { + if (value) + *value = xqos->property.value.props[i].value; + return true; + } + } + return false; +} + +#ifdef DDSI_INCLUDE_SECURITY +static void fill_property(dds_property_t *prop, const char *name, const char *value) +{ + prop->name = ddsrt_strdup(name); + prop->value = ddsrt_strdup(value); + prop->propagate = false; +} + +/** + * Add DDS Security configuration to the QoS as a Property policy used by the security + * plugins to get their proper settings. If security properties are already present in + * the QoS, the settings from configuration are ignored. + */ +void ddsi_xqos_mergein_security_config (dds_qos_t *xqos, const struct omg_security_configuration_type *cfg) +{ + assert(cfg != NULL); + + if (!(xqos->present & QP_PROPERTY_LIST)) + { + xqos->property.value.n = 0; + xqos->property.value.props = NULL; + xqos->property.binary_value.n = 0; + xqos->property.binary_value.props = NULL; + xqos->present |= QP_PROPERTY_LIST; + } + + /* assume that no security properties exist in qos: fill QoS properties with values from configuration */ + xqos->property.value.props = ddsrt_realloc (xqos->property.value.props, xqos->property.value.n + 18 /* max */ * sizeof (dds_property_t)); + + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_AUTH_LIBRARY_PATH, cfg->authentication_plugin.library_path); + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_AUTH_LIBRARY_INIT, cfg->authentication_plugin.library_init); + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_AUTH_LIBRARY_FINALIZE, cfg->authentication_plugin.library_finalize); + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_CRYPTO_LIBRARY_PATH, cfg->cryptography_plugin.library_path); + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_CRYPTO_LIBRARY_INIT, cfg->cryptography_plugin.library_init); + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_CRYPTO_LIBRARY_FINALIZE, cfg->cryptography_plugin.library_finalize); + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_ACCESS_LIBRARY_PATH, cfg->access_control_plugin.library_path); + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_ACCESS_LIBRARY_INIT, cfg->access_control_plugin.library_init); + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_ACCESS_LIBRARY_FINALIZE, cfg->access_control_plugin.library_finalize); + + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_AUTH_IDENTITY_CA, cfg->authentication_properties.identity_ca); + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_AUTH_PRIV_KEY, cfg->authentication_properties.private_key); + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_AUTH_IDENTITY_CERT, cfg->authentication_properties.identity_certificate); + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_ACCESS_PERMISSIONS_CA, cfg->access_control_properties.permissions_ca); + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_ACCESS_GOVERNANCE, cfg->access_control_properties.governance); + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_ACCESS_PERMISSIONS, cfg->access_control_properties.permissions); + if (cfg->authentication_properties.password ) + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_AUTH_PASSWORD, cfg->authentication_properties.password); + if (cfg->authentication_properties.trusted_ca_dir ) + fill_property(&(xqos->property.value.props[xqos->property.value.n++]), DDS_SEC_PROP_ACCESS_TRUSTED_CA_DIR, cfg->authentication_properties.trusted_ca_dir); +} +#endif /* DDSI_INCLUDE_SECURITY */ + static int partition_is_default (const dds_partition_qospolicy_t *a) { uint32_t i; @@ -3095,12 +3405,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); } /*************************/ @@ -3110,6 +3425,9 @@ static void plist_or_xqos_print (char * __restrict *buf, size_t * __restrict buf /* shift == 0: plist, shift > 0: just qos */ const char *sep = ""; uint64_t pw, qw; + if (*bufsize == 0) + return; + (*buf)[0] = 0; if (shift > 0) { const dds_qos_t *qos = src; @@ -3161,7 +3479,7 @@ static void plist_or_xqos_log (uint32_t cat, const struct ddsrt_log_cfg *logcfg, { if (logcfg->c.mask & cat) { - char tmp[1024], *ptmp = tmp; + char tmp[2048], *ptmp = tmp; size_t tmpsize = sizeof (tmp); plist_or_xqos_print (&ptmp, &tmpsize, src, shift, pwanted, qwanted); DDS_CLOG (cat, logcfg, "%s", tmp); @@ -3195,3 +3513,10 @@ void ddsi_plist_log (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const dds { plist_or_xqos_log (cat, logcfg, plist, 0, ~(uint64_t)0, ~(uint64_t)0); } + +size_t plist_print_generic (char * __restrict buf, size_t bufsize, const void * __restrict src, const enum pserop * __restrict desc) +{ + const size_t bufsize_in = bufsize; + (void) print_generic (&buf, &bufsize, src, 0, desc); + return bufsize_in - bufsize; +} diff --git a/src/core/ddsi/src/ddsi_pmd.c b/src/core/ddsi/src/ddsi_pmd.c index 9e7db55..dd19eee 100644 --- a/src/core/ddsi/src/ddsi_pmd.c +++ b/src/core/ddsi/src/ddsi_pmd.c @@ -14,6 +14,7 @@ #include "dds/ddsi/ddsi_pmd.h" #include "dds/ddsi/ddsi_serdata.h" #include "dds/ddsi/ddsi_serdata_default.h" +#include "dds/ddsi/ddsi_serdata_pserop.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_entity.h" @@ -30,20 +31,13 @@ #include "dds/ddsi/sysdeps.h" -static void debug_print_rawdata (const struct ddsi_domaingv *gv, const char *msg, const void *data, size_t len) -{ - const unsigned char *c = data; - size_t i; - GVTRACE ("%s<", msg); - for (i = 0; i < len; i++) - { - if (32 < c[i] && c[i] <= 127) - GVTRACE ("%s%c", (i > 0 && (i%4) == 0) ? " " : "", c[i]); - else - GVTRACE ("%s\\x%02x", (i > 0 && (i%4) == 0) ? " " : "", c[i]); - } - GVTRACE (">"); -} +/* note: treating guid prefix + kind as if it were a GUID because that matches + the octet-sequence/sequence-of-uint32 distinction between the specified wire + representation and the internal representation */ +const enum pserop participant_message_data_ops[] = { XG, XO, XSTOP }; +size_t participant_message_data_nops = sizeof (participant_message_data_ops) / sizeof (participant_message_data_ops[0]); +const enum pserop participant_message_data_ops_key[] = { XG, XSTOP }; +size_t participant_message_data_nops_key = sizeof (participant_message_data_ops_key) / sizeof (participant_message_data_ops_key[0]); void write_pmd_message_guid (struct ddsi_domaingv * const gv, struct ddsi_guid *pp_guid, unsigned pmd_kind) { @@ -67,10 +61,8 @@ void write_pmd_message (struct thread_state1 * const ts1, struct nn_xpack *xp, s #define PMD_DATA_LENGTH 1 struct ddsi_domaingv * const gv = pp->e.gv; struct writer *wr; - union { - ParticipantMessageData_t pmd; - char pad[offsetof (ParticipantMessageData_t, value) + PMD_DATA_LENGTH]; - } u; + unsigned char data[PMD_DATA_LENGTH] = { 0 }; + ParticipantMessageData_t pmd; struct ddsi_serdata *serdata; struct ddsi_tkmap_instance *tk; @@ -80,18 +72,11 @@ void write_pmd_message (struct thread_state1 * const ts1, struct nn_xpack *xp, s return; } - u.pmd.participantGuidPrefix = nn_hton_guid_prefix (pp->e.guid.prefix); - u.pmd.kind = ddsrt_toBE4u (pmd_kind); - u.pmd.length = PMD_DATA_LENGTH; - memset (u.pmd.value, 0, u.pmd.length); - - struct ddsi_rawcdr_sample raw = { - .blob = &u, - .size = offsetof (ParticipantMessageData_t, value) + PMD_DATA_LENGTH, - .key = &u.pmd, - .keysize = 16 - }; - serdata = ddsi_serdata_from_sample (gv->rawcdr_topic, SDK_DATA, &raw); + pmd.participantGuidPrefix = pp->e.guid.prefix; + pmd.kind = pmd_kind; + pmd.value.length = (uint32_t) sizeof (data); + pmd.value.value = data; + serdata = ddsi_serdata_from_sample (gv->pmd_topic, SDK_DATA, &pmd); serdata->timestamp = ddsrt_time_wallclock (); tk = ddsi_tkmap_lookup_instance_ref (gv->m_tkmap, serdata); @@ -100,66 +85,44 @@ void write_pmd_message (struct thread_state1 * const ts1, struct nn_xpack *xp, s #undef PMD_DATA_LENGTH } -void handle_pmd_message (const struct receiver_state *rst, ddsrt_wctime_t timestamp, uint32_t statusinfo, const void *vdata, uint32_t len) +void handle_pmd_message (const struct receiver_state *rst, struct ddsi_serdata *sample_common) { - const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */ - const int bswap = (data->identifier == CDR_LE) ^ (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + /* use sample with knowledge of internal representation: there's a deserialized sample inside already */ + const struct ddsi_serdata_pserop *sample = (const struct ddsi_serdata_pserop *) sample_common; struct proxy_participant *proxypp; ddsi_guid_t ppguid; struct lease *l; - RSTTRACE (" PMD ST%x", statusinfo); - if (data->identifier != CDR_LE && data->identifier != CDR_BE) + RSTTRACE (" PMD ST%x", sample->c.statusinfo); + switch (sample->c.statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER)) { - RSTTRACE (" PMD data->identifier %u !?\n", ntohs (data->identifier)); - return; - } - - switch (statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER)) - { - case 0: - if (offsetof (ParticipantMessageData_t, value) > len - sizeof (struct CDRHeader)) - debug_print_rawdata (rst->gv, " SHORT1", data, len); - else + case 0: { + const ParticipantMessageData_t *pmd = sample->sample; + RSTTRACE (" pp %"PRIx32":%"PRIx32":%"PRIx32" kind %"PRIu32" data %"PRIu32, PGUIDPREFIX (pmd->participantGuidPrefix), pmd->kind, pmd->value.length); + ppguid.prefix = pmd->participantGuidPrefix; + ppguid.entityid.u = NN_ENTITYID_PARTICIPANT; + if ((proxypp = entidx_lookup_proxy_participant_guid (rst->gv->entity_index, &ppguid)) == NULL) + RSTTRACE (" PPunknown"); + else if (pmd->kind == PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE && + (l = ddsrt_atomic_ldvoidp (&proxypp->minl_man)) != NULL) { - const ParticipantMessageData_t *pmd = (ParticipantMessageData_t *) (data + 1); - ddsi_guid_prefix_t p = nn_ntoh_guid_prefix (pmd->participantGuidPrefix); - uint32_t kind = ntohl (pmd->kind); - uint32_t length = bswap ? ddsrt_bswap4u (pmd->length) : pmd->length; - RSTTRACE (" pp %"PRIx32":%"PRIx32":%"PRIx32" kind %u data %u", p.u[0], p.u[1], p.u[2], kind, length); - if (len - sizeof (struct CDRHeader) - offsetof (ParticipantMessageData_t, value) < length) - debug_print_rawdata (rst->gv, " SHORT2", pmd->value, len - sizeof (struct CDRHeader) - offsetof (ParticipantMessageData_t, value)); - else - debug_print_rawdata (rst->gv, "", pmd->value, length); - ppguid.prefix = p; - ppguid.entityid.u = NN_ENTITYID_PARTICIPANT; - if ((proxypp = entidx_lookup_proxy_participant_guid (rst->gv->entity_index, &ppguid)) == NULL) - RSTTRACE (" PPunknown"); - else if (kind == PARTICIPANT_MESSAGE_DATA_KIND_MANUAL_LIVELINESS_UPDATE && - (l = ddsrt_atomic_ldvoidp (&proxypp->minl_man)) != NULL) - { - /* Renew lease for entity with shortest manual-by-participant lease */ - lease_renew (l, ddsrt_time_elapsed ()); - } + /* Renew lease for entity with shortest manual-by-participant lease */ + lease_renew (l, ddsrt_time_elapsed ()); } break; + } case NN_STATUSINFO_DISPOSE: case NN_STATUSINFO_UNREGISTER: - case NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER: - /* Serialized key; BE or LE doesn't matter as both fields are - defined as octets. */ - if (len < sizeof (struct CDRHeader) + sizeof (ddsi_guid_prefix_t)) - debug_print_rawdata (rst->gv, " SHORT3", data, len); + case NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER: { + const ParticipantMessageData_t *pmd = sample->sample; + ppguid.prefix = pmd->participantGuidPrefix; + ppguid.entityid.u = NN_ENTITYID_PARTICIPANT; + if (delete_proxy_participant_by_guid (rst->gv, &ppguid, sample->c.timestamp, 0) < 0) + RSTTRACE (" unknown"); else - { - ppguid.prefix = nn_ntoh_guid_prefix (*((ddsi_guid_prefix_t *) (data + 1))); - ppguid.entityid.u = NN_ENTITYID_PARTICIPANT; - if (delete_proxy_participant_by_guid (rst->gv, &ppguid, timestamp, 0) < 0) - RSTTRACE (" unknown"); - else - RSTTRACE (" delete"); - } + RSTTRACE (" delete"); break; + } } RSTTRACE ("\n"); } 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..6d8061d --- /dev/null +++ b/src/core/ddsi/src/ddsi_security_exchange.c @@ -0,0 +1,261 @@ +/* + * 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/ddsi_serdata_pserop.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" + +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; + 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); + } + + serdata = ddsi_serdata_from_sample (wr->topic, SDK_DATA, &pmg); + serdata->timestamp = ddsrt_time_wallclock (); + result = enqueue_sample_wrlock_held (wr, seq, NULL, serdata, prd, 1) == 0; + ddsi_serdata_unref (serdata); + 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; + ddsi_plist_t ps; + struct participant_builtin_topic_data_locators locs; + 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, &ps, &locs); + ddsi_plist_addtomsg_bo (mpayload, &ps, ~(uint64_t)0, ~(uint64_t)0, true); + nn_xmsg_addpar_sentinel_bo (mpayload, true); + ddsi_plist_fini (&ps); + 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, struct ddsi_serdata *sample_common) +{ + const struct ddsi_serdata_pserop *sample = (const struct ddsi_serdata_pserop *) sample_common; + const struct nn_participant_generic_message *msg = sample->sample; + struct participant *pp = NULL; + struct proxy_writer *pwr = NULL; + ddsi_guid_t guid; + const ddsi_guid_t *pwr_guid; + struct ddsi_handshake *handshake; + + DDSRT_UNUSED_ARG(wr_entity_id); + + 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"); + return; + } + + 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); + } +} + +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; + 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); + serdata = ddsi_serdata_from_sample (wr->topic, SDK_DATA, &pmg); + serdata->timestamp = ddsrt_time_wallclock (); + tk = ddsi_tkmap_lookup_instance_ref (gv->m_tkmap, serdata); + r = write_sample_p2p_wrlock_held(wr, seq, NULL, serdata, tk, prd); + ddsrt_mutex_unlock (&wr->e.lock); + 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, struct ddsi_serdata *sample_common) +{ + struct ddsi_domaingv * const gv = rst->gv; + const struct ddsi_serdata_pserop *sample = (const struct ddsi_serdata_pserop *) sample_common; + const struct nn_participant_generic_message *msg = sample->sample; + ddsi_guid_t proxypp_guid; + + 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) + { + struct participant * const 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)); + return; + } + struct proxy_participant *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)); + return; + } + 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 * const 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)); + return; + } + 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 * const 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)); + return; + } + 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)); + } +} + +#endif /* DDSI_INCLUDE_SECURITY */ diff --git a/src/core/ddsi/src/ddsi_security_msg.c b/src/core/ddsi/src/ddsi_security_msg.c new file mode 100644 index 0000000..ce44537 --- /dev/null +++ b/src/core/ddsi/src/ddsi_security_msg.c @@ -0,0 +1,193 @@ +/* + * 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 + */ +#include +#include +#include "dds/ddsrt/md5.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsi/q_bswap.h" +#include "dds/ddsi/q_entity.h" +#include "dds/ddsi/q_transmit.h" +#include "dds/ddsi/q_misc.h" +#include "dds/ddsi/ddsi_tkmap.h" +#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[] = +{ + /* nn_participant_generic_message */ + XG, Xl, /* nn_message_identity_t message_identity */ + XG, Xl, /* nn_message_identity_t related_message_identity */ + XG, /* ddsi_guid_t destination_participant_guid */ + XG, /* ddsi_guid_t destination_endpoint_guid */ + XG, /* ddsi_guid_t source_endpoint_guid */ + XS, /* char* message_class_id */ + XQ, /* nn_dataholderseq_t message_data */ + /* nn_dataholder_t */ + XS, /* char* class_id */ + XQ, /* dds_propertyseq_t properties */ + XbPROP, XS, XS, /* dds_property_t */ + XSTOP, + XQ, /* dds_binarypropertyseq_t binary_properties */ + XbPROP, XS, XO, /* dds_binaryproperty_t */ + XSTOP, + XSTOP, + XSTOP /* end */ +}; +const size_t pserop_participant_generic_message_nops = sizeof (pserop_participant_generic_message) / sizeof (pserop_participant_generic_message[0]); + +static void +alias_simple_sequence(ddsi_octetseq_t *dst, const ddsi_octetseq_t *src, size_t elem_size) +{ + dst->length = src->length; + if (src->length > 0) + { + /* Even when aliased, sequence buffers are not shared. */ + dst->value = ddsrt_memdup(src->value, src->length * elem_size); + } + else + dst->value = NULL; +} + +static void +alias_dataholder(nn_dataholder_t *dst, const nn_dataholder_t *src) +{ + dst->class_id = src->class_id; + alias_simple_sequence((ddsi_octetseq_t*)&dst->properties, + (const ddsi_octetseq_t*)&src->properties, + sizeof(dds_property_t)); + alias_simple_sequence((ddsi_octetseq_t*)&dst->binary_properties, + (const ddsi_octetseq_t*)&src->binary_properties, + sizeof(dds_binaryproperty_t)); +} + +static void +alias_dataholderseq(nn_dataholderseq_t *dst, const nn_dataholderseq_t *src) +{ + dst->n = src->n; + if (src->n > 0) + { + /* Even when aliased, sequence buffers are not shared. */ + dst->tags = ddsrt_malloc(src->n * sizeof(nn_dataholder_t)); + for (uint32_t i = 0; i < src->n; i++) + { + alias_dataholder(&(dst->tags[i]), &(src->tags[i])); + } + } + else + dst->tags = NULL; +} + +void +nn_participant_generic_message_init( + nn_participant_generic_message_t *msg, + const ddsi_guid_t *wrguid, + int64_t wrseq, + const ddsi_guid_t *dstpguid, + const ddsi_guid_t *dsteguid, + const ddsi_guid_t *srceguid, + const char *classid, + const nn_dataholderseq_t *mdata, + const nn_message_identity_t *rmid) +{ + assert(msg); + assert(wrguid); + assert(classid); + + memset(msg, 0, sizeof(*msg)); + + msg->message_identity.source_guid = *wrguid; + msg->message_identity.sequence_number = wrseq; + + if (rmid) + { + msg->related_message_identity.source_guid = rmid->source_guid; + msg->related_message_identity.sequence_number = rmid->sequence_number; + } + + if (dstpguid) + msg->destination_participant_guid = *dstpguid; + + if (dsteguid) + msg->destination_endpoint_guid = *dsteguid; + + if (srceguid) + msg->source_endpoint_guid = *srceguid; + + msg->message_class_id = classid; + + if (mdata) + alias_dataholderseq(&msg->message_data, mdata); +} + +void +nn_participant_generic_message_deinit( + nn_participant_generic_message_t *msg) +{ + assert(msg); + plist_fini_generic(msg, pserop_participant_generic_message, true); +} + +dds_return_t +nn_participant_generic_message_serialize( + const nn_participant_generic_message_t *msg, + unsigned char **data, + size_t *len) +{ + return plist_ser_generic ((void**)data, len, (void*)msg, pserop_participant_generic_message); +} + +dds_return_t +nn_participant_generic_message_deseralize( + nn_participant_generic_message_t *msg, + const unsigned char *data, + size_t len, + bool bswap) +{ + assert(sizeof(nn_participant_generic_message_t) == plist_memsize_generic(pserop_participant_generic_message)); + return plist_deser_generic (msg, data, len, bswap, pserop_participant_generic_message); +} + +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); + ddsrt_iovec_t guid_ref = { .iov_len=0, .iov_base=NULL }; + ddsi_guid_t *msg_guid; + ddsi_guid_t pp_guid; + int pass; + + DDSRT_UNUSED_ARG(wr); + + assert(wr); + assert(prd); + assert(serdata); + + /* 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; + + pass = is_null_guid(msg_guid); + if (!pass) + { + pp_guid = nn_hton_guid(prd->c.proxypp->e.guid); + pass = guid_eq(msg_guid, &pp_guid); + } + + ddsi_serdata_to_ser_unref(serdata, &guid_ref); + + return pass; +} diff --git a/src/core/ddsi/src/ddsi_security_omg.c b/src/core/ddsi/src/ddsi_security_omg.c new file mode 100644 index 0000000..92c9529 --- /dev/null +++ b/src/core/ddsi/src/ddsi_security_omg.c @@ -0,0 +1,4014 @@ +/* + * 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/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" +#include "dds/ddsrt/sync.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/dds_security_plugins.h" +#include "dds/ddsrt/hopscotch.h" + +#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" + +/* TODO: This constant which determines the time pending matches are maintained + * and not used should be made a configurable parameter, + */ +#define PENDING_MATCH_EXPIRY_TIME 300 + +#define EXCEPTION_LOG(gv,e,cat,...) \ + q_omg_log_exception(&gv->logconfig, cat, e, __FILE__, __LINE__, DDS_FUNCTION, __VA_ARGS__) +#define EXCEPTION_VLOG(gv,e,cat,fmt,ap) \ + q_omg_vlog_exception(&gv->logconfig, cat, e, __FILE__, __LINE__, DDS_FUNCTION, fmt, ap) + +#define EXCEPTION_ERROR(gv,e,...) EXCEPTION_LOG(gv, e, DDS_LC_ERROR, __VA_ARGS__) +#define EXCEPTION_WARNING(gv,e,...) EXCEPTION_LOG(gv, e, DDS_LC_WARNING, __VA_ARGS__) + + +#define SECURITY_ATTR_IS_VALID(attr) \ + ((attr) & NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID) + +/* 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)) \ +) + +/* 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) +{ + return ((guid->entityid.u == NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER) || + (guid->entityid.u == NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_READER)); +} + +static bool endpoint_is_DCPSPublicationsSecure (const ddsi_guid_t *guid) +{ + return ((guid->entityid.u == NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER) || + (guid->entityid.u == NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_READER)); +} + +static bool endpoint_is_DCPSSubscriptionsSecure (const ddsi_guid_t *guid) +{ + return ((guid->entityid.u == NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER) || + (guid->entityid.u == NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER)); +} + +static bool endpoint_is_DCPSParticipantStatelessMessage (const ddsi_guid_t *guid) +{ + return ((guid->entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER) || + (guid->entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER)); +} + +static bool endpoint_is_DCPSParticipantMessageSecure (const ddsi_guid_t *guid) +{ + return ((guid->entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER) || + (guid->entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER)); +} + +static bool endpoint_is_DCPSParticipantVolatileMessageSecure (const ddsi_guid_t *guid) +{ + return ((guid->entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER) || + (guid->entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER)); +} + +struct participant_sec_index { + ddsrt_mutex_t lock; + ddsrt_avl_ctree_t participants; +}; + +/* The pending _match_index uses an avl tree to store pending_match's where the + * guid_pair is used as the key. The remote_guid is the primary key and + * the local_guid is the secondary key. The use of the remote_guid as the primary key + * is used in the function clear_pending_matches_by_remote_guid to clear the + * pending matches associated with a remote entity. + * + * The table containing the pending matches is protected by the pending_match_index:lock. + * It is allowed to access the fields (crypto_handle and tokens) of a pending_match outside + * the pending_match_index:lock provided that the pending_match is protected by the + * lock of the entity corresponding to the local_guid. + * A pending_match is either created when registering and matching an remote entity and + * the corresponding crypto tokens are not available or when the crypto tokens associated + * with a remote entity are received but it has not yet been discovered. + */ +struct guid_pair { + ddsi_guid_t remote_guid; + ddsi_guid_t local_guid; +}; + +struct pending_match { + ddsrt_avl_node_t avlnode; + ddsrt_fibheap_node_t heapnode; + struct guid_pair guids; + enum entity_kind kind; + int64_t crypto_handle; + DDS_Security_ParticipantCryptoTokenSeq *tokens; + ddsrt_mtime_t expiry; +}; + +struct pending_match_index { + ddsrt_mutex_t lock; + const struct ddsi_domaingv *gv; + ddsrt_avl_tree_t pending_matches; + ddsrt_fibheap_t expiry_timers; + struct xevent *evt; +}; + +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 pending_match_index security_matches; + struct participant_sec_index partiticpant_index; + struct dds_security_access_control_listener ac_listener; + struct dds_security_authentication_listener auth_listener; +}; + +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); +static int compare_pending_match_exptime (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_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); +const ddsrt_avl_treedef_t pending_match_index_treedef = + DDSRT_AVL_TREEDEF_INITIALIZER (offsetof (struct pending_match, avlnode), offsetof (struct pending_match, guids), compare_guid_pair, 0); + +const ddsrt_fibheap_def_t pending_match_expiry_fhdef = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (struct pending_match, heapnode), compare_pending_match_exptime); + + +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 *gpa = va; + const struct guid_pair *gpb = vb; + int r; + + if ((r = guid_compare(&gpa->remote_guid, &gpb->remote_guid)) == 0) + r = guid_compare(&gpa->local_guid, &gpb->local_guid); + return r; +} + +static int compare_pending_match_exptime (const void *va, const void *vb) +{ + const struct pending_match *ma = va; + const struct pending_match *mb = vb; + return (ma->expiry.v == mb->expiry.v) ? 0 : (ma->expiry.v < mb->expiry.v) ? -1 : 1; +} + +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_access_control *q_omg_participant_get_access_control(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->access_control_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; +} + +struct dds_security_cryptography *q_omg_participant_get_cryptography(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->crypto_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_vlog_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, va_list ap) +{ + char logbuffer[512]; + int l; + + l = vsnprintf(logbuffer, sizeof(logbuffer), fmt, 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); +} + +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, ...) +{ + va_list ap; + va_start (ap, fmt); + q_omg_vlog_exception(lc, cat, exception, file, line, func, fmt, ap); + va_end (ap); +} + +static void free_pending_match(struct pending_match *match) +{ + if (match) + { + DDS_Security_ParticipantCryptoTokenSeq_free(match->tokens); + ddsrt_free(match); + } +} + +static void pending_match_expiry_cb(struct xevent *xev, void *varg, ddsrt_mtime_t tnow); + +static struct pending_match * find_or_create_pending_entity_match(struct pending_match_index *index, enum entity_kind kind, const ddsi_guid_t *remote_guid, const ddsi_guid_t *local_guid, int64_t crypto_handle, DDS_Security_ParticipantCryptoTokenSeq *tokens) +{ + struct guid_pair guids = { .remote_guid = *remote_guid, .local_guid = *local_guid}; + struct pending_match *match; + ddsrt_avl_ipath_t ipath; + + ddsrt_mutex_lock(&index->lock); + if ((match = ddsrt_avl_lookup_ipath(&pending_match_index_treedef, &index->pending_matches, &guids, &ipath)) == NULL) + { + match = ddsrt_malloc(sizeof(*match)); + match->crypto_handle = 0; + match->tokens = NULL; + match->guids = guids; + match->kind = kind; + match->expiry = DDSRT_MTIME_NEVER; + ddsrt_avl_insert_ipath(&pending_match_index_treedef, &index->pending_matches, match, &ipath); + } + + if (crypto_handle) + match->crypto_handle = crypto_handle; + + if (tokens) + { + match->tokens = tokens; + match->expiry = ddsrt_mtime_add_duration(ddsrt_time_monotonic(), DDS_SECS(PENDING_MATCH_EXPIRY_TIME)); + ddsrt_fibheap_insert(&pending_match_expiry_fhdef, &index->expiry_timers, match); + (void)resched_xevent_if_earlier(index->evt, match->expiry); + } + ddsrt_mutex_unlock(&index->lock); + + return match; +} + +static void unregister_and_free_pending_match(const struct ddsi_domaingv * gv, dds_security_context *sc, struct pending_match *match) +{ + if (match->crypto_handle != 0) + { + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + const char *ename; + bool r = true; + + switch (match->kind) + { + case EK_PROXY_PARTICIPANT: + break; + case EK_PROXY_READER: + ename = "reader"; + r = sc->crypto_context->crypto_key_factory->unregister_datareader(sc->crypto_context->crypto_key_factory, match->crypto_handle, &exception); + break; + case EK_PROXY_WRITER: + ename = "writer"; + r = sc->crypto_context->crypto_key_factory->unregister_datawriter(sc->crypto_context->crypto_key_factory, match->crypto_handle, &exception); + break; + default: + assert(0); + break; + } + if (!r) + EXCEPTION_ERROR(gv, &exception, "Failed to unregister remote %s crypto "PGUIDFMT" related to "PGUIDFMT, ename, PGUID(match->guids.remote_guid), PGUID(match->guids.local_guid)); + } + free_pending_match(match); +} + +static void delete_pending_match(struct pending_match_index *index, struct pending_match *match) +{ + ddsrt_mutex_lock(&index->lock); + ddsrt_avl_delete(&pending_match_index_treedef, &index->pending_matches, match); + if (match->expiry.v != DDS_NEVER) + ddsrt_fibheap_delete(&pending_match_expiry_fhdef, &index->expiry_timers, match); + free_pending_match(match); + ddsrt_mutex_unlock(&index->lock); +} + +static void pending_match_expiry_cb(struct xevent *xev, void *varg, ddsrt_mtime_t tnow) +{ + struct pending_match_index *index = varg; + + ddsrt_mutex_lock(&index->lock); + struct pending_match *match = ddsrt_fibheap_min(&pending_match_expiry_fhdef, &index->expiry_timers); + while (match && match->expiry.v <= tnow.v) + { + ddsrt_fibheap_delete(&pending_match_expiry_fhdef, &index->expiry_timers, match); + ddsrt_avl_delete(&pending_match_index_treedef, &index->pending_matches, match); + unregister_and_free_pending_match(index->gv, index->gv->security_context, match); + match = ddsrt_fibheap_min(&pending_match_expiry_fhdef, &index->expiry_timers); + } + if (match) + resched_xevent_if_earlier(xev, match->expiry); + ddsrt_mutex_unlock(&index->lock); +} + +static void clear_pending_matches_by_local_guid(dds_security_context *sc, struct pending_match_index *index, const ddsi_guid_t *local_guid) +{ + struct pending_match *match; + + ddsrt_mutex_lock(&index->lock); + match = ddsrt_avl_find_min(&pending_match_index_treedef, &index->pending_matches); + while (match) + { + struct pending_match *next = ddsrt_avl_find_succ(&pending_match_index_treedef, &index->pending_matches, match); + if (guid_compare(&match->guids.local_guid, local_guid) == 0) + { + ddsrt_avl_delete(&pending_match_index_treedef, &index->pending_matches, match); + if (match->expiry.v != DDS_NEVER) + ddsrt_fibheap_delete(&pending_match_expiry_fhdef, &index->expiry_timers, match); + next = ddsrt_avl_lookup_succ(&pending_match_index_treedef, &index->pending_matches, &match->guids); + unregister_and_free_pending_match(index->gv, sc, match); + } + match = next; + } + ddsrt_mutex_unlock(&index->lock); +} + +static void clear_pending_matches_by_remote_guid(dds_security_context *sc, struct pending_match_index *index, const ddsi_guid_t *remote_guid) +{ + struct guid_pair template = { .remote_guid = *remote_guid, .local_guid = {.prefix.u = {0, 0, 0}, .entityid.u = 0} }; + struct pending_match *match; + + ddsrt_mutex_lock(&index->lock); + match = ddsrt_avl_lookup_succ(&pending_match_index_treedef, &index->pending_matches, &template); + while (match && guid_compare(&match->guids.remote_guid, remote_guid) == 0) + { + struct pending_match *next = ddsrt_avl_lookup_succ(&pending_match_index_treedef, &index->pending_matches, &match->guids); + ddsrt_avl_delete(&pending_match_index_treedef, &index->pending_matches, match); + if (match->expiry.v != DDS_NEVER) + ddsrt_fibheap_delete(&pending_match_expiry_fhdef, &index->expiry_timers, match); + unregister_and_free_pending_match(index->gv, sc, match); + match = next; + } + ddsrt_mutex_unlock(&index->lock); +} + +static void pending_match_index_init(const struct ddsi_domaingv *gv, struct pending_match_index *index) +{ + ddsrt_mutex_init(&index->lock); + ddsrt_avl_init(&pending_match_index_treedef, &index->pending_matches); + ddsrt_fibheap_init(&pending_match_expiry_fhdef, &index->expiry_timers); + index->gv = gv; + index->evt = qxev_callback(gv->xevents, DDSRT_MTIME_NEVER, pending_match_expiry_cb, index);; +} + +static void pending_match_index_deinit(struct pending_match_index *index) +{ + delete_xevent_callback(index->evt); + ddsrt_mutex_destroy(&index->lock); + assert(ddsrt_avl_is_empty(&index->pending_matches)); + ddsrt_avl_free(&pending_match_index_treedef, &index->pending_matches, 0); +} + +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; + pm->authenticated = false; + + return pm; +} + +static void proxypp_pp_match_free(struct ddsi_domaingv *gv, 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)) + { + /* FIXME: enable exception warning when access control is updated to return a permission handle for each + * matching local and remote participant. + */ +#if 0 + EXCEPTION_ERROR(gv, &exception, "Failed to return remote permissions handle"); +#else + DDSRT_UNUSED_ARG (gv); + DDS_Security_Exception_reset(&exception); +#endif + } + } + ddsrt_free(pm); +} + +static void pp_proxypp_unrelate_locked(struct dds_security_context *sc, struct participant *pp, const ddsi_guid_t *proxypp_guid) +{ + struct pp_proxypp_match *pm; + ddsrt_avl_dpath_t dpath; + + 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); + } +} + +static void pp_proxypp_unrelate(struct dds_security_context *sc, struct participant *pp, const ddsi_guid_t *proxypp_guid) +{ + ddsrt_mutex_lock(&pp->sec_attr->lock); + pp_proxypp_unrelate_locked (sc, pp, proxypp_guid); + ddsrt_mutex_unlock(&pp->sec_attr->lock); +} + +static void proxypp_pp_unrelate_locked(struct dds_security_context *sc, struct proxy_participant *proxypp, const ddsi_guid_t *pp_guid, int64_t pp_crypto_handle) +{ + DDSRT_UNUSED_ARG(pp_guid); + struct proxypp_pp_match *pm; + ddsrt_avl_dpath_t dpath; + + 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(proxypp->e.gv, sc, pm); + } +} + +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) + { + ddsrt_mutex_lock(&proxypp->sec_attr->lock); + proxypp_pp_unrelate_locked(sc, proxypp, pp_guid, pp_crypto_handle); + 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) +{ + return (sc->crypto_context != NULL || sc->authentication_context != NULL || sc->access_control_context != NULL); +} + +void q_omg_security_init (struct ddsi_domaingv *gv) +{ + dds_security_context *sc; + + sc = ddsrt_malloc (sizeof (dds_security_context)); + memset (sc, 0, sizeof (dds_security_context)); + + sc->auth_plugin.name = AUTH_NAME; + sc->ac_plugin.name = AC_NAME; + sc->crypto_plugin.name = CRYPTO_NAME; + + ddsrt_mutex_init(&sc->partiticpant_index.lock); + ddsrt_avl_cinit(&participant_index_treedef, &sc->partiticpant_index.participants); + pending_match_index_init(gv, &sc->security_matches); + + ddsrt_mutex_init (&sc->omg_security_lock); + gv->security_context = sc; + + if (gv->config.omg_security_configuration) + gv->handshake_include_optional = gv->config.omg_security_configuration->cfg.authentication_properties.include_optional_fields != 0; + else + gv->handshake_include_optional = false; + + ddsi_handshake_admin_init(gv); +} + +/** + * Releases all plugins + */ +static void release_plugins (struct ddsi_domaingv *gv, dds_security_context *sc) +{ + if (dds_security_plugin_release (&sc->auth_plugin, sc->authentication_context)) + GVERROR ("Error occurred releasing %s plugin", sc->auth_plugin.name); + + if (dds_security_plugin_release (&sc->crypto_plugin, sc->crypto_context)) + GVERROR ("Error occurred releasing %s plugin", sc->crypto_plugin.name); + + if (dds_security_plugin_release (&sc->ac_plugin, sc->access_control_context)) + GVERROR ("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_stop (struct ddsi_domaingv *gv) +{ + ddsi_handshake_admin_stop(gv); +} + +void q_omg_security_deinit (struct dds_security_context *sc) +{ + pending_match_index_deinit(&sc->security_matches); +} + +void q_omg_security_free (struct ddsi_domaingv *gv) +{ + dds_security_context *sc = gv->security_context; + + ddsrt_avl_cfree(&participant_index_treedef, &sc->partiticpant_index.participants, 0); + ddsrt_mutex_destroy(&sc->partiticpant_index.lock); + + if (sc->authentication_context != NULL && sc->access_control_context != NULL && sc->crypto_context != NULL) + release_plugins (gv, sc); + + ddsi_handshake_admin_deinit(gv); + ddsrt_mutex_destroy (&sc->omg_security_lock); + ddsrt_free(sc); + gv->security_context = NULL; +} + +static void dds_qos_to_security_plugin_configuration (const dds_qos_t *qos, dds_security_plugin_suite_config *suite_config) +{ + const struct { const char *name; size_t offset; } tab[] = { + { DDS_SEC_PROP_AUTH_LIBRARY_PATH, offsetof (dds_security_plugin_suite_config, authentication.library_path) }, + { DDS_SEC_PROP_AUTH_LIBRARY_INIT, offsetof (dds_security_plugin_suite_config, authentication.library_init) }, + { DDS_SEC_PROP_AUTH_LIBRARY_FINALIZE, offsetof (dds_security_plugin_suite_config, authentication.library_finalize) }, + { DDS_SEC_PROP_CRYPTO_LIBRARY_PATH, offsetof (dds_security_plugin_suite_config, cryptography.library_path) }, + { DDS_SEC_PROP_CRYPTO_LIBRARY_INIT, offsetof (dds_security_plugin_suite_config, cryptography.library_init) }, + { DDS_SEC_PROP_CRYPTO_LIBRARY_FINALIZE, offsetof (dds_security_plugin_suite_config, cryptography.library_finalize) }, + { DDS_SEC_PROP_ACCESS_LIBRARY_PATH, offsetof (dds_security_plugin_suite_config, access_control.library_path) }, + { DDS_SEC_PROP_ACCESS_LIBRARY_INIT, offsetof (dds_security_plugin_suite_config, access_control.library_init) }, + { DDS_SEC_PROP_ACCESS_LIBRARY_FINALIZE, offsetof (dds_security_plugin_suite_config, access_control.library_finalize) } + }; + + for (size_t i = 0; i < qos->property.value.n; i++) + for (size_t j = 0; j < sizeof (tab) / sizeof (tab[0]); j++) + if (strcmp (qos->property.value.props[i].name, tab[j].name) == 0) + *((char **) ((char *) suite_config + tab[j].offset)) = ddsrt_strdup (qos->property.value.props[i].value); +} + +static void deinit_plugin_config (dds_security_plugin_config *plugin_config) +{ + ddsrt_free (plugin_config->library_path); + ddsrt_free (plugin_config->library_init); + ddsrt_free (plugin_config->library_finalize); +} + +static void deinit_plugin_suite_config (dds_security_plugin_suite_config *suite_config) +{ + deinit_plugin_config (&suite_config->access_control); + deinit_plugin_config (&suite_config->authentication); + deinit_plugin_config (&suite_config->cryptography); +} + +typedef bool (*expired_pp_check_fn_t)(const struct participant * pp, DDS_Security_Handle handle); +typedef bool (*expired_proxypp_check_fn_t)(const struct proxy_participant * proxypp, DDS_Security_Handle handle); + +static bool delete_pp_by_handle (DDS_Security_Handle handle, expired_pp_check_fn_t expired_pp_check_fn, struct ddsi_domaingv *gv) +{ + struct participant *pp; + struct entidx_enum_participant epp; + bool result = false; + entidx_enum_participant_init (&epp, gv->entity_index); + while ((pp = entidx_enum_participant_next (&epp)) != NULL) + { + if (q_omg_participant_is_secure (pp) && expired_pp_check_fn (pp, handle)) + { + (void) delete_participant (gv, &pp->e.guid); + result = true; + } + } + entidx_enum_participant_fini (&epp); + return result; +} + +static bool delete_proxypp_by_handle (const DDS_Security_Handle handle, expired_proxypp_check_fn_t expired_proxypp_check_fn, struct ddsi_domaingv *gv) +{ + struct proxy_participant *proxypp; + struct entidx_enum_proxy_participant eproxypp; + bool result = false; + entidx_enum_proxy_participant_init (&eproxypp, gv->entity_index); + while ((proxypp = entidx_enum_proxy_participant_next (&eproxypp)) != NULL) + { + if (q_omg_proxy_participant_is_secure(proxypp) && expired_proxypp_check_fn (proxypp, handle)) + { + (void) delete_proxy_participant_by_guid (gv, &proxypp->e.guid, ddsrt_time_wallclock (), true); + result = true; + } + } + entidx_enum_proxy_participant_fini (&eproxypp); + return result; +} + +static bool pp_expired_by_perm (const struct participant * pp, DDS_Security_Handle handle) +{ + return pp->sec_attr->permissions_handle == handle; +} + +static bool proxypp_expired_by_perm (const struct proxy_participant * proxypp, DDS_Security_Handle handle) +{ + bool result = false; + uint32_t i = 0; + ddsrt_avl_iter_t it; + ddsrt_mutex_lock (&proxypp->sec_attr->lock); + for (struct proxypp_pp_match *ppm = ddsrt_avl_iter_first (&proxypp_pp_treedef, &proxypp->sec_attr->participants, &it); ppm; ppm = ddsrt_avl_iter_next (&it), i++) + { + if (ppm->permissions_handle == handle) + { + result = true; + break; + } + } + ddsrt_mutex_unlock (&proxypp->sec_attr->lock); + return result; +} + +static bool pp_expired_by_id (const struct participant * pp, DDS_Security_Handle handle) +{ + return pp->sec_attr->local_identity_handle == handle; +} + +static bool proxypp_expired_by_id (const struct proxy_participant * proxypp, DDS_Security_Handle handle) +{ + return proxypp->sec_attr->remote_identity_handle == handle; +} + +/* When a local identity (i.e. the identity of a local participant) or + a local permissions handle (bound to a local participant) expires, + the participant will be deleted. Strictly speaking, as described in the DDS + Security specification, the communication for this partcipant should be + stopped. A possible interpretation is that the participant and its + depending endpoints remain alive in 'expired' state and e.g. unread data + that was received earlier could still be retrieved by the application. + As we considered this as an edge case that would not be used widely, + the current implementation simply deletes the DDSI participant and leaves + the participant entity in the API in an invalid state, which could result + in error codes when calling API functions on these entities. This approach + dramatically simplifies the code for handling the revocation of permission + and identity handles. + + For remote identity revocation, in case any of the permission handles + in a pp-match of a proxy participant is expired, the proxy participant + is deleted, as the expired permission grant for a (remote) participant + applies to the participant as a whole (bound to its subject of the + identity certificate used by the participant) */ +static DDS_Security_boolean on_revoke_permissions_cb(const dds_security_access_control *plugin, const DDS_Security_PermissionsHandle handle) +{ + struct ddsi_domaingv *gv = plugin->gv; + thread_state_awake (lookup_thread_state (), gv); + + if (!delete_pp_by_handle (handle, pp_expired_by_perm, gv)) + delete_proxypp_by_handle (handle, proxypp_expired_by_perm, gv); + + thread_state_asleep (lookup_thread_state ()); + return true; +} + +/* See comment above on_revoke_permissions_cb */ +static DDS_Security_boolean on_revoke_identity_cb(const dds_security_authentication *plugin, const DDS_Security_IdentityHandle handle) +{ + struct ddsi_domaingv *gv = plugin->gv; + thread_state_awake (lookup_thread_state (), gv); + + if (!delete_pp_by_handle (handle, pp_expired_by_id, gv)) + delete_proxypp_by_handle (handle, proxypp_expired_by_id, gv); + + thread_state_asleep (lookup_thread_state ()); + return true; +} + +dds_return_t q_omg_security_load (dds_security_context *sc, const dds_qos_t *qos, struct ddsi_domaingv *gv) +{ + dds_security_plugin_suite_config psc; + memset (&psc, 0, sizeof (psc)); + + ddsrt_mutex_lock (&sc->omg_security_lock); + + /* Get plugin information */ + dds_qos_to_security_plugin_configuration (qos, &psc); + + /* Check configuration content */ + if (dds_security_check_plugin_configuration (&psc, gv) != DDS_RETCODE_OK) + goto error; + + if (dds_security_load_security_library (&psc.authentication, &sc->auth_plugin, (void **) &sc->authentication_context, gv) != DDS_RETCODE_OK) + { + GVERROR ("Could not load %s plugin.\n", sc->auth_plugin.name); + goto error; + } + if (dds_security_load_security_library (&psc.access_control, &sc->ac_plugin, (void **) &sc->access_control_context, gv) != DDS_RETCODE_OK) + { + GVERROR ("Could not load %s library\n", sc->ac_plugin.name); + goto error; + } + if (dds_security_load_security_library (&psc.cryptography, &sc->crypto_plugin, (void **) &sc->crypto_context, gv) != DDS_RETCODE_OK) + { + GVERROR ("Could not load %s library\n", sc->crypto_plugin.name); + goto error; + } + + /* now check if all plugin functions are implemented */ + if (dds_security_verify_plugin_functions (sc->authentication_context, &sc->auth_plugin, sc->crypto_context, &sc->crypto_plugin, + sc->access_control_context, &sc->ac_plugin, gv) != DDS_RETCODE_OK) + { + goto error_verify; + } + + /* Add listeners */ + DDS_Security_SecurityException ex = DDS_SECURITY_EXCEPTION_INIT; + sc->ac_listener.on_revoke_permissions = on_revoke_permissions_cb; + if (!sc->access_control_context->set_listener (sc->access_control_context, &sc->ac_listener, &ex)) + { + GVERROR ("Could not set access_control listener: %s\n", ex.message ? ex.message : ""); + goto error_set_ac_listener; + } + sc->auth_listener.on_revoke_identity = on_revoke_identity_cb; + if (!sc->authentication_context->set_listener (sc->authentication_context, &sc->auth_listener, &ex)) + { + GVERROR ("Could not set authentication listener: %s\n", ex.message ? ex.message : ""); + goto error_set_auth_listener; + } + +#if HANDSHAKE_IMPLEMENTED + (void) q_handshake_initialize (); +#endif + + deinit_plugin_suite_config (&psc); + ddsrt_mutex_unlock (&sc->omg_security_lock); + GVTRACE ("DDS Security plugins have been loaded\n"); + return DDS_RETCODE_OK; + +error_set_auth_listener: + sc->access_control_context->set_listener (sc->access_control_context, NULL, &ex); +error_set_ac_listener: +error_verify: + release_plugins (gv, sc); +error: + deinit_plugin_suite_config (&psc); + ddsrt_mutex_unlock (&sc->omg_security_lock); + return DDS_RETCODE_ERROR; +} + +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); + } +} + +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) +{ + return (proxypp->sec_attr != NULL); +} + +bool q_omg_participant_allow_unauthenticated(struct participant *pp) +{ + return ((pp->sec_attr != NULL) && pp->sec_attr->attr.allow_unauthenticated_participants); +} + +dds_return_t q_omg_security_check_create_participant(struct participant *pp, uint32_t domain_id) +{ + dds_return_t ret = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; + struct dds_security_context *sc = q_omg_security_get_secure_context(pp); + struct ddsi_domaingv *gv = pp->e.gv; + 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 DDS_RETCODE_OK; + + /* 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(gv, &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(gv, &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(gv, &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(gv, &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(gv, &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(gv, &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(gv, &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(gv, &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(gv, &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"); + + ret = DDS_RETCODE_OK; + +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 (ret != DDS_RETCODE_OK) + participant_sec_attributes_free(sec_attr); +validation_failed: + q_omg_shallow_free_security_qos(&par_qos); + return ret; +} + +void q_omg_security_participant_set_initialized(struct participant *pp) +{ + 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; + + GVTRACE("cleanup participant "PGUIDFMT" security attributes\n", PGUID(attr->pp_guid)); + + 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(gv, &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(gv, &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(gv, &exception, "Failed to return participant security attributes"); + } + + if (!sc->crypto_context->crypto_key_factory->unregister_participant(sc->crypto_context->crypto_key_factory, attr->crypto_handle, &exception)) + EXCEPTION_ERROR(gv, &exception, "Failed to unregister participant"); + + 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); + } + + clear_pending_matches_by_local_guid(sc, &sc->security_matches, &pp->e.guid); + + 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; + + return false; +} + +static void q_omg_get_endpoint_security_info(DDS_Security_EndpointSecurityAttributes *attr, nn_security_info_t *info) +{ + 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; + bool result = false; + + if (access_control->get_topic_sec_attributes(access_control, permission_handle, topic_name, &attributes, &exception)) + { + result = attributes.is_discovery_protected; + access_control->return_topic_sec_attributes(access_control, &attributes, &exception); + } + else + { + DDS_Security_Exception_reset(&exception); + } + return result; +} + +static void handle_not_allowed( + const struct ddsi_domaingv *gv, + DDS_Security_PermissionsHandle permissions_handle, + dds_security_access_control * ac_ctx, + DDS_Security_SecurityException * exception, + const char * topic_name, + const char * fmt, + ...) ddsrt_attribute_format ((printf, 6, 7)); + +static void handle_not_allowed(const struct ddsi_domaingv *gv, DDS_Security_PermissionsHandle permissions_handle, dds_security_access_control * ac_ctx, + DDS_Security_SecurityException * exception, const char * topic_name, const char * fmt, ...) +{ + /* In case topic has discovery protection enabled: don't log in log category error, as the message + will contain the topic name which may be considered as sensitive information */ + va_list ap; + bool discovery_protected = is_topic_discovery_protected(permissions_handle, ac_ctx, topic_name); + va_start (ap, fmt); + EXCEPTION_VLOG(gv, exception, discovery_protected ? DDS_LC_TRACE : DDS_LC_ERROR, fmt, ap); + va_end (ap); + if (discovery_protected) + DDS_Security_Exception_reset(exception); +} + +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) + handle_not_allowed(gv, pp->sec_attr->permissions_handle, sc->access_control_context, &exception, topic_name, "Local topic permission denied"); + 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) + handle_not_allowed(pp->e.gv, pp->sec_attr->permissions_handle, sc->access_control_context, &exception, topic_name, "Writer is not permitted"); + + 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; + + 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(); + if (!sc->access_control_context->get_datawriter_sec_attributes(sc->access_control_context, pp->sec_attr->permissions_handle, wr->topic->name, &partitions, NULL, &wr->sec_attr->attr, &exception)) + { + EXCEPTION_ERROR(pp->e.gv, &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(pp->e.gv, &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) + { + clear_pending_matches_by_local_guid(sc, &sc->security_matches, &wr->e.guid); + + 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(wr->e.gv, &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(wr->e.gv, &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; +} + +bool q_omg_security_check_create_reader(struct participant *pp, uint32_t domain_id, const char *topic_name, const struct dds_qos *reader_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 (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) + handle_not_allowed(pp->e.gv, pp->sec_attr->permissions_handle, sc->access_control_context, &exception, topic_name, "Reader is not permitted"); + + q_omg_shallow_free_security_qos(&security_qos); + g_omg_shallow_free_StringSeq(&partitions.name); + + return result; +} + +void q_omg_security_register_reader(struct reader *rd) +{ + 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; + + 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(); + + if (!sc->access_control_context->get_datareader_sec_attributes(sc->access_control_context, pp->sec_attr->permissions_handle, rd->topic->name, &partitions, NULL, &rd->sec_attr->attr, &exception)) + { + EXCEPTION_ERROR(pp->e.gv, &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(pp->e.gv, &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); + + clear_pending_matches_by_local_guid(sc, &sc->security_matches, &rd->e.guid); + + 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(rd->e.gv, &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(rd->e.gv, &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; +} + +unsigned determine_subscription_writer(const struct reader *rd) +{ + if (q_omg_reader_is_discovery_protected (rd)) + return NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER; + else + return NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER; +} + +unsigned determine_publication_writer (const struct writer *wr) +{ + if (q_omg_writer_is_discovery_protected (wr)) + return NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER; + else + return NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER; +} + +static int64_t check_remote_participant_permissions(uint32_t domain_id, struct participant *pp, struct proxy_participant *proxypp, int64_t remote_identity_handle) +{ + 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; + struct ddsi_domaingv *gv = pp->e.gv; + + 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) + { + GVTRACE("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(gv, &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(gv, &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(gv, &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(gv, &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(gv, &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(gv, &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(gv, &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; +} + +static void send_participant_crypto_tokens(struct participant *pp, struct proxy_participant *proxypp, DDS_Security_ParticipantCryptoHandle local_crypto, DDS_Security_ParticipantCryptoHandle remote_crypto) +{ + 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(pp->e.gv, &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(pp->e.gv, &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(gv, &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" permissions=%"PRId64"\n", pp->sec_attr->crypto_handle, crypto_handle, permissions_handle); + match_proxypp_pp(pp, proxypp, permissions_handle, shared_secret); + + GVTRACE(" create proxypp-pp match pp="PGUIDFMT" proxypp="PGUIDFMT" lidh=%"PRId64"\n", PGUID(pp->e.guid), PGUID(proxypp->e.guid), pp->sec_attr->local_identity_handle); + + if (proxypp_is_rtps_protected(proxypp)) + { + struct pending_match *match = find_or_create_pending_entity_match(&sc->security_matches, EK_PROXY_PARTICIPANT, &proxypp->e.guid, &pp->e.guid, crypto_handle, NULL); + if (match->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, match->tokens, &exception); + if (!ret) + EXCEPTION_ERROR(gv, &exception, " Failed to set remote participant crypto tokens "PGUIDFMT" --> "PGUIDFMT, PGUID(proxypp->e.guid), PGUID(pp->e.guid)); + else + GVTRACE(" set participant tokens src("PGUIDFMT") to dst("PGUIDFMT") (by registering remote)\n", PGUID(proxypp->e.guid), PGUID(pp->e.guid)); + delete_pending_match(&sc->security_matches, match); + } + 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_set_remote_participant_authenticated(struct participant *pp, struct proxy_participant *proxypp) +{ + 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) + pm->authenticated = true; + ddsrt_mutex_unlock(&proxypp->sec_attr->lock); +} + +static bool is_volatile_secure_endpoint(ddsi_entityid_t entityid) +{ + return ((entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER) || (entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER)); +} + +static struct proxypp_pp_match * get_pp_proxypp_match_if_authenticated(struct participant *pp, struct proxy_participant *proxypp, ddsi_entityid_t entityid) +{ + 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) + { + if (!pm->authenticated && !is_volatile_secure_endpoint(entityid)) + pm = NULL; + } + ddsrt_mutex_unlock(&proxypp->sec_attr->lock); + return pm; +} + +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); + if ((pp = entidx_lookup_participant_guid(gv->entity_index, &pm->pp_guid)) != NULL) + pp_proxypp_unrelate(sc, pp, &proxypp->e.guid); + proxypp_pp_match_free(gv, sc, pm); + pm = next; + } + + clear_pending_matches_by_remote_guid(sc, &sc->security_matches, &proxypp->e.guid); + + 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(gv, &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(gv, &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) +{ + struct proxy_participant *proxypp; + + assert (gv); + assert (guid); + + /* TODO: Check if the proxy writer guid prefix matches that of the proxy + * participant. Deletion is not allowed when they're not equal. */ + + /* Always allow deletion from a secure proxy writer. */ + if (pwr_entityid.u == NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER) + return true; + + /* Not from a secure proxy writer. + * Only allow deletion when proxy participant is not authenticated. */ + proxypp = entidx_lookup_proxy_participant_guid (gv->entity_index, guid); + if (!proxypp) + { + GVLOGDISC (" unknown"); + return false; + } + + return (!proxypp_is_authenticated(proxypp)); +} + +bool q_omg_is_similar_participant_security_info(struct participant *pp, struct proxy_participant *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; + } + } + 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; + + if (!sc) + return; + + tseq = DDS_Security_DataHolderSeq_alloc(); + q_omg_copyin_DataHolderSeq(tseq, tokens); + + 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); + + if (!pm) + { + GVTRACE("remember participant tokens src("PGUIDFMT") dst("PGUIDFMT")\n", PGUID(proxypp->e.guid), PGUID(pp->e.guid)); + (void)find_or_create_pending_entity_match(&sc->security_matches, EK_PROXY_PARTICIPANT, &proxypp->e.guid, &pp->e.guid, 0, 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)) + { + 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(gv, &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; +} + +void set_proxy_participant_security_info(struct proxy_participant *proxypp, const ddsi_plist_t *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; + } else { + proxypp->security_info.security_attributes = 0; + proxypp->security_info.plugin_security_attributes = 0; + } +} + +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; + DDS_Security_TopicBuiltinTopicData topic_data; + + 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->c.security_info)) + return true; + + 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; + } + + q_omg_shallow_copy_PublicationBuiltinTopicDataSecure(&publication_data, &pwr->e.guid, pwr->c.xqos, &pwr->c.security_info); + bool result = sc->access_control_context->check_remote_datawriter(sc->access_control_context, permissions_handle, (int)domain_id, &publication_data, &exception); + if (!result) + { + handle_not_allowed(gv, pp->sec_attr->permissions_handle, sc->access_control_context, &exception, publication_data.topic_name, + "Access control does not allow remote writer "PGUIDFMT, PGUID(pwr->e.guid)); + } + else + { + q_omg_shallow_copy_TopicBuiltinTopicData(&topic_data, publication_data.topic_name, publication_data.type_name); + result = sc->access_control_context->check_remote_topic(sc->access_control_context, permissions_handle, (int)domain_id, &topic_data, &exception); + q_omg_shallow_free_TopicBuiltinTopicData(&topic_data); + if (!result) + handle_not_allowed(gv, pp->sec_attr->permissions_handle, sc->access_control_context, &exception, publication_data.topic_name, + "Access control does not allow remote topic %s", publication_data.topic_name); + } + q_omg_shallow_free_PublicationBuiltinTopicDataSecure(&publication_data); + + return result; +} + +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(gv, &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(gv, &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 *proxypp_match; + bool send_tokens = false; + bool allowed = false; + + if ((proxypp_match = get_pp_proxypp_match_if_authenticated(pp, proxypp, pwr->e.guid.entityid)) == NULL) + return false; + + ddsrt_mutex_lock(&rd->e.lock); + if (ddsrt_avl_lookup (&rd_writers_treedef, &rd->writers, &pwr->e.guid) != NULL) + allowed = true; + 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. */ + + *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, proxypp_match->shared_secret, &exception); + if (*crypto_handle != 0) + { + GVTRACE(" volatile secure reader: proxypp_crypto=%"PRId64" rd_crypto=%"PRId64" pwr_crypto=%"PRId64"\n", proxypp->sec_attr->crypto_handle, rd->sec_attr->crypto_handle, *crypto_handle); + allowed = true; + } + else + EXCEPTION_ERROR(gv, &exception, "Failed to register remote writer "PGUIDFMT" with reader "PGUIDFMT, PGUID(pwr->e.guid), PGUID(rd->e.guid)); + } + else + { + struct pending_match *pending_match = find_or_create_pending_entity_match(&sc->security_matches, EK_PROXY_WRITER, &pwr->e.guid, &rd->e.guid, 0, NULL); + + /* Generate writer crypto info. */ + if (pending_match->crypto_handle == 0) + { + *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, proxypp_match->shared_secret, &exception); + if (*crypto_handle == 0) + EXCEPTION_ERROR(gv, &exception, "Failed to register remote writer "PGUIDFMT" with reader "PGUIDFMT, PGUID(pwr->e.guid), PGUID(rd->e.guid)); + else + { + pending_match->crypto_handle = *crypto_handle; + send_tokens = true; + if (pending_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, *crypto_handle, pending_match->tokens, &exception)) + EXCEPTION_ERROR(gv, &exception, "Failed to set remote writer crypto tokens "PGUIDFMT" --> "PGUIDFMT, PGUID(pwr->e.guid), PGUID(rd->e.guid)); + else + { + GVTRACE("match_remote_writer "PGUIDFMT" with reader "PGUIDFMT": tokens available\n", PGUID(pwr->e.guid), PGUID(rd->e.guid)); + allowed = true; + } + delete_pending_match(&sc->security_matches, pending_match); + } + } + } + } + ddsrt_mutex_unlock(&rd->e.lock); + + if (send_tokens) + (void)send_reader_crypto_tokens(rd, pwr, rd->sec_attr->crypto_handle, *crypto_handle); + + return allowed; +} + +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; + + *crypto_handle = 0; + + 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->c.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->c.security_info.security_attributes, pwr->c.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->c.security_info.security_attributes)) { + pwr->c.security_info.security_attributes = info.security_attributes; + } + if (!SECURITY_ATTR_IS_VALID(pwr->c.security_info.plugin_security_attributes)) { + pwr->c.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; + + if (m->crypto_handle != 0) + { + if (!sc->crypto_context->crypto_key_factory->unregister_datawriter(sc->crypto_context->crypto_key_factory, m->crypto_handle, &exception)) + EXCEPTION_ERROR(gv, &exception, "Failed to unregister remote writer "PGUIDFMT" for reader "PGUIDFMT, PGUID(m->pwr_guid), PGUID(*rd_guid)); + } +} + +void q_omg_security_deregister_remote_writer(const struct proxy_writer *pwr) +{ + struct ddsi_domaingv *gv = pwr->e.gv; + struct dds_security_context *sc = gv->security_context; + + if (q_omg_proxy_participant_is_secure(pwr->c.proxypp)) + clear_pending_matches_by_remote_guid(sc, &sc->security_matches, &pwr->e.guid); +} + +bool q_omg_security_check_remote_reader_permissions(const struct proxy_reader *prd, uint32_t domain_id, struct participant *pp, bool *relay_only) +{ + 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_SubscriptionBuiltinTopicDataSecure subscription_data; + DDS_Security_TopicBuiltinTopicData topic_data; + DDS_Security_boolean sec_relay_only; + + /* relay_only is meaningless in all cases except the one where the access control plugin says otherwise */ + *relay_only = false; + + 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->c.security_info)) + return true; + + 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; + } + + q_omg_shallow_copy_SubscriptionBuiltinTopicDataSecure(&subscription_data, &prd->e.guid, prd->c.xqos, &prd->c.security_info); + bool result = sc->access_control_context->check_remote_datareader(sc->access_control_context, permissions_handle, (int)domain_id, &subscription_data, &sec_relay_only, &exception); + if (!result) + { + handle_not_allowed(gv, pp->sec_attr->permissions_handle, sc->access_control_context, &exception, subscription_data.topic_name, + "Access control does not allow remote reader "PGUIDFMT, PGUID(prd->e.guid)); + } + else + { + *relay_only = !!sec_relay_only; + q_omg_shallow_copy_TopicBuiltinTopicData(&topic_data, subscription_data.topic_name, subscription_data.type_name); + result = sc->access_control_context->check_remote_topic(sc->access_control_context, permissions_handle, (int)domain_id, &topic_data, &exception); + q_omg_shallow_free_TopicBuiltinTopicData(&topic_data); + if (!result) + handle_not_allowed(gv, pp->sec_attr->permissions_handle, sc->access_control_context, &exception, subscription_data.topic_name, + "Access control does not allow remote topic %s", subscription_data.topic_name); + } + q_omg_shallow_free_SubscriptionBuiltinTopicDataSecure(&subscription_data); + + return result; +} + +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); + + info->security_attributes = 0; + info->plugin_security_attributes = 0; + + /* + * If Security info is present, use that. + * Otherwise, use the specified values for the secure builtin endpoints. + * (Table 20 – EndpointSecurityAttributes for all "Builtin Security Endpoints") + * Otherwise, reset. + */ + if (plist->present & PP_ENDPOINT_SECURITY_INFO) + { + info->security_attributes = plist->endpoint_security_info.security_attributes; + info->plugin_security_attributes = plist->endpoint_security_info.plugin_security_attributes; + } + else if (endpoint_is_DCPSParticipantSecure (&entity->guid)|| + endpoint_is_DCPSPublicationsSecure (&entity->guid) || + endpoint_is_DCPSSubscriptionsSecure (&entity->guid)) + { + /* Discovery protection flags */ + info->plugin_security_attributes = NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID; + info->security_attributes = NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID; + if (proxypp_info_available) + { + if (proxypp_sec_info->security_attributes & NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_DISCOVERY_PROTECTED) + info->security_attributes |= NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_PROTECTED; + if (proxypp_sec_info->plugin_security_attributes & NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_DISCOVERY_ENCRYPTED) + info->plugin_security_attributes |= NN_PLUGIN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + if (proxypp_sec_info->plugin_security_attributes & NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_DISCOVERY_AUTHENTICATED) + info->plugin_security_attributes |= NN_PLUGIN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + else + { + /* No participant info: assume hardcoded OpenSplice V6.10.0 values. */ + info->security_attributes |= NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_PROTECTED; + info->plugin_security_attributes |= NN_PLUGIN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + } + } + else if (endpoint_is_DCPSParticipantMessageSecure (&entity->guid)) + { + /* Liveliness protection flags */ + info->plugin_security_attributes = NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID; + info->security_attributes = NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID; + if (proxypp_info_available) + { + if (proxypp_sec_info->security_attributes & NN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_LIVELINESS_PROTECTED) + info->security_attributes |= NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_PROTECTED; + if (proxypp_sec_info->plugin_security_attributes & NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_LIVELINESS_ENCRYPTED) + info->plugin_security_attributes |= NN_PLUGIN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + if (proxypp_sec_info->plugin_security_attributes & NN_PLUGIN_PARTICIPANT_SECURITY_ATTRIBUTES_FLAG_IS_LIVELINESS_AUTHENTICATED) + info->plugin_security_attributes |= NN_PLUGIN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + else + { + /* No participant info: assume hardcoded OpenSplice V6.10.0 values. */ + info->security_attributes |= NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_PROTECTED; + info->plugin_security_attributes |= NN_PLUGIN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + } + } + else if (endpoint_is_DCPSParticipantStatelessMessage (&entity->guid)) + { + info->security_attributes = NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID; + info->plugin_security_attributes = 0; + } + else if (endpoint_is_DCPSParticipantVolatileMessageSecure (&entity->guid)) + { + info->security_attributes = + NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_VALID | NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_PROTECTED; + info->plugin_security_attributes = 0; + } +} + +void q_omg_security_deregister_remote_reader_match(const struct ddsi_domaingv *gv, const ddsi_guid_t *wr_guid, struct wr_prd_match *m) +{ + struct dds_security_context *sc = gv->security_context; + DDS_Security_SecurityException exception = DDS_SECURITY_EXCEPTION_INIT; + + if (m->crypto_handle != 0) + { + if (!sc->crypto_context->crypto_key_factory->unregister_datareader(sc->crypto_context->crypto_key_factory, m->crypto_handle, &exception)) + EXCEPTION_ERROR(gv, &exception, "Failed to unregister remote reader "PGUIDFMT" for writer "PGUIDFMT, PGUID(m->prd_guid), PGUID(*wr_guid)); + } +} + +void q_omg_security_deregister_remote_reader(const struct proxy_reader *prd) +{ + struct ddsi_domaingv *gv = prd->e.gv; + struct dds_security_context *sc = gv->security_context; + + if (q_omg_proxy_participant_is_secure(prd->c.proxypp)) + clear_pending_matches_by_remote_guid(sc, &sc->security_matches, &prd->e.guid); +} + +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(gv, &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(gv, &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, bool relay_only) +{ + 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 *proxypp_match; + bool send_tokens = false; + bool allowed = false; + + if ((proxypp_match = get_pp_proxypp_match_if_authenticated(pp, proxypp, prd->e.guid.entityid)) == NULL) + return false; + + ddsrt_mutex_lock(&wr->e.lock); + if (ddsrt_avl_lookup (&wr_readers_treedef, &wr->readers, &prd->e.guid) != NULL) + allowed = true; + else if (wr->e.guid.entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER || !wr->sec_attr->attr.is_submessage_protected) + { + /* The builtin ParticipantVolatileSecure endpoints do not exchange tokens. + * Simulate that we already got them. */ + + *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, proxypp_match->shared_secret, relay_only, &exception); + if (*crypto_handle != 0) + { + GVTRACE(" match_remote_reader: proxypp_crypto=%"PRId64" wr_crypto=%"PRId64" prd_crypto=%"PRId64"\n", proxypp->sec_attr->crypto_handle, wr->sec_attr->crypto_handle, *crypto_handle); + send_tokens = (wr->e.guid.entityid.u != NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER); + allowed = true; + } + else + EXCEPTION_ERROR(gv, &exception, "Failed to register remote reader "PGUIDFMT" with writer "PGUIDFMT, PGUID(prd->e.guid), PGUID(wr->e.guid)); + } + else + { + struct pending_match *pending_match = find_or_create_pending_entity_match(&sc->security_matches, EK_PROXY_READER, &prd->e.guid, &wr->e.guid, 0, NULL); + + /* Generate writer crypto info. */ + if (pending_match->crypto_handle == 0) + { + *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, proxypp_match->shared_secret, relay_only, &exception); + if (*crypto_handle == 0) + EXCEPTION_ERROR(gv, &exception, "Failed to register remote reader "PGUIDFMT" with writer "PGUIDFMT, PGUID(prd->e.guid), PGUID(wr->e.guid)); + else + { + pending_match->crypto_handle = *crypto_handle; + send_tokens = true; + GVTRACE(" register_remote_reader_match: proxypp_crypto=%"PRId64" wr_crypto=%"PRId64" prd_crypto=%"PRId64"\n", proxypp->sec_attr->crypto_handle, wr->sec_attr->crypto_handle, *crypto_handle); + if (pending_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, *crypto_handle, pending_match->tokens, &exception)) + EXCEPTION_ERROR(gv, &exception, "Failed to set remote reader crypto tokens "PGUIDFMT" --> "PGUIDFMT, PGUID(prd->e.guid), PGUID(wr->e.guid)); + else + { + GVTRACE(" match_remote_reader "PGUIDFMT" with writer "PGUIDFMT": tokens available\n", PGUID(prd->e.guid), PGUID(wr->e.guid)); + allowed = true; + } + delete_pending_match(&sc->security_matches, pending_match); + } + } + } + } + ddsrt_mutex_unlock(&wr->e.lock); + + if (send_tokens) + (void)send_writer_crypto_tokens(wr, prd, wr->sec_attr->crypto_handle, *crypto_handle); + + return allowed; +} + +bool q_omg_security_match_remote_reader_enabled(struct writer *wr, struct proxy_reader *prd, bool relay_only, int64_t *crypto_handle) +{ + struct ddsi_domaingv *gv = wr->e.gv; + nn_security_info_t info; + + *crypto_handle = 0; + + 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->c.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->c.security_info.security_attributes, prd->c.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->c.security_info.security_attributes)) { + prd->c.security_info.security_attributes = info.security_attributes; + } + if (!SECURITY_ATTR_IS_VALID(prd->c.security_info.plugin_security_attributes)) { + prd->c.security_info.plugin_security_attributes = info.plugin_security_attributes; + } + + return q_omg_security_register_remote_reader_match(prd, wr, crypto_handle, relay_only); +} + +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 pending_match *match; + struct proxy_writer *pwr = NULL; + int64_t crypto_handle = 0; + + if (!sc) + return; + + DDS_Security_DatawriterCryptoTokenSeq * tseq = DDS_Security_DataHolderSeq_alloc(); + q_omg_copyin_DataHolderSeq(tseq, tokens); + + ddsrt_mutex_lock(&rd->e.lock); + match = find_or_create_pending_entity_match(&sc->security_matches, EK_PROXY_WRITER, pwr_guid, &rd->e.guid, 0, tseq); + 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)); + 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)) + EXCEPTION_ERROR(gv, &exception, "Failed to set remote writer crypto tokens "PGUIDFMT" for reader "PGUIDFMT, PGUID(pwr->e.guid), PGUID(rd->e.guid)); + else + { + GVTRACE("set_remote_writer_crypto_tokens "PGUIDFMT" with reader "PGUIDFMT"\n", PGUID(pwr->e.guid), PGUID(rd->e.guid)); + crypto_handle = match->crypto_handle; + } + delete_pending_match(&sc->security_matches, match); + } + ddsrt_mutex_unlock(&rd->e.lock); + + if (crypto_handle != 0) + connect_reader_with_proxy_writer_secure(rd, pwr, ddsrt_time_monotonic (), 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 pending_match *match; + struct proxy_reader *prd = NULL; + int64_t crypto_handle = 0; + + if (!sc) + return; + + DDS_Security_DatawriterCryptoTokenSeq *tseq = DDS_Security_DataHolderSeq_alloc(); + q_omg_copyin_DataHolderSeq(tseq, tokens); + + ddsrt_mutex_lock(&wr->e.lock); + match = find_or_create_pending_entity_match(&sc->security_matches, EK_PROXY_READER, prd_guid, &wr->e.guid, 0, tseq); + 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)); + 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)) + EXCEPTION_ERROR(gv, &exception, "Failed to set remote reader crypto tokens "PGUIDFMT" for writer "PGUIDFMT, PGUID(prd->e.guid), PGUID(wr->e.guid)); + else + { + GVTRACE("set_remote_reader_crypto_tokens "PGUIDFMT" with writer "PGUIDFMT"\n", PGUID(prd->e.guid), PGUID(wr->e.guid)); + crypto_handle = match->crypto_handle; + } + delete_pending_match(&sc->security_matches, match); + } + ddsrt_mutex_unlock(&wr->e.lock); + + if (crypto_handle != 0) + connect_writer_with_proxy_reader_secure(wr, prd, ddsrt_time_monotonic (), 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), rd->topic->name, rd->topic->type_name); + // 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), rd->topic->name, rd->topic->type_name); + 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), rd->topic->name, + rd->topic->type_name, 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) +{ + 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), wr->topic->name, wr->topic->type_name); + + // 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), + wr->topic->name, wr->topic->type_name); + 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), wr->topic->name, wr->topic->type_name, 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 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) +{ + 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) +{ + 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->name, wr->topic->type_name); + + 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) +{ + 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 (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) +{ + 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) +{ + 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) + { + DDS_Security_Exception_reset (&ex); + 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; +} + +bool q_omg_reader_is_submessage_protected(const struct reader *rd) +{ + 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) +{ + *buf = NULL; + if (!q_omg_writer_is_payload_protected (wr)) + return true; + + unsigned char *enc_buf; + size_t enc_len; + if (!q_omg_security_encode_serialized_payload (wr, vec->iov_base, vec->iov_len, &enc_buf, &enc_len)) + return false; + + /* Replace the iov buffer, which should always be aliased. */ + vec->iov_base = (char *) enc_buf; + vec->iov_len = (ddsrt_iov_len_t) enc_len; + assert ((size_t) vec->iov_len == enc_len); + *buf = enc_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); + assert (payloadsz); + assert (*payloadsz); + assert (submsg_len); + assert (sampleinfo); + + if (sampleinfo->pwr == NULL) + /* No specified proxy writer means no encoding. */ + return true; + + /* Only decode when the attributes tell us so. */ + if ((sampleinfo->pwr->c.security_info.security_attributes & NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_PAYLOAD_PROTECTED) + != NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_PAYLOAD_PROTECTED) + return true; + + unsigned char *dst_buf = NULL; + size_t dst_len = 0; + if (!q_omg_security_decode_serialized_payload (sampleinfo->pwr, payloadp, *payloadsz, &dst_buf, &dst_len)) + { + GVTRACE ("decode_payload: failed to decrypt data from "PGUIDFMT"\n", PGUID (sampleinfo->pwr->e.guid)); + return false; + } + + /* Expect result to always fit into the original buffer. */ + assert (*payloadsz >= dst_len); + + /* Reduce submessage and payload lengths. */ + *submsg_len -= *payloadsz - (uint32_t) dst_len; + *payloadsz = (uint32_t) dst_len; + memcpy (payloadp, dst_buf, dst_len); + ddsrt_free (dst_buf); + return true; +} + +bool decode_Data (const struct ddsi_domaingv *gv, struct nn_rsample_info *sampleinfo, unsigned char *payloadp, uint32_t payloadsz, size_t *submsg_len) +{ + /* Only decode when there's actual data. */ + if (payloadp == NULL || payloadsz == 0) + return true; + else if (!decode_payload (gv, sampleinfo, payloadp, &payloadsz, submsg_len)) + return false; + else + { + /* It's possible that the payload size (and thus the sample size) has been reduced. */ + sampleinfo->size = payloadsz; + return true; + } +} + +bool decode_DataFrag (const struct ddsi_domaingv *gv, struct nn_rsample_info *sampleinfo, unsigned char *payloadp, uint32_t payloadsz, size_t *submsg_len) +{ + /* Only decode when there's actual data; do not touch the sampleinfo->size in + contradiction to decode_Data() (it has been calculated differently). */ + if (payloadp == NULL || payloadsz == 0) + return true; + else + return decode_payload (gv, sampleinfo, payloadp, &payloadsz, submsg_len); +} + +void encode_datareader_submsg (struct nn_xmsg *msg, struct nn_xmsg_marker sm_marker, struct proxy_writer *pwr, const struct ddsi_guid *rd_guid) +{ + /* FIXME: avoid this lookup */ + 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)) + return; + assert (q_omg_participant_is_secure (rd->c.pp)); + + unsigned char *src_buf; + size_t src_len; + unsigned char *dst_buf; + size_t dst_len; + + /* Make one blob of the current sub-message by appending the serialized payload. */ + nn_xmsg_submsg_append_refd_payload (msg, sm_marker); + + /* Get the sub-message buffer. */ + src_buf = nn_xmsg_submsg_from_marker (msg, sm_marker); + src_len = nn_xmsg_submsg_size (msg, sm_marker); + + if (q_omg_security_encode_datareader_submessage (rd, &pwr->e.guid.prefix, src_buf, src_len, &dst_buf, &dst_len)) + { + nn_xmsg_submsg_replace (msg, sm_marker, dst_buf, dst_len); + ddsrt_free (dst_buf); + } + else + { + /* The sub-message should have been encoded, which failed. Remove it to prevent it from being send. */ + nn_xmsg_submsg_remove (msg, sm_marker); + } +} + +void encode_datawriter_submsg (struct nn_xmsg *msg, struct nn_xmsg_marker sm_marker, struct writer *wr) +{ + 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; + size_t dst_len; + ddsi_guid_prefix_t dst_guid_prefix; + ddsi_guid_prefix_t *dst = NULL; + + /* Make one blob of the current sub-message by appending the serialized payload. */ + nn_xmsg_submsg_append_refd_payload (msg, sm_marker); + + /* Get the sub-message buffer. */ + src_buf = nn_xmsg_submsg_from_marker (msg, sm_marker); + src_len = nn_xmsg_submsg_size (msg, sm_marker); + + if (nn_xmsg_getdst1prefix (msg, &dst_guid_prefix)) + dst = &dst_guid_prefix; + + if (q_omg_security_encode_datawriter_submessage (wr, dst, src_buf, src_len, &dst_buf, &dst_len)) + { + nn_xmsg_submsg_replace (msg, sm_marker, dst_buf, dst_len); + ddsrt_free (dst_buf); + } + else + { + /* The sub-message should have been encoded, which failed. Remove it to prevent it from being send. */ + nn_xmsg_submsg_remove (msg, sm_marker); + } +} + +bool validate_msg_decoding (const struct entity_common *e, const struct proxy_endpoint_common *c, const struct proxy_participant *proxypp, const struct receiver_state *rst, SubmessageKind_t prev_smid) +{ + assert (e); + assert (c); + assert (proxypp); + assert (rst); + + /* If this endpoint is expected to have submessages protected, it means that the + * previous submessage id (prev_smid) has to be SMID_SEC_PREFIX. That caused the + * protected submessage to be copied into the current RTPS message as a clear + * submessage, which we are currently handling. + * However, we have to check if the prev_smid is actually SMID_SEC_PREFIX, otherwise + * a rascal can inject data as just a clear submessage. */ + if ((c->security_info.security_attributes & NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_PROTECTED) + == NN_ENDPOINT_SECURITY_ATTRIBUTES_FLAG_IS_SUBMESSAGE_PROTECTED) + { + if (prev_smid != SMID_SEC_PREFIX) + return false; + } + + /* At this point, we should also check if the complete RTPS message was encoded when + * that is expected. */ + if (q_omg_security_is_remote_rtps_protected (proxypp, e->guid.entityid) && !rst->rtps_encoded) + { + return false; + } + + return true; +} + +static int32_t validate_submsg (struct ddsi_domaingv *gv, SubmessageKind_t smid, const unsigned char *submsg, unsigned char const * const end, int byteswap) +{ + assert (end >= submsg); + if ((size_t) (end - submsg) < RTPS_SUBMESSAGE_HEADER_SIZE) + { + GVWARNING ("Submsg 0x%02x does not fit message", smid); + return -1; + } + + SubmessageHeader_t const * const hdr = (SubmessageHeader_t *) submsg; + if (hdr->submessageId != smid && smid != SMID_PAD) + { + GVWARNING("Unexpected submsg 0x%02x (0x%02x expected)", hdr->submessageId, smid); + return -1; + } + + uint16_t size = hdr->octetsToNextHeader; + if (byteswap) + size = ddsrt_bswap2u (size); + const int32_t result = (int32_t) size + (int32_t) RTPS_SUBMESSAGE_HEADER_SIZE; + if (end - submsg < result) + { + GVWARNING ("Submsg 0x%02x does not fit message", smid); + return -1; + } + return result; +} + +static int32_t padding_submsg (struct ddsi_domaingv *gv, unsigned char *start, unsigned char *end, int byteswap) +{ + assert (end >= start); + const size_t size = (size_t) (end - start); + if (size < RTPS_SUBMESSAGE_HEADER_SIZE) + { + GVWARNING("Padding submessage doesn't fit"); + return -1; + } + + assert (size <= UINT16_MAX + RTPS_SUBMESSAGE_HEADER_SIZE); + SubmessageHeader_t * const padding = (SubmessageHeader_t *) start; + padding->submessageId = SMID_PAD; + DDSRT_STATIC_ASSERT (SMFLAG_ENDIANNESS == 1); + padding->flags = (byteswap ? !(DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN) : (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN)); + padding->octetsToNextHeader = (uint16_t) (size - RTPS_SUBMESSAGE_HEADER_SIZE); + if (byteswap) + padding->octetsToNextHeader = ddsrt_bswap2u (padding->octetsToNextHeader); + return (int32_t) size; +} + +static bool decode_SecPrefix_patched_hdr_flags (const struct receiver_state *rst, unsigned char *submsg, size_t submsg_size, unsigned char * const msg_end, const ddsi_guid_prefix_t * const src_prefix, const ddsi_guid_prefix_t * const dst_prefix, int byteswap) +{ + int smsize = -1; + size_t totalsize = submsg_size; + unsigned char *body_submsg; + unsigned char *prefix_submsg; + unsigned char *postfix_submsg; + + /* First sub-message is the SEC_PREFIX. */ + prefix_submsg = submsg; + + /* Next sub-message is SEC_BODY when encrypted or the original submessage when only signed. */ + body_submsg = submsg + submsg_size; + if ((smsize = validate_submsg (rst->gv, SMID_PAD, body_submsg, msg_end, byteswap)) <= 0) + return false; + totalsize += (size_t) smsize; + + /* Third sub-message should be the SEC_POSTFIX. */ + postfix_submsg = submsg + totalsize; + if ((smsize = validate_submsg (rst->gv, SMID_SEC_POSTFIX, postfix_submsg, msg_end, byteswap)) <= 0) + return false; + totalsize += (size_t) smsize; + + /* Decode all three submessages. */ + unsigned char *dst_buf; + size_t 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) + { + /* + * The 'normal' submessage sequence handling will continue after the + * given security SEC_PREFIX. + */ + SubmessageHeader_t const * const body_submsg_hdr = (SubmessageHeader_t const *) body_submsg; + if (body_submsg_hdr->submessageId == SMID_SEC_BODY) + { + /* + * Copy the decoded buffer into the original message, replacing (part + * of) SEC_BODY. + * + * By replacing the SEC_BODY with the decoded submessage, everything + * can continue as if there was never an encoded submessage. + */ + assert (totalsize >= submsg_size); + assert (dst_len <= totalsize - submsg_size); + memcpy (body_submsg, dst_buf, dst_len); + + /* Remainder of SEC_BODY & SEC_POSTFIX should be padded to keep the submsg sequence going. */ + smsize = padding_submsg (rst->gv, body_submsg + dst_len, prefix_submsg + totalsize, byteswap); + } + else + { + /* + * When only signed, then the submessage is already available and + * SMID_SEC_POSTFIX will be ignored. + * So, we don't really have to do anything. + */ + } + ddsrt_free (dst_buf); + } + else + { + /* + * Decoding or signing failed. + * + * Replace the security submessages with padding. This also removes a plain + * submessage when a signature check failed. + */ + smsize = padding_submsg (rst->gv, body_submsg, prefix_submsg + totalsize, byteswap); + } + + return (smsize > 0); +} + +bool decode_SecPrefix (const struct receiver_state *rst, unsigned char *submsg, size_t submsg_size, unsigned char * const msg_end, const ddsi_guid_prefix_t * const src_prefix, const ddsi_guid_prefix_t * const dst_prefix, int byteswap) +{ + /* FIXME: eliminate the patching of hdr->flags if possible */ + SubmessageHeader_t *hdr = (SubmessageHeader_t *) submsg; + const uint8_t saved_flags = hdr->flags; + if (byteswap) + { + if (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN) + hdr->flags |= 0x01; + else + hdr->flags &= 0xFE; + } + bool result = decode_SecPrefix_patched_hdr_flags (rst, submsg, submsg_size, msg_end, src_prefix, dst_prefix, byteswap); + hdr->flags = saved_flags; + return result; +} + +static nn_rtps_msg_state_t check_rtps_message_is_secure (struct ddsi_domaingv *gv, Header_t *hdr, const unsigned char *buff, bool isstream, struct proxy_participant **proxypp) +{ + const uint32_t offset = RTPS_MESSAGE_HEADER_SIZE + (isstream ? sizeof (MsgLen_t) : 0); + const SubmessageHeader_t *submsg = (const SubmessageHeader_t *) (buff + offset); + if (submsg->submessageId != SMID_SRTPS_PREFIX) + return NN_RTPS_MSG_STATE_PLAIN; + + ddsi_guid_t guid; + guid.prefix = hdr->guid_prefix; + guid.entityid.u = NN_ENTITYID_PARTICIPANT; + + GVTRACE (" from "PGUIDFMT, PGUID (guid)); + + if ((*proxypp = entidx_lookup_proxy_participant_guid (gv->entity_index, &guid)) == NULL) + { + GVTRACE ("received encoded rtps message from unknown participant\n"); + return NN_RTPS_MSG_STATE_ERROR; + } + else if (!proxypp_is_authenticated (*proxypp)) + { + GVTRACE ("received encoded rtps message from unauthenticated participant\n"); + return NN_RTPS_MSG_STATE_ERROR; + } + else + { + return NN_RTPS_MSG_STATE_ENCODED; + } +} + +static nn_rtps_msg_state_t +decode_rtps_message_awake ( + struct nn_rmsg **rmsg, + Header_t **hdr, + unsigned char **buff, + ssize_t *sz, + struct nn_rbufpool *rbpool, + bool isstream, + struct proxy_participant *proxypp) +{ + unsigned char *dstbuf; + unsigned char *srcbuf; + size_t srclen, dstlen; + + /* Currently the decode_rtps_message returns a new allocated buffer. + * This could be optimized by providing a pre-allocated nn_rmsg buffer to + * copy the decoded rtps message in. + */ + if (isstream) + { + /* Remove MsgLen Submessage which was only needed for a stream to determine the end of the message */ + assert (*sz > (ssize_t) sizeof (MsgLen_t)); + srcbuf = *buff + sizeof (MsgLen_t); + srclen = (size_t) *sz - sizeof (MsgLen_t); + memmove (srcbuf, *buff, RTPS_MESSAGE_HEADER_SIZE); + } + else + { + assert (*sz > 0); + srcbuf = *buff; + srclen = (size_t) *sz; + } + + if (!q_omg_security_decode_rtps_message (proxypp, srcbuf, srclen, &dstbuf, &dstlen)) + return NN_RTPS_MSG_STATE_ERROR; + else + { + assert (dstlen <= UINT32_MAX); + + nn_rmsg_commit (*rmsg); + *rmsg = nn_rmsg_new (rbpool); + *buff = NN_RMSG_PAYLOAD (*rmsg); + + memcpy(*buff, dstbuf, dstlen); + nn_rmsg_setsize (*rmsg, (uint32_t) dstlen); + + ddsrt_free (dstbuf); + + *hdr = (Header_t *) *buff; + (*hdr)->guid_prefix = nn_ntoh_guid_prefix ((*hdr)->guid_prefix); + *sz = (ssize_t) dstlen; + assert ((size_t) *sz == dstlen); + return NN_RTPS_MSG_STATE_ENCODED; + } +} + +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) +{ + struct proxy_participant *proxypp; + nn_rtps_msg_state_t ret; + thread_state_awake_fixed_domain (ts1); + ret = check_rtps_message_is_secure (gv, *hdr, *buff, isstream, &proxypp); + if (ret == NN_RTPS_MSG_STATE_ENCODED) + ret = decode_rtps_message_awake (rmsg, hdr, buff, sz, rbpool, isstream, proxypp); + thread_state_asleep (ts1); + return ret; +} + +ssize_t +secure_conn_write( + const struct ddsi_domaingv *gv, + ddsi_tran_conn_t conn, + const nn_locator_t *dst, + size_t niov, + const ddsrt_iovec_t *iov, + uint32_t flags, + MsgLen_t *msg_len, + bool dst_one, + nn_msg_sec_info_t *sec_info, + ddsi_tran_write_fn_t conn_write_cb) +{ + Header_t *hdr; + ddsi_guid_t guid; + unsigned char stbuf[2048]; + unsigned char *srcbuf; + unsigned char *dstbuf; + size_t srclen, dstlen; + int64_t dst_handle = 0; + + assert(iov); + assert(conn); + assert(msg_len); + assert(sec_info); + assert(niov > 0); + assert(conn_write_cb); + + if (dst_one) + { + dst_handle = sec_info->dst_pp_handle; + if (dst_handle == 0) { + return -1; + } + } + + hdr = (Header_t *) iov[0].iov_base; + guid.prefix = nn_ntoh_guid_prefix (hdr->guid_prefix); + guid.entityid.u = NN_ENTITYID_PARTICIPANT; + + /* first determine the size of the message, then select the + * on-stack buffer or allocate one on the heap ... + */ + srclen = 0; + for (size_t i = 0; i < niov; i++) + { + /* Do not copy MsgLen submessage in case of a stream connection */ + if (i != 1 || !conn->m_stream) + srclen += iov[i].iov_len; + } + if (srclen <= sizeof (stbuf)) + srcbuf = stbuf; + else + srcbuf = ddsrt_malloc (srclen); + + /* ... then copy data into buffer */ + srclen = 0; + for (size_t i = 0; i < niov; i++) + { + if (i != 1 || !conn->m_stream) + { + memcpy (srcbuf + srclen, iov[i].iov_base, iov[i].iov_len); + srclen += iov[i].iov_len; + } + } + + ssize_t ret = -1; + if (!q_omg_security_encode_rtps_message (gv, sec_info->src_pp_handle, &guid, srcbuf, srclen, &dstbuf, &dstlen, dst_handle)) + ret = -1; + else + { + ddsrt_iovec_t tmp_iov[3]; + size_t tmp_niov; + + if (conn->m_stream) + { + /* Add MsgLen submessage after Header */ + assert (dstlen <= UINT32_MAX - sizeof (*msg_len)); + msg_len->length = (uint32_t) (dstlen + sizeof (*msg_len)); + + tmp_iov[0].iov_base = dstbuf; + tmp_iov[0].iov_len = RTPS_MESSAGE_HEADER_SIZE; + tmp_iov[1].iov_base = (void *) msg_len; + tmp_iov[1].iov_len = sizeof (*msg_len); + tmp_iov[2].iov_base = dstbuf + RTPS_MESSAGE_HEADER_SIZE; + tmp_iov[2].iov_len = (ddsrt_iov_len_t) (dstlen - RTPS_MESSAGE_HEADER_SIZE); + tmp_niov = 3; + } + else + { + assert (dstlen <= UINT32_MAX); + msg_len->length = (uint32_t) dstlen; + + tmp_iov[0].iov_base = dstbuf; + tmp_iov[0].iov_len = (ddsrt_iov_len_t) dstlen; + tmp_niov = 1; + } + ret = conn_write_cb (conn, dst, tmp_niov, tmp_iov, flags); + ddsrt_free (dstbuf); + } + + if (srcbuf != stbuf) + ddsrt_free (srcbuf); + 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_security_enabled(void); + +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 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(bool relay_only), 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), UNUSED_ARG(bool *relay_only)); +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 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)); + +extern inline bool q_omg_participant_allow_unauthenticated(UNUSED_ARG(struct participant *pp)); + +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 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_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 bool decode_Data( + UNUSED_ARG(const struct ddsi_domaingv *gv), + UNUSED_ARG(struct nn_rsample_info *sampleinfo), + UNUSED_ARG(unsigned char *payloadp), + UNUSED_ARG(uint32_t payloadsz), + UNUSED_ARG(size_t *submsg_len)); + +extern inline bool decode_DataFrag( + UNUSED_ARG(const struct ddsi_domaingv *gv), + UNUSED_ARG(struct nn_rsample_info *sampleinfo), + UNUSED_ARG(unsigned char *payloadp), + UNUSED_ARG(uint32_t payloadsz), + UNUSED_ARG(size_t *submsg_len)); + +extern inline void encode_datareader_submsg( + UNUSED_ARG(struct nn_xmsg *msg), + UNUSED_ARG(struct nn_xmsg_marker sm_marker), + UNUSED_ARG(struct proxy_writer *pwr), + UNUSED_ARG(const struct ddsi_guid *rd_guid)); + +extern inline void encode_datawriter_submsg( + UNUSED_ARG(struct nn_xmsg *msg), + UNUSED_ARG(struct nn_xmsg_marker sm_marker), + UNUSED_ARG(struct writer *wr)); + +extern inline bool validate_msg_decoding( + UNUSED_ARG(const struct entity_common *e), + UNUSED_ARG(const struct proxy_endpoint_common *c), + UNUSED_ARG(struct proxy_participant *proxypp), + UNUSED_ARG(struct receiver_state *rst), + UNUSED_ARG(SubmessageKind_t prev_smid)); + +extern inline int decode_SecPrefix( + UNUSED_ARG(struct receiver_state *rst), + UNUSED_ARG(unsigned char *submsg), + UNUSED_ARG(size_t submsg_size), + UNUSED_ARG(unsigned char * const msg_end), + UNUSED_ARG(const ddsi_guid_prefix_t * const src_prefix), + UNUSED_ARG(const ddsi_guid_prefix_t * const dst_prefix), + UNUSED_ARG(int byteswap)); + +extern inline nn_rtps_msg_state_t decode_rtps_message( + UNUSED_ARG(struct thread_state1 * const ts1), + UNUSED_ARG(struct ddsi_domaingv *gv), + UNUSED_ARG(struct nn_rmsg **rmsg), + UNUSED_ARG(Header_t **hdr), + UNUSED_ARG(unsigned char **buff), + UNUSED_ARG(ssize_t *sz), + 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..65959bc --- /dev/null +++ b/src/core/ddsi/src/ddsi_security_util.c @@ -0,0 +1,726 @@ +/* + * 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) + g_omg_shallow_copy_octSeq(&dst->user_data.value, &plist->qos.user_data); + /* 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); +} + +void +q_omg_shallow_copy_TopicBuiltinTopicData( + DDS_Security_TopicBuiltinTopicData *dst, + const char *topic_name, + const char *type_name) +{ + memset(dst, 0, sizeof(DDS_Security_TopicBuiltinTopicData)); + dst->name = (DDS_Security_string)topic_name; + dst->type_name = (DDS_Security_string)type_name; +} + +void +q_omg_shallow_free_TopicBuiltinTopicData( + DDS_Security_TopicBuiltinTopicData *obj) +{ + DDSRT_UNUSED_ARG(obj); +} + + + +#endif /* DDSI_INCLUDE_SECURITY */ diff --git a/src/core/ddsi/src/ddsi_serdata.c b/src/core/ddsi/src/ddsi_serdata.c index 5cd816e..d1f5fa6 100644 --- a/src/core/ddsi/src/ddsi_serdata.c +++ b/src/core/ddsi/src/ddsi_serdata.c @@ -37,7 +37,7 @@ extern inline void ddsi_serdata_unref (struct ddsi_serdata *serdata); extern inline uint32_t ddsi_serdata_size (const struct ddsi_serdata *d); extern inline struct ddsi_serdata *ddsi_serdata_from_ser (const struct ddsi_sertopic *topic, enum ddsi_serdata_kind kind, const struct nn_rdata *fragchain, size_t size); extern inline struct ddsi_serdata *ddsi_serdata_from_ser_iov (const struct ddsi_sertopic *topic, enum ddsi_serdata_kind kind, ddsrt_msg_iovlen_t niov, const ddsrt_iovec_t *iov, size_t size); -extern inline struct ddsi_serdata *ddsi_serdata_from_keyhash (const struct ddsi_sertopic *topic, const struct nn_keyhash *keyhash); +extern inline struct ddsi_serdata *ddsi_serdata_from_keyhash (const struct ddsi_sertopic *topic, const struct ddsi_keyhash *keyhash); extern inline struct ddsi_serdata *ddsi_serdata_from_sample (const struct ddsi_sertopic *topic, enum ddsi_serdata_kind kind, const void *sample); extern inline struct ddsi_serdata *ddsi_serdata_to_topicless (const struct ddsi_serdata *d); extern inline void ddsi_serdata_to_ser (const struct ddsi_serdata *d, size_t off, size_t sz, void *buf); @@ -48,3 +48,4 @@ extern inline bool ddsi_serdata_topicless_to_sample (const struct ddsi_sertopic extern inline bool ddsi_serdata_eqkey (const struct ddsi_serdata *a, const struct ddsi_serdata *b); extern inline bool ddsi_serdata_print (const struct ddsi_serdata *d, char *buf, size_t size); extern inline bool ddsi_serdata_print_topicless (const struct ddsi_sertopic *topic, const struct ddsi_serdata *d, char *buf, size_t size); +extern inline void ddsi_serdata_get_keyhash (const struct ddsi_serdata *d, struct ddsi_keyhash *buf, bool force_md5); diff --git a/src/core/ddsi/src/ddsi_serdata_default.c b/src/core/ddsi/src/ddsi_serdata_default.c index 2889ba6..4a37c91 100644 --- a/src/core/ddsi/src/ddsi_serdata_default.c +++ b/src/core/ddsi/src/ddsi_serdata_default.c @@ -183,6 +183,7 @@ static void serdata_default_init(struct ddsi_serdata_default *d, const struct dd memset (d->keyhash.m_hash, 0, sizeof (d->keyhash.m_hash)); d->keyhash.m_set = 0; d->keyhash.m_iskey = 0; + d->keyhash.m_keysize = 0; } static struct ddsi_serdata_default *serdata_default_allocnew (struct serdatapool *serpool, uint32_t init_size) @@ -345,7 +346,7 @@ static struct ddsi_serdata *serdata_default_from_ser_iov_nokey (const struct dds return fix_serdata_default_nokey (d, tpcmn->serdata_basehash); } -static struct ddsi_serdata *ddsi_serdata_from_keyhash_cdr (const struct ddsi_sertopic *tpcmn, const nn_keyhash_t *keyhash) +static struct ddsi_serdata *ddsi_serdata_from_keyhash_cdr (const struct ddsi_sertopic *tpcmn, const ddsi_keyhash_t *keyhash) { /* FIXME: not quite sure this is correct, though a check against a specially hacked OpenSplice suggests it is */ const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)tpcmn; @@ -368,11 +369,12 @@ static struct ddsi_serdata *ddsi_serdata_from_keyhash_cdr (const struct ddsi_ser memcpy (d->keyhash.m_hash, keyhash->value, sizeof (d->keyhash.m_hash)); d->keyhash.m_set = 1; d->keyhash.m_iskey = 1; + d->keyhash.m_keysize = sizeof (d->keyhash.m_hash); return fix_serdata_default(d, tp->c.serdata_basehash); } } -static struct ddsi_serdata *ddsi_serdata_from_keyhash_cdr_nokey (const struct ddsi_sertopic *tpcmn, const nn_keyhash_t *keyhash) +static struct ddsi_serdata *ddsi_serdata_from_keyhash_cdr_nokey (const struct ddsi_sertopic *tpcmn, const ddsi_keyhash_t *keyhash) { const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)tpcmn; struct ddsi_serdata_default *d = serdata_default_new(tp, SDK_KEY); @@ -381,6 +383,7 @@ static struct ddsi_serdata *ddsi_serdata_from_keyhash_cdr_nokey (const struct dd (void)keyhash; d->keyhash.m_set = 1; d->keyhash.m_iskey = 1; + d->keyhash.m_keysize = 0; return fix_serdata_default_nokey(d, tp->c.serdata_basehash); } @@ -389,11 +392,15 @@ static void gen_keyhash_from_sample (const struct ddsi_sertopic_default *topic, const struct ddsi_sertopic_default_desc *desc = &topic->type; kh->m_set = 1; if (desc->m_nkeys == 0) + { kh->m_iskey = 1; + kh->m_keysize = 0; + } else if (desc->m_flagset & DDS_TOPIC_FIXED_KEY) { dds_ostreamBE_t os; kh->m_iskey = 1; + kh->m_keysize = sizeof(kh->m_hash); dds_ostreamBE_init (&os, 0); os.x.m_buffer = kh->m_hash; os.x.m_size = 16; @@ -404,6 +411,7 @@ static void gen_keyhash_from_sample (const struct ddsi_sertopic_default *topic, dds_ostreamBE_t os; ddsrt_md5_state_t md5st; kh->m_iskey = 0; + kh->m_keysize = sizeof(kh->m_hash); dds_ostreamBE_init (&os, 64); dds_stream_write_keyBE (&os, sample, topic); ddsrt_md5_init (&md5st); @@ -453,86 +461,6 @@ static struct ddsi_serdata *serdata_default_from_sample_cdr_nokey (const struct return fix_serdata_default_nokey (d, tpcmn->serdata_basehash); } -static struct ddsi_serdata *serdata_default_from_sample_plist (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, const void *vsample) -{ - /* Currently restricted to DDSI discovery data (XTypes will need a rethink of the default representation and that may result in discovery data being moved to that new representation), and that means: keys are either GUIDs or an unbounded string for topics, for which MD5 is acceptable. Furthermore, these things don't get written very often, so scanning the parameter list to get the key value out is good enough for now. And at least it keeps the DDSI discovery data writing out of the internals of the sample representation */ - const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)tpcmn; - const struct ddsi_plist_sample *sample = vsample; - struct ddsi_serdata_default *d = serdata_default_new(tp, kind); - if (d == NULL) - return NULL; - serdata_default_append_blob (&d, 1, sample->size, sample->blob); - const unsigned char *rawkey = ddsi_plist_findparam_native_unchecked (sample->blob, sample->keyparam); -#ifndef NDEBUG - size_t keysize; -#endif - assert(rawkey); - switch (sample->keyparam) - { - case PID_PARTICIPANT_GUID: - case PID_ENDPOINT_GUID: - case PID_GROUP_GUID: - d->keyhash.m_set = 1; - d->keyhash.m_iskey = 1; - memcpy (d->keyhash.m_hash, rawkey, 16); -#ifndef NDEBUG - keysize = 16; -#endif - break; - - case PID_TOPIC_NAME: { - const char *topic_name = (const char *) (rawkey + sizeof(uint32_t)); - uint32_t topic_name_sz; - uint32_t topic_name_sz_BE; - ddsrt_md5_state_t md5st; - ddsrt_md5_byte_t digest[16]; - topic_name_sz = (uint32_t) strlen (topic_name) + 1; - topic_name_sz_BE = ddsrt_toBE4u (topic_name_sz); - d->keyhash.m_set = 1; - d->keyhash.m_iskey = 0; - ddsrt_md5_init (&md5st); - ddsrt_md5_append (&md5st, (const ddsrt_md5_byte_t *) &topic_name_sz_BE, sizeof (topic_name_sz_BE)); - ddsrt_md5_append (&md5st, (const ddsrt_md5_byte_t *) topic_name, topic_name_sz); - ddsrt_md5_finish (&md5st, digest); - memcpy (d->keyhash.m_hash, digest, 16); -#ifndef NDEBUG - keysize = sizeof (uint32_t) + topic_name_sz; -#endif - break; - } - - default: - abort(); - } - - /* if it is supposed to be just a key, rawkey must be be the first field and followed only by a sentinel */ - assert (kind != SDK_KEY || rawkey == (const unsigned char *)sample->blob + sizeof (nn_parameter_t)); - assert (kind != SDK_KEY || sample->size == sizeof (nn_parameter_t) + alignup_size (keysize, 4) + sizeof (nn_parameter_t)); - return fix_serdata_default (d, tp->c.serdata_basehash); -} - -static struct ddsi_serdata *serdata_default_from_sample_rawcdr (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, const void *vsample) -{ - /* Currently restricted to DDSI discovery data (XTypes will need a rethink of the default representation and that may result in discovery data being moved to that new representation), and that means: keys are either GUIDs or an unbounded string for topics, for which MD5 is acceptable. Furthermore, these things don't get written very often, so scanning the parameter list to get the key value out is good enough for now. And at least it keeps the DDSI discovery data writing out of the internals of the sample representation */ - const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)tpcmn; - const struct ddsi_rawcdr_sample *sample = vsample; - struct ddsi_serdata_default *d = serdata_default_new(tp, kind); - if (d == NULL) - return NULL; - assert (sample->keysize <= 16); - serdata_default_append_blob (&d, 1, sample->size, sample->blob); - serdata_default_append_aligned (&d, 0, 4); - d->keyhash.m_set = 1; - d->keyhash.m_iskey = 1; - if (sample->keysize == 0) - return fix_serdata_default_nokey (d, tp->c.serdata_basehash); - else - { - memcpy (&d->keyhash.m_hash, sample->key, sample->keysize); - return fix_serdata_default (d, tp->c.serdata_basehash); - } -} - static struct ddsi_serdata *serdata_default_to_topicless (const struct ddsi_serdata *serdata_common) { const struct ddsi_serdata_default *d = (const struct ddsi_serdata_default *)serdata_common; @@ -655,37 +583,24 @@ static size_t serdata_default_print_cdr (const struct ddsi_sertopic *sertopic_co return dds_stream_print_sample (&is, tp, buf, size); } -static size_t serdata_default_print_plist (const struct ddsi_sertopic *sertopic_common, const struct ddsi_serdata *serdata_common, char *buf, size_t size) +static void serdata_default_get_keyhash (const struct ddsi_serdata *serdata_common, struct ddsi_keyhash *buf, bool force_md5) { const struct ddsi_serdata_default *d = (const struct ddsi_serdata_default *)serdata_common; - const struct ddsi_sertopic_default *tp = (const struct ddsi_sertopic_default *)sertopic_common; - ddsi_plist_src_t src; - ddsi_plist_t tmp; - src.buf = (const unsigned char *) d->data; - src.bufsz = d->pos; - src.encoding = d->hdr.identifier; - src.factory = tp->c.gv->m_factory; - src.logconfig = &tp->c.gv->logconfig; - src.protocol_version.major = RTPS_MAJOR; - src.protocol_version.minor = RTPS_MINOR; - src.strict = false; - src.vendorid = NN_VENDORID_ECLIPSE; - if (ddsi_plist_init_frommsg (&tmp, NULL, ~(uint64_t)0, ~(uint64_t)0, &src) < 0) - return (size_t) snprintf (buf, size, "(unparseable-plist)"); + assert(buf); + assert(d->keyhash.m_set); + if (force_md5 && d->keyhash.m_iskey /* m_iskey == !md5 */) + { + ddsrt_md5_state_t md5st; + ddsrt_md5_init (&md5st); + ddsrt_md5_append(&md5st, (ddsrt_md5_byte_t*)(d->keyhash.m_hash), d->keyhash.m_keysize); + ddsrt_md5_finish(&md5st, (ddsrt_md5_byte_t*)(buf->value)); + } else { - size_t ret = ddsi_plist_print (buf, size, &tmp); - ddsi_plist_fini (&tmp); - return ret; + memcpy (buf->value, d->keyhash.m_hash, 16); } } -static size_t serdata_default_print_raw (const struct ddsi_sertopic *sertopic_common, const struct ddsi_serdata *serdata_common, char *buf, size_t size) -{ - (void)sertopic_common; (void)serdata_common; - return (size_t) snprintf (buf, size, "(blob)"); -} - const struct ddsi_serdata_ops ddsi_serdata_ops_cdr = { .get_size = serdata_default_get_size, .eqkey = serdata_default_eqkey, @@ -700,7 +615,8 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_cdr = { .to_ser_unref = serdata_default_to_ser_unref, .to_topicless = serdata_default_to_topicless, .topicless_to_sample = serdata_default_topicless_to_sample_cdr, - .print = serdata_default_print_cdr + .print = serdata_default_print_cdr, + .get_keyhash = serdata_default_get_keyhash }; const struct ddsi_serdata_ops ddsi_serdata_ops_cdr_nokey = { @@ -717,39 +633,6 @@ const struct ddsi_serdata_ops ddsi_serdata_ops_cdr_nokey = { .to_ser_unref = serdata_default_to_ser_unref, .to_topicless = serdata_default_to_topicless, .topicless_to_sample = serdata_default_topicless_to_sample_cdr_nokey, - .print = serdata_default_print_cdr -}; - -const struct ddsi_serdata_ops ddsi_serdata_ops_plist = { - .get_size = serdata_default_get_size, - .eqkey = serdata_default_eqkey, - .free = serdata_default_free, - .from_ser = serdata_default_from_ser, - .from_ser_iov = serdata_default_from_ser_iov, - .from_keyhash = 0, - .from_sample = serdata_default_from_sample_plist, - .to_ser = serdata_default_to_ser, - .to_sample = 0, - .to_ser_ref = serdata_default_to_ser_ref, - .to_ser_unref = serdata_default_to_ser_unref, - .to_topicless = serdata_default_to_topicless, - .topicless_to_sample = 0, - .print = serdata_default_print_plist -}; - -const struct ddsi_serdata_ops ddsi_serdata_ops_rawcdr = { - .get_size = serdata_default_get_size, - .eqkey = serdata_default_eqkey, - .free = serdata_default_free, - .from_ser = serdata_default_from_ser, - .from_ser_iov = serdata_default_from_ser_iov, - .from_keyhash = 0, - .from_sample = serdata_default_from_sample_rawcdr, - .to_ser = serdata_default_to_ser, - .to_sample = 0, - .to_ser_ref = serdata_default_to_ser_ref, - .to_ser_unref = serdata_default_to_ser_unref, - .to_topicless = serdata_default_to_topicless, - .topicless_to_sample = 0, - .print = serdata_default_print_raw + .print = serdata_default_print_cdr, + .get_keyhash = serdata_default_get_keyhash }; diff --git a/src/core/ddsi/src/ddsi_serdata_plist.c b/src/core/ddsi/src/ddsi_serdata_plist.c new file mode 100644 index 0000000..528fa81 --- /dev/null +++ b/src/core/ddsi/src/ddsi_serdata_plist.c @@ -0,0 +1,311 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/log.h" +#include "dds/ddsrt/md5.h" +#include "dds/ddsrt/mh3.h" +#include "dds/ddsi/q_bswap.h" +#include "dds/ddsi/q_config.h" +#include "dds/ddsi/q_freelist.h" +#include "dds/ddsi/ddsi_tkmap.h" +#include "dds/ddsi/ddsi_cdrstream.h" +#include "dds/ddsi/q_radmin.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/ddsi/ddsi_serdata_plist.h" +#include "dds/ddsi/q_xmsg.h" + +static uint32_t serdata_plist_get_size (const struct ddsi_serdata *dcmn) +{ + const struct ddsi_serdata_plist *d = (const struct ddsi_serdata_plist *) dcmn; + return 4 + d->pos; // FIXME: +4 for CDR header should be eliminated +} + +static bool serdata_plist_eqkey (const struct ddsi_serdata *acmn, const struct ddsi_serdata *bcmn) +{ + const struct ddsi_serdata_plist *a = (const struct ddsi_serdata_plist *) acmn; + const struct ddsi_serdata_plist *b = (const struct ddsi_serdata_plist *) bcmn; + return memcmp (&a->keyhash, &b->keyhash, sizeof (a->keyhash)) == 0; +} + +static void serdata_plist_free (struct ddsi_serdata *dcmn) +{ + struct ddsi_serdata_plist *d = (struct ddsi_serdata_plist *) dcmn; + ddsrt_free (d); +} + +static struct ddsi_serdata_plist *serdata_plist_new (const struct ddsi_sertopic_plist *tp, enum ddsi_serdata_kind kind, size_t size, const void *cdr_header) +{ + /* FIXME: check whether this really is the correct maximum: offsets are relative + to the CDR header, but there are also some places that use a serdata as-if it + were a stream, and those use offsets (m_index) relative to the start of the + serdata */ + if (size < 4 || size > UINT32_MAX - offsetof (struct ddsi_serdata_plist, identifier)) + return NULL; + struct ddsi_serdata_plist *d = ddsrt_malloc (sizeof (*d) + size); + if (d == NULL) + return NULL; + ddsi_serdata_init (&d->c, &tp->c, kind); + d->pos = 0; + d->size = (uint32_t) size; + // FIXME: vendorid/protoversion are not available when creating a serdata + // these should be overruled by the one creating the serdata + d->vendorid = NN_VENDORID_UNKNOWN; + d->protoversion.major = RTPS_MAJOR; + d->protoversion.minor = RTPS_MINOR; + const uint16_t *hdrsrc = cdr_header; + d->identifier = hdrsrc[0]; + d->options = hdrsrc[1]; + if (d->identifier != PL_CDR_LE && d->identifier != PL_CDR_BE) + { + ddsrt_free (d); + return NULL; + } + return d; +} + +static struct ddsi_serdata *serdata_plist_fix (const struct ddsi_sertopic_plist *tp, struct ddsi_serdata_plist *d) +{ + assert (tp->keyparam != PID_SENTINEL); + void *needlep; + size_t needlesz; + if (ddsi_plist_findparam_checking (d->data, d->pos, d->identifier, tp->keyparam, &needlep, &needlesz) != DDS_RETCODE_OK) + { + ddsrt_free (d); + return NULL; + } + assert (needlep); + if (needlesz != sizeof (d->keyhash)) + { + ddsrt_free (d); + return NULL; + } + memcpy (&d->keyhash, needlep, 16); + d->c.hash = ddsrt_mh3 (&d->keyhash, sizeof (d->keyhash), 0) ^ tp->c.serdata_basehash; + return &d->c; +} + +static struct ddsi_serdata *serdata_plist_from_ser (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, const struct nn_rdata *fragchain, size_t size) +{ + const struct ddsi_sertopic_plist *tp = (const struct ddsi_sertopic_plist *) tpcmn; + struct ddsi_serdata_plist *d = serdata_plist_new (tp, kind, size, NN_RMSG_PAYLOADOFF (fragchain->rmsg, NN_RDATA_PAYLOAD_OFF (fragchain))); + if (d == NULL) + return NULL; + uint32_t off = 4; /* must skip the CDR header */ + assert (fragchain->min == 0); + assert (fragchain->maxp1 >= off); /* CDR header must be in first fragment */ + while (fragchain) + { + assert (fragchain->min <= off); + assert (fragchain->maxp1 <= size); + if (fragchain->maxp1 > off) + { + /* only copy if this fragment adds data */ + const unsigned char *payload = NN_RMSG_PAYLOADOFF (fragchain->rmsg, NN_RDATA_PAYLOAD_OFF (fragchain)); + uint32_t n = fragchain->maxp1 - off; + memcpy (d->data + d->pos, payload + off - fragchain->min, n); + d->pos += n; + off = fragchain->maxp1; + } + fragchain = fragchain->nextfrag; + } + return serdata_plist_fix (tp, d); +} + +static struct ddsi_serdata *serdata_plist_from_ser_iov (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, ddsrt_msg_iovlen_t niov, const ddsrt_iovec_t *iov, size_t size) +{ + const struct ddsi_sertopic_plist *tp = (const struct ddsi_sertopic_plist *) tpcmn; + assert (niov >= 1); + struct ddsi_serdata_plist *d = serdata_plist_new (tp, kind, size, iov[0].iov_base); + if (d == NULL) + return NULL; + memcpy (d->data + d->pos, (const char *) iov[0].iov_base + 4, iov[0].iov_len - 4); + d->pos += (uint32_t) iov[0].iov_len - 4; + for (ddsrt_msg_iovlen_t i = 1; i < niov; i++) + { + memcpy (d->data + d->pos, (const char *) iov[i].iov_base, iov[i].iov_len); + d->pos += (uint32_t) iov[i].iov_len; + } + return serdata_plist_fix (tp, d); +} + +static struct ddsi_serdata *serdata_plist_from_keyhash (const struct ddsi_sertopic *tpcmn, const ddsi_keyhash_t *keyhash) +{ + const struct ddsi_sertopic_plist *tp = (const struct ddsi_sertopic_plist *) tpcmn; + const struct { uint16_t identifier, options; nn_parameter_t par; ddsi_keyhash_t kh; nn_parameter_t sentinel; } in = { + .identifier = PL_CDR_BE, + .options = 0, + .par = { + .parameterid = ddsrt_toBE2u (tp->keyparam), + .length = ddsrt_toBE2u ((uint16_t) sizeof (*keyhash)) + }, + .kh = *keyhash, + .sentinel = { + .parameterid = ddsrt_toBE2u (PID_SENTINEL), + .length = 0 + } + }; + const ddsrt_iovec_t iov = { .iov_base = (void *) &in, .iov_len = sizeof (in) }; + return serdata_plist_from_ser_iov (tpcmn, SDK_KEY, 1, &iov, sizeof (in) - 4); +} + +static bool serdata_plist_topicless_to_sample (const struct ddsi_sertopic *topic_common, const struct ddsi_serdata *serdata_common, void *sample, void **bufptr, void *buflim) +{ + const struct ddsi_serdata_plist *d = (const struct ddsi_serdata_plist *)serdata_common; + const struct ddsi_sertopic_plist *tp = (const struct ddsi_sertopic_plist *) topic_common; + struct ddsi_domaingv * const gv = tp->c.gv; + if (bufptr) abort(); else { (void)buflim; } /* FIXME: haven't implemented that bit yet! */ + ddsi_plist_src_t src = { + .buf = (const unsigned char *) d->data, + .bufsz = d->pos, + .encoding = d->identifier, + .factory = gv->m_factory, + .logconfig = &gv->logconfig, + .protocol_version = d->protoversion, + .strict = NN_STRICT_P (gv->config), + .vendorid = d->vendorid + }; + const dds_return_t rc = ddsi_plist_init_frommsg (sample, NULL, ~(uint64_t)0, ~(uint64_t)0, &src); + // FIXME: need a more informative return type + if (rc != DDS_RETCODE_OK && rc != DDS_RETCODE_UNSUPPORTED) + GVWARNING ("SPDP (vendor %u.%u): invalid qos/parameters\n", src.vendorid.id[0], src.vendorid.id[1]); + return (rc == DDS_RETCODE_OK); +} + +static bool serdata_plist_to_sample (const struct ddsi_serdata *serdata_common, void *sample, void **bufptr, void *buflim) +{ + /* the "plist" topics only differ in the parameter that is used as the key value */ + return serdata_plist_topicless_to_sample (serdata_common->topic, serdata_common, sample, bufptr, buflim); +} + +static void serdata_plist_to_ser (const struct ddsi_serdata *serdata_common, size_t off, size_t sz, void *buf) +{ + const struct ddsi_serdata_plist *d = (const struct ddsi_serdata_plist *)serdata_common; + memcpy (buf, (char *) &d->identifier + off, sz); +} + +static struct ddsi_serdata *serdata_plist_to_ser_ref (const struct ddsi_serdata *serdata_common, size_t off, size_t sz, ddsrt_iovec_t *ref) +{ + const struct ddsi_serdata_plist *d = (const struct ddsi_serdata_plist *)serdata_common; + ref->iov_base = (char *) &d->identifier + off; + ref->iov_len = (ddsrt_iov_len_t) sz; + return ddsi_serdata_ref (serdata_common); +} + +static void serdata_plist_to_ser_unref (struct ddsi_serdata *serdata_common, const ddsrt_iovec_t *ref) +{ + (void) ref; + ddsi_serdata_unref (serdata_common); +} + +static struct ddsi_serdata *serdata_plist_from_sample (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, const void *sample) +{ + const struct ddsi_sertopic_plist *tp = (const struct ddsi_sertopic_plist *)tpcmn; + const struct { uint16_t identifier, options; } header = { tp->native_encoding_identifier, 0 }; + const ddsi_guid_t nullguid = { .prefix = { .u = { 0,0,0 } }, .entityid = { .u = 0 } }; + + // FIXME: key must not require byteswapping (GUIDs are ok) + // FIXME: rework plist stuff so it doesn't need an nn_xmsg + struct nn_xmsg *mpayload = nn_xmsg_new (tp->c.gv->xmsgpool, &nullguid, NULL, 0, NN_XMSG_KIND_DATA); + memcpy (nn_xmsg_append (mpayload, NULL, 4), &header, 4); + ddsi_plist_addtomsg (mpayload, sample, ~(uint64_t)0, ~(uint64_t)0); + nn_xmsg_addpar_sentinel (mpayload); + + size_t sz; + unsigned char *blob = nn_xmsg_payload (&sz, mpayload); +#ifndef NDEBUG + void *needle; + size_t needlesz; + assert (ddsi_plist_findparam_checking (blob + 4, sz, header.identifier, tp->keyparam, &needle, &needlesz) == DDS_RETCODE_OK); + assert (needle && needlesz == 16); +#endif + ddsrt_iovec_t iov = { .iov_base = blob, .iov_len = (ddsrt_iov_len_t) sz }; + struct ddsi_serdata *d = serdata_plist_from_ser_iov (tpcmn, kind, 1, &iov, sz - 4); + nn_xmsg_free (mpayload); + + /* we know the vendor when we construct a serdata from a sample */ + struct ddsi_serdata_plist *d_plist = (struct ddsi_serdata_plist *) d; + d_plist->vendorid = NN_VENDORID_ECLIPSE; + return d; +} + +static struct ddsi_serdata *serdata_plist_to_topicless (const struct ddsi_serdata *serdata_common) +{ + const struct ddsi_serdata_plist *d = (const struct ddsi_serdata_plist *) serdata_common; + const struct ddsi_sertopic_plist *tp = (const struct ddsi_sertopic_plist *) d->c.topic; + ddsrt_iovec_t iov = { .iov_base = (char *) &d->identifier, .iov_len = 4 + d->pos }; + struct ddsi_serdata *dcmn_tl = serdata_plist_from_ser_iov (&tp->c, SDK_KEY, 1, &iov, d->pos); + assert (dcmn_tl != NULL); + dcmn_tl->topic = NULL; + return dcmn_tl; +} + +static void serdata_plist_get_keyhash (const struct ddsi_serdata *serdata_common, struct ddsi_keyhash *buf, bool force_md5) +{ + const struct ddsi_serdata_plist *d = (const struct ddsi_serdata_plist *)serdata_common; + if (!force_md5) + memcpy (buf, &d->keyhash, 16); + else + { + ddsrt_md5_state_t md5st; + ddsrt_md5_init (&md5st); + ddsrt_md5_append (&md5st, (ddsrt_md5_byte_t *) &d->keyhash, 16); + ddsrt_md5_finish (&md5st, (ddsrt_md5_byte_t *) buf->value); + } +} + +static size_t serdata_plist_print_plist (const struct ddsi_sertopic *sertopic_common, const struct ddsi_serdata *serdata_common, char *buf, size_t size) +{ + const struct ddsi_serdata_plist *d = (const struct ddsi_serdata_plist *) serdata_common; + const struct ddsi_sertopic_plist *tp = (const struct ddsi_sertopic_plist *) sertopic_common; + ddsi_plist_src_t src = { + .buf = (const unsigned char *) d->data, + .bufsz = d->pos, + .encoding = d->identifier, + .factory = tp->c.gv->m_factory, + .logconfig = &tp->c.gv->logconfig, + .protocol_version = d->protoversion, + .strict = false, + .vendorid = d->vendorid + }; + ddsi_plist_t tmp; + if (ddsi_plist_init_frommsg (&tmp, NULL, ~(uint64_t)0, ~(uint64_t)0, &src) < 0) + return (size_t) snprintf (buf, size, "(unparseable-plist)"); + else + { + size_t ret = ddsi_plist_print (buf, size, &tmp); + ddsi_plist_fini (&tmp); + return ret; + } +} + +const struct ddsi_serdata_ops ddsi_serdata_ops_plist = { + .get_size = serdata_plist_get_size, + .eqkey = serdata_plist_eqkey, + .free = serdata_plist_free, + .from_ser = serdata_plist_from_ser, + .from_ser_iov = serdata_plist_from_ser_iov, + .from_keyhash = serdata_plist_from_keyhash, + .from_sample = serdata_plist_from_sample, + .to_ser = serdata_plist_to_ser, + .to_sample = serdata_plist_to_sample, + .to_ser_ref = serdata_plist_to_ser_ref, + .to_ser_unref = serdata_plist_to_ser_unref, + .to_topicless = serdata_plist_to_topicless, + .topicless_to_sample = serdata_plist_topicless_to_sample, + .print = serdata_plist_print_plist, + .get_keyhash = serdata_plist_get_keyhash +}; diff --git a/src/core/ddsi/src/ddsi_serdata_pserop.c b/src/core/ddsi/src/ddsi_serdata_pserop.c new file mode 100644 index 0000000..1796497 --- /dev/null +++ b/src/core/ddsi/src/ddsi_serdata_pserop.c @@ -0,0 +1,298 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/log.h" +#include "dds/ddsrt/md5.h" +#include "dds/ddsrt/mh3.h" +#include "dds/ddsi/q_bswap.h" +#include "dds/ddsi/q_config.h" +#include "dds/ddsi/q_freelist.h" +#include "dds/ddsi/ddsi_tkmap.h" +#include "dds/ddsi/ddsi_cdrstream.h" +#include "dds/ddsi/q_radmin.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/ddsi/ddsi_serdata_pserop.h" + +static uint32_t serdata_pserop_get_size (const struct ddsi_serdata *dcmn) +{ + const struct ddsi_serdata_pserop *d = (const struct ddsi_serdata_pserop *) dcmn; + return 4 + d->pos; // FIXME: +4 for CDR header should be eliminated +} + +static bool serdata_pserop_eqkey (const struct ddsi_serdata *acmn, const struct ddsi_serdata *bcmn) +{ + const struct ddsi_serdata_pserop *a = (const struct ddsi_serdata_pserop *) acmn; + const struct ddsi_serdata_pserop *b = (const struct ddsi_serdata_pserop *) bcmn; + if (a->keyless != b->keyless) + return false; + else if (a->keyless) + return true; + else + return memcmp (a->sample, b->sample, 16) == 0; +} + +static void serdata_pserop_free (struct ddsi_serdata *dcmn) +{ + struct ddsi_serdata_pserop *d = (struct ddsi_serdata_pserop *) dcmn; + const struct ddsi_sertopic_pserop *tp = (const struct ddsi_sertopic_pserop *) d->c.topic; + if (d->c.kind == SDK_DATA) + plist_fini_generic (d->sample, tp->ops, true); + if (d->sample) + ddsrt_free (d->sample); + ddsrt_free (d); +} + +static struct ddsi_serdata_pserop *serdata_pserop_new (const struct ddsi_sertopic_pserop *tp, enum ddsi_serdata_kind kind, size_t size, const void *cdr_header) +{ + /* FIXME: check whether this really is the correct maximum: offsets are relative + to the CDR header, but there are also some places that use a serdata as-if it + were a stream, and those use offsets (m_index) relative to the start of the + serdata */ + assert (kind != SDK_EMPTY); + if (size < 4 || size > UINT32_MAX - offsetof (struct ddsi_serdata_pserop, identifier)) + return NULL; + struct ddsi_serdata_pserop *d = ddsrt_malloc (sizeof (*d) + size); + if (d == NULL) + return NULL; + ddsi_serdata_init (&d->c, &tp->c, kind); + d->keyless = (tp->ops_key == NULL); + d->pos = 0; + d->size = (uint32_t) size; + const uint16_t *hdrsrc = cdr_header; + d->identifier = hdrsrc[0]; + d->options = hdrsrc[1]; + assert (d->identifier == CDR_LE || d->identifier == CDR_BE); + if (kind == SDK_KEY && d->keyless) + d->sample = NULL; + else if ((d->sample = ddsrt_malloc ((kind == SDK_DATA) ? tp->memsize : 16)) == NULL) + { + ddsrt_free (d); + return NULL; + } + return d; +} + +static struct ddsi_serdata *serdata_pserop_fix (const struct ddsi_sertopic_pserop *tp, struct ddsi_serdata_pserop *d) +{ + const bool needs_bswap = (d->identifier != tp->native_encoding_identifier); + const enum pserop *ops = (d->c.kind == SDK_DATA) ? tp->ops : tp->ops_key; + d->c.hash = tp->c.serdata_basehash; + if (ops != NULL) + { + assert (d->pos >= 16 && tp->memsize >= 16); + if (plist_deser_generic (d->sample, d->data, d->pos, needs_bswap, (d->c.kind == SDK_DATA) ? tp->ops : tp->ops_key) < 0) + { + ddsrt_free (d->sample); + ddsrt_free (d); + return NULL; + } + if (tp->ops_key) + { + assert (d->pos >= 16 && tp->memsize >= 16); + d->c.hash ^= ddsrt_mh3 (d->sample, 16, 0); + } + } + return &d->c; +} + +static struct ddsi_serdata *serdata_pserop_from_ser (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, const struct nn_rdata *fragchain, size_t size) +{ + const struct ddsi_sertopic_pserop *tp = (const struct ddsi_sertopic_pserop *)tpcmn; + struct ddsi_serdata_pserop *d = serdata_pserop_new (tp, kind, size, NN_RMSG_PAYLOADOFF (fragchain->rmsg, NN_RDATA_PAYLOAD_OFF (fragchain))); + uint32_t off = 4; /* must skip the CDR header */ + assert (fragchain->min == 0); + assert (fragchain->maxp1 >= off); /* CDR header must be in first fragment */ + while (fragchain) + { + assert (fragchain->min <= off); + assert (fragchain->maxp1 <= size); + if (fragchain->maxp1 > off) + { + /* only copy if this fragment adds data */ + const unsigned char *payload = NN_RMSG_PAYLOADOFF (fragchain->rmsg, NN_RDATA_PAYLOAD_OFF (fragchain)); + uint32_t n = fragchain->maxp1 - off; + memcpy (d->data + d->pos, payload + off - fragchain->min, n); + d->pos += n; + off = fragchain->maxp1; + } + fragchain = fragchain->nextfrag; + } + return serdata_pserop_fix (tp, d); +} + +static struct ddsi_serdata *serdata_pserop_from_ser_iov (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, ddsrt_msg_iovlen_t niov, const ddsrt_iovec_t *iov, size_t size) +{ + const struct ddsi_sertopic_pserop *tp = (const struct ddsi_sertopic_pserop *)tpcmn; + assert (niov >= 1); + struct ddsi_serdata_pserop *d = serdata_pserop_new (tp, kind, size, iov[0].iov_base); + const uint16_t *hdrsrc = (uint16_t *) iov[0].iov_base; + d->identifier = hdrsrc[0]; + d->options = hdrsrc[1]; + assert (d->identifier == CDR_LE || d->identifier == CDR_BE); + memcpy (d->data + d->pos, (const char *) iov[0].iov_base + 4, iov[0].iov_len - 4); + d->pos += (uint32_t) iov[0].iov_len - 4; + for (ddsrt_msg_iovlen_t i = 1; i < niov; i++) + { + memcpy (d->data + d->pos, (const char *) iov[i].iov_base, iov[i].iov_len); + d->pos += (uint32_t) iov[i].iov_len; + } + return serdata_pserop_fix (tp, d); +} + +static struct ddsi_serdata *serdata_pserop_from_keyhash (const struct ddsi_sertopic *tpcmn, const ddsi_keyhash_t *keyhash) +{ + const struct { uint16_t identifier, options; ddsi_keyhash_t kh; } in = { CDR_BE, 0, *keyhash }; + const ddsrt_iovec_t iov = { .iov_base = (void *) &in, .iov_len = sizeof (in) }; + return serdata_pserop_from_ser_iov (tpcmn, SDK_KEY, 1, &iov, sizeof (in) - 4); +} + +static bool serdata_pserop_to_sample (const struct ddsi_serdata *serdata_common, void *sample, void **bufptr, void *buflim) +{ + const struct ddsi_serdata_pserop *d = (const struct ddsi_serdata_pserop *)serdata_common; + const struct ddsi_sertopic_pserop *tp = (const struct ddsi_sertopic_pserop *) d->c.topic; + if (bufptr) abort(); else { (void)buflim; } /* FIXME: haven't implemented that bit yet! */ + if (d->c.kind == SDK_KEY) + memcpy (sample, d->sample, 16); + else + { + dds_return_t x; + x = plist_deser_generic (sample, d->data, d->pos, d->identifier != tp->native_encoding_identifier, tp->ops); + plist_unalias_generic (sample, tp->ops); + assert (x >= 0); + (void) x; + } + return true; /* FIXME: can't conversion to sample fail? */ +} + +static void serdata_pserop_to_ser (const struct ddsi_serdata *serdata_common, size_t off, size_t sz, void *buf) +{ + const struct ddsi_serdata_pserop *d = (const struct ddsi_serdata_pserop *)serdata_common; + memcpy (buf, (char *) &d->identifier + off, sz); +} + +static struct ddsi_serdata *serdata_pserop_to_ser_ref (const struct ddsi_serdata *serdata_common, size_t off, size_t sz, ddsrt_iovec_t *ref) +{ + const struct ddsi_serdata_pserop *d = (const struct ddsi_serdata_pserop *)serdata_common; + ref->iov_base = (char *) &d->identifier + off; + ref->iov_len = (ddsrt_iov_len_t) sz; + return ddsi_serdata_ref (serdata_common); +} + +static void serdata_pserop_to_ser_unref (struct ddsi_serdata *serdata_common, const ddsrt_iovec_t *ref) +{ + (void) ref; + ddsi_serdata_unref (serdata_common); +} + +static struct ddsi_serdata *serdata_pserop_from_sample (const struct ddsi_sertopic *tpcmn, enum ddsi_serdata_kind kind, const void *sample) +{ + const struct ddsi_sertopic_pserop *tp = (const struct ddsi_sertopic_pserop *)tpcmn; + const struct { uint16_t identifier, options; } header = { tp->native_encoding_identifier, 0 }; + if (kind == SDK_KEY && tp->ops_key == NULL) + return serdata_pserop_fix (tp, serdata_pserop_new (tp, kind, 0, &header)); + else + { + void *data; + size_t size; + if (plist_ser_generic (&data, &size, sample, (kind == SDK_DATA) ? tp->ops : tp->ops_key) < 0) + return NULL; + const size_t size4 = (size + 3) & ~(size_t)3; + struct ddsi_serdata_pserop *d = serdata_pserop_new (tp, kind, size4, &header); + assert (tp->ops_key == NULL || (size >= 16 && tp->memsize >= 16)); + assert (d->data != NULL); // clang static analyzer + memcpy (d->data, data, size); + memset (d->data + size, 0, size4 - size); + d->pos = (uint32_t) size; + ddsrt_free (data); // FIXME: shouldn't allocate twice & copy + // FIXME: and then this silly thing deserialises it immediately again -- perhaps it should be a bit lazier + return serdata_pserop_fix (tp, d); + } +} + +static struct ddsi_serdata *serdata_pserop_to_topicless (const struct ddsi_serdata *serdata_common) +{ + const struct ddsi_serdata_pserop *d = (const struct ddsi_serdata_pserop *)serdata_common; + const struct ddsi_sertopic_pserop *tp = (const struct ddsi_sertopic_pserop *)d->c.topic; + ddsrt_iovec_t iov = { .iov_base = (char *) &d->identifier, .iov_len = (ddsrt_iov_len_t) (4 + d->pos) }; + struct ddsi_serdata *dcmn_tl = serdata_pserop_from_ser_iov (&tp->c, SDK_KEY, 1, &iov, iov.iov_len); + assert (dcmn_tl != NULL); + dcmn_tl->topic = NULL; + return dcmn_tl; +} + +static bool serdata_pserop_topicless_to_sample (const struct ddsi_sertopic *topic_common, const struct ddsi_serdata *serdata_common, void *sample, void **bufptr, void *buflim) +{ + const struct ddsi_serdata_pserop *d = (const struct ddsi_serdata_pserop *)serdata_common; + const struct ddsi_sertopic_pserop *tp = (const struct ddsi_sertopic_pserop *)topic_common; + if (bufptr) abort(); else { (void)buflim; } /* FIXME: haven't implemented that bit yet! */ + if (tp->ops_key) + memcpy (sample, d->sample, 16); + return true; +} + +static void serdata_pserop_get_keyhash (const struct ddsi_serdata *serdata_common, struct ddsi_keyhash *buf, bool force_md5) +{ + const struct ddsi_serdata_pserop *d = (const struct ddsi_serdata_pserop *)serdata_common; + const struct ddsi_sertopic_pserop *tp = (const struct ddsi_sertopic_pserop *)d->c.topic; + if (tp->ops_key == NULL) + memset (buf, 0, 16); + else + { + /* need big-endian representation for key hash, so be lazy & re-serialize + (and yes, it costs another malloc ...); note that key at offset 0 implies + ops_key is a prefix of ops */ + void *be; + size_t besize; + (void) plist_ser_generic_be (&be, &besize, d->sample, tp->ops_key); + assert (besize == 16); /* that's the deal with keys for now */ + if (!force_md5) + memcpy (buf, be, 16); + else + { + ddsrt_md5_state_t md5st; + ddsrt_md5_init (&md5st); + ddsrt_md5_append (&md5st, (ddsrt_md5_byte_t *) be, 16); + ddsrt_md5_finish (&md5st, (ddsrt_md5_byte_t *) buf->value); + } + ddsrt_free (be); + } +} + +static size_t serdata_pserop_print_pserop (const struct ddsi_sertopic *sertopic_common, const struct ddsi_serdata *serdata_common, char *buf, size_t size) +{ + const struct ddsi_serdata_pserop *d = (const struct ddsi_serdata_pserop *)serdata_common; + const struct ddsi_sertopic_pserop *tp = (const struct ddsi_sertopic_pserop *)sertopic_common; + return plist_print_generic (buf, size, d->sample, tp->ops); +} + +const struct ddsi_serdata_ops ddsi_serdata_ops_pserop = { + .get_size = serdata_pserop_get_size, + .eqkey = serdata_pserop_eqkey, + .free = serdata_pserop_free, + .from_ser = serdata_pserop_from_ser, + .from_ser_iov = serdata_pserop_from_ser_iov, + .from_keyhash = serdata_pserop_from_keyhash, + .from_sample = serdata_pserop_from_sample, + .to_ser = serdata_pserop_to_ser, + .to_sample = serdata_pserop_to_sample, + .to_ser_ref = serdata_pserop_to_ser_ref, + .to_ser_unref = serdata_pserop_to_ser_unref, + .to_topicless = serdata_pserop_to_topicless, + .topicless_to_sample = serdata_pserop_topicless_to_sample, + .print = serdata_pserop_print_pserop, + .get_keyhash = serdata_pserop_get_keyhash +}; diff --git a/src/core/ddsi/src/ddsi_sertopic.c b/src/core/ddsi/src/ddsi_sertopic.c index 04052cc..8c58c8f 100644 --- a/src/core/ddsi/src/ddsi_sertopic.c +++ b/src/core/ddsi/src/ddsi_sertopic.c @@ -56,8 +56,7 @@ uint32_t ddsi_sertopic_hash (const struct ddsi_sertopic *a) struct ddsi_sertopic *ddsi_sertopic_ref (const struct ddsi_sertopic *sertopic_const) { struct ddsi_sertopic *sertopic = (struct ddsi_sertopic *) sertopic_const; - if (sertopic) - ddsrt_atomic_inc32 (&sertopic->refc); + ddsrt_atomic_inc32 (&sertopic->refc); return sertopic; } @@ -68,7 +67,7 @@ struct ddsi_sertopic *ddsi_sertopic_lookup_locked (struct ddsi_domaingv *gv, con if (sertopic != NULL) assert (sertopic->gv != NULL); #endif - return ddsi_sertopic_ref (sertopic); + return sertopic ? ddsi_sertopic_ref (sertopic) : NULL; } void ddsi_sertopic_register_locked (struct ddsi_domaingv *gv, struct ddsi_sertopic *sertopic) @@ -84,21 +83,18 @@ void ddsi_sertopic_register_locked (struct ddsi_domaingv *gv, struct ddsi_sertop void ddsi_sertopic_unref (struct ddsi_sertopic *sertopic) { - if (sertopic) + if (ddsrt_atomic_dec32_ov (&sertopic->refc) == 1) { - if (ddsrt_atomic_dec32_ov (&sertopic->refc) == 1) + /* if registered, drop from set of registered sertopics */ + if (sertopic->gv) { - /* if registered, drop from set of registered sertopics */ - if (sertopic->gv) - { - ddsrt_mutex_lock (&sertopic->gv->sertopics_lock); - (void) ddsrt_hh_remove (sertopic->gv->sertopics, sertopic); - ddsrt_mutex_unlock (&sertopic->gv->sertopics_lock); - sertopic->gv = NULL; - } - - ddsi_sertopic_free (sertopic); + ddsrt_mutex_lock (&sertopic->gv->sertopics_lock); + (void) ddsrt_hh_remove (sertopic->gv->sertopics, sertopic); + ddsrt_mutex_unlock (&sertopic->gv->sertopics_lock); + sertopic->gv = NULL; } + + ddsi_sertopic_free (sertopic); } } diff --git a/src/core/ddsi/src/ddsi_sertopic_plist.c b/src/core/ddsi/src/ddsi_sertopic_plist.c new file mode 100644 index 0000000..f9f98b0 --- /dev/null +++ b/src/core/ddsi/src/ddsi_sertopic_plist.c @@ -0,0 +1,95 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/mh3.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsi/ddsi_plist.h" +#include "dds/ddsi/ddsi_sertopic.h" +#include "dds/ddsi/ddsi_serdata_plist.h" + +static bool sertopic_plist_equal (const struct ddsi_sertopic *acmn, const struct ddsi_sertopic *bcmn) +{ + const struct ddsi_sertopic_plist *a = (struct ddsi_sertopic_plist *) acmn; + const struct ddsi_sertopic_plist *b = (struct ddsi_sertopic_plist *) bcmn; + if (a->native_encoding_identifier != b->native_encoding_identifier) + return false; + if (a->keyparam != b->keyparam) + return false; + return true; +} + +static uint32_t sertopic_plist_hash (const struct ddsi_sertopic *tpcmn) +{ + const struct ddsi_sertopic_plist *tp = (struct ddsi_sertopic_plist *) tpcmn; + uint32_t h = 0; + h = ddsrt_mh3 (&tp->native_encoding_identifier, sizeof (tp->native_encoding_identifier), h); + h = ddsrt_mh3 (&tp->keyparam, sizeof (tp->keyparam), h); + return h; +} + +static void sertopic_plist_free (struct ddsi_sertopic *tpcmn) +{ + struct ddsi_sertopic_plist *tp = (struct ddsi_sertopic_plist *) tpcmn; + ddsi_sertopic_fini (&tp->c); + ddsrt_free (tp); +} + +static void sertopic_plist_zero_samples (const struct ddsi_sertopic *sertopic_common, void *sample, size_t count) +{ + (void) sertopic_common; + ddsi_plist_t *xs = sample; + for (size_t i = 0; i < count; i++) + ddsi_plist_init_empty (&xs[i]); +} + +static void sertopic_plist_realloc_samples (void **ptrs, const struct ddsi_sertopic *sertopic_common, void *old, size_t oldcount, size_t count) +{ + (void) sertopic_common; + ddsi_plist_t *new = (oldcount == count) ? old : dds_realloc (old, count * sizeof (ddsi_plist_t)); + if (new) + { + for (size_t i = count; i < oldcount; i++) + ddsi_plist_init_empty (&new[i]); + for (size_t i = 0; i < count; i++) + ptrs[i] = &new[i]; + } +} + +static void sertopic_plist_free_samples (const struct ddsi_sertopic *sertopic_common, void **ptrs, size_t count, dds_free_op_t op) +{ + (void) sertopic_common; + if (count > 0) + { +#ifndef NDEBUG + for (size_t i = 0, off = 0; i < count; i++, off += sizeof (ddsi_plist_t)) + assert ((char *)ptrs[i] == (char *)ptrs[0] + off); +#endif + ddsi_plist_t *xs = ptrs[0]; + for (size_t i = 0; i < count; i++) + ddsi_plist_fini (&xs[i]); + if (op & DDS_FREE_ALL_BIT) + dds_free (ptrs[0]); + } +} + +const struct ddsi_sertopic_ops ddsi_sertopic_ops_plist = { + .equal = sertopic_plist_equal, + .hash = sertopic_plist_hash, + .free = sertopic_plist_free, + .zero_samples = sertopic_plist_zero_samples, + .realloc_samples = sertopic_plist_realloc_samples, + .free_samples = sertopic_plist_free_samples +}; diff --git a/src/core/ddsi/src/ddsi_sertopic_pserop.c b/src/core/ddsi/src/ddsi_sertopic_pserop.c new file mode 100644 index 0000000..c8ebdb9 --- /dev/null +++ b/src/core/ddsi/src/ddsi_sertopic_pserop.c @@ -0,0 +1,118 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "dds/ddsrt/md5.h" +#include "dds/ddsrt/mh3.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsi/q_bswap.h" +#include "dds/ddsi/q_config.h" +#include "dds/ddsi/q_freelist.h" +#include "dds/ddsi/ddsi_plist_generic.h" +#include "dds/ddsi/ddsi_sertopic.h" +#include "dds/ddsi/ddsi_serdata_pserop.h" + +static bool sertopic_pserop_equal (const struct ddsi_sertopic *acmn, const struct ddsi_sertopic *bcmn) +{ + const struct ddsi_sertopic_pserop *a = (struct ddsi_sertopic_pserop *) acmn; + const struct ddsi_sertopic_pserop *b = (struct ddsi_sertopic_pserop *) bcmn; + if (a->native_encoding_identifier != b->native_encoding_identifier) + return false; + if (a->memsize != b->memsize) + return false; + if (a->nops != b->nops) + return false; + assert (a->nops > 0); + if (memcmp (a->ops, b->ops, a->nops * sizeof (*a->ops)) != 0) + return false; + if (a->nops_key != b->nops_key) + return false; + if (a->ops_key && memcmp (a->ops_key, b->ops_key, a->nops_key * sizeof (*a->ops_key)) != 0) + return false; + return true; +} + +static uint32_t sertopic_pserop_hash (const struct ddsi_sertopic *tpcmn) +{ + const struct ddsi_sertopic_pserop *tp = (struct ddsi_sertopic_pserop *) tpcmn; + uint32_t h = 0; + h = ddsrt_mh3 (&tp->native_encoding_identifier, sizeof (tp->native_encoding_identifier), h); + h = ddsrt_mh3 (&tp->memsize, sizeof (tp->memsize), h); + h = ddsrt_mh3 (&tp->nops, sizeof (tp->nops), h); + h = ddsrt_mh3 (tp->ops, tp->nops * sizeof (*tp->ops), h); + h = ddsrt_mh3 (&tp->nops_key, sizeof (tp->nops_key), h); + if (tp->ops_key) + h = ddsrt_mh3 (tp->ops_key, tp->nops_key * sizeof (*tp->ops_key), h); + return h; +} + +static void sertopic_pserop_free (struct ddsi_sertopic *tpcmn) +{ + struct ddsi_sertopic_pserop *tp = (struct ddsi_sertopic_pserop *) tpcmn; + ddsi_sertopic_fini (&tp->c); + ddsrt_free (tp); +} + +static void sertopic_pserop_zero_samples (const struct ddsi_sertopic *sertopic_common, void *sample, size_t count) +{ + const struct ddsi_sertopic_pserop *tp = (const struct ddsi_sertopic_pserop *)sertopic_common; + memset (sample, 0, tp->memsize * count); +} + +static void sertopic_pserop_realloc_samples (void **ptrs, const struct ddsi_sertopic *sertopic_common, void *old, size_t oldcount, size_t count) +{ + const struct ddsi_sertopic_pserop *tp = (const struct ddsi_sertopic_pserop *)sertopic_common; + const size_t size = tp->memsize; + char *new = (oldcount == count) ? old : dds_realloc (old, size * count); + if (new && count > oldcount) + memset (new + size * oldcount, 0, size * (count - oldcount)); + for (size_t i = 0; i < count; i++) + { + void *ptr = (char *) new + i * size; + ptrs[i] = ptr; + } +} + +static void sertopic_pserop_free_samples (const struct ddsi_sertopic *sertopic_common, void **ptrs, size_t count, dds_free_op_t op) +{ + if (count > 0) + { + const struct ddsi_sertopic_pserop *tp = (const struct ddsi_sertopic_pserop *)sertopic_common; + const size_t size = tp->memsize; +#ifndef NDEBUG + for (size_t i = 0, off = 0; i < count; i++, off += size) + assert ((char *)ptrs[i] == (char *)ptrs[0] + off); +#endif + char *ptr = ptrs[0]; + for (size_t i = 0; i < count; i++) + { + plist_fini_generic (ptr, tp->ops, false); + ptr += size; + } + if (op & DDS_FREE_ALL_BIT) + { + dds_free (ptrs[0]); + } + } +} + +const struct ddsi_sertopic_ops ddsi_sertopic_ops_pserop = { + .equal = sertopic_pserop_equal, + .hash = sertopic_pserop_hash, + .free = sertopic_pserop_free, + .zero_samples = sertopic_pserop_zero_samples, + .realloc_samples = sertopic_pserop_realloc_samples, + .free_samples = sertopic_pserop_free_samples +}; diff --git a/src/core/ddsi/src/ddsi_udp.c b/src/core/ddsi/src/ddsi_udp.c index 65d10fd..d67929d 100644 --- a/src/core/ddsi/src/ddsi_udp.c +++ b/src/core/ddsi/src/ddsi_udp.c @@ -477,11 +477,11 @@ static dds_return_t ddsi_udp_create_conn (ddsi_tran_conn_t *conn_out, ddsi_tran_ } } - if ((rc = set_rcvbuf (gv, sock, &gv->config.socket_min_rcvbuf_size)) != DDS_RETCODE_OK) + if (set_rcvbuf (gv, sock, &gv->config.socket_min_rcvbuf_size) != DDS_RETCODE_OK) goto fail_w_socket; - if ((rc = set_sndbuf (gv, sock, gv->config.socket_min_sndbuf_size)) != DDS_RETCODE_OK) + if (set_sndbuf (gv, sock, gv->config.socket_min_sndbuf_size) != DDS_RETCODE_OK) goto fail_w_socket; - if (gv->config.dontRoute && (rc = set_dont_route (gv, sock, ipv6)) != DDS_RETCODE_OK) + if (gv->config.dontRoute && set_dont_route (gv, sock, ipv6) != DDS_RETCODE_OK) goto fail_w_socket; if ((rc = ddsrt_bind (sock, &socketname.a, ddsrt_sockaddr_get_size (&socketname.a))) != DDS_RETCODE_OK) diff --git a/src/core/ddsi/src/q_config.c b/src/core/ddsi/src/q_config.c index 2193d1e..1f5ffa1 100644 --- a/src/core/ddsi/src/q_config.c +++ b/src/core/ddsi/src/q_config.c @@ -207,6 +207,9 @@ DI(if_partition_mapping); #endif DI(if_peer); DI(if_thread_properties); +#ifdef DDSI_INCLUDE_SECURITY +DI(if_omg_security); +#endif #undef DI #define CO(name) ((int) offsetof (struct config, name)) @@ -277,6 +280,151 @@ static const struct cfgelem general_cfgelems[] = { END_MARKER }; +#ifdef DDSI_INCLUDE_SECURITY +/** Security Configuration */ +static const struct cfgelem authentication_library_attributes[] = { + { ATTR ("path"), 1, "dds_security_auth", RELOFF (config_omg_security_listelem, cfg.authentication_plugin.library_path), 0, uf_string, ff_free, pf_string, + BLURB("

    This element points to the path of Authentication plugin library.

    \n\ +

    It can be either absolute path excluding file extension ( /usr/lib/dds_security_auth ) or single file without extension ( dds_security_auth ).

    \n\ +

    If single file is supplied, the library located by way of the current working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for Windows systems.

    ") }, + { ATTR ("initFunction"), 1, "init_authentication", RELOFF (config_omg_security_listelem, cfg.authentication_plugin.library_init), 0, uf_string, ff_free, pf_string, + BLURB("

    This element names the initialization function of Authentication plugin. This function is called after loading the plugin library for instantiation purposes. Init function must return an object that implements DDS Security Authentication interface.

    ") }, + { ATTR ("finalizeFunction"), 1, "finalize_authentication", RELOFF (config_omg_security_listelem, cfg.authentication_plugin.library_finalize), 0, uf_string, ff_free, pf_string, + BLURB("

    This element names the finalization function of Authentication plugin. This function is called to let the plugin release its resources.

    ") }, + END_MARKER +}; + +static const struct cfgelem access_control_library_attributes[] = { + { ATTR ("path"), 1, "dds_security_ac", RELOFF (config_omg_security_listelem, cfg.access_control_plugin.library_path), 0, uf_string, ff_free, pf_string, + BLURB("

    This element points to the path of Access Control plugin library.

    \n\ +

    It can be either absolute path excluding file extension ( /usr/lib/dds_security_ac ) or single file without extension ( dds_security_ac ).

    \n\ +

    If single file is supplied, the library located by way of the current working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for Windows systems.

    ") }, + { ATTR ("initFunction"), 1, "init_access_control", RELOFF (config_omg_security_listelem, cfg.access_control_plugin.library_init), 0, uf_string, ff_free, pf_string, + BLURB("

    This element names the initialization function of Access Control plugin. This function is called after loading the plugin library for instantiation purposes. Init function must return an object that implements DDS Security Access Control interface.

    ") }, + { ATTR ("finalizeFunction"), 1, "finalize_access_control", RELOFF (config_omg_security_listelem, cfg.access_control_plugin.library_finalize), 0, uf_string, ff_free, pf_string, + BLURB("

    This element names the finalization function of Access Control plugin. This function is called to let the plugin release its resources.

    ") }, + END_MARKER +}; + +static const struct cfgelem cryptography_library_attributes[] = { + { ATTR ("path"), 1, "dds_security_crypto", RELOFF (config_omg_security_listelem, cfg.cryptography_plugin.library_path), 0, uf_string, ff_free, pf_string, + BLURB("

    This element points to the path of Cryptographic plugin library.

    \n\ +

    It can be either absolute path excluding file extension ( /usr/lib/dds_security_crypto ) or single file without extension ( dds_security_crypto ).

    \n\ +

    If single file is supplied, the library located by way of the current working directory, or LD_LIBRARY_PATH for Unix systems, and PATH for Windows systems.

    ") }, + { ATTR ("initFunction"), 1, "init_crypto", RELOFF (config_omg_security_listelem, cfg.cryptography_plugin.library_init), 0, uf_string, ff_free, pf_string, + BLURB("

    This element names the initialization function of Cryptographic plugin. This function is called after loading the plugin library for instantiation purposes. Init function must return an object that implements DDS Security Cryptographic interface.

    ") }, + { ATTR ("finalizeFunction"), 1, "finalize_crypto", RELOFF (config_omg_security_listelem, cfg.cryptography_plugin.library_finalize), 0, uf_string, ff_free, pf_string, + BLURB("

    This element names the finalization function of Cryptographic plugin. This function is called to let the plugin release its resources.

    ") }, + END_MARKER +}; + + +static const struct cfgelem authentication_config_elements[] = { + { LEAF_W_ATTRS("Library", authentication_library_attributes), 1, "", RELOFF (config_omg_security_listelem, cfg.authentication_plugin), 0, 0, 0, pf_string, + BLURB("

    This element specifies the library to be loaded as the DDS Security Access Control plugin.

    ") }, + { LEAF ("IdentityCertificate"), 1, NULL, RELOFF (config_omg_security_listelem, cfg.authentication_properties.identity_certificate), 0, uf_string, ff_free, pf_string, + BLURB("

    Identity certificate that will be used for identifying all participants in the OSPL instance.
    The content is URI to a X509 certificate signed by the IdentityCA in PEM format containing the signed public key.

    \n\ +

    Supported URI schemes: file, data

    \n\ +

    Examples:

    \n\ +

    file:participant1_identity_cert.pem

    \n\ +

    data:,-----BEGIN CERTIFICATE-----
    \n\ +MIIDjjCCAnYCCQDCEu9...6rmT87dhTo=
    \n\ +-----END CERTIFICATE-----

    ") }, + { LEAF ("IdentityCA"), 1, NULL, RELOFF (config_omg_security_listelem, cfg.authentication_properties.identity_ca), 0, uf_string, ff_free, pf_string, + BLURB("

    URI to the X509 certificate [39] of the Identity CA that is the signer of Identity Certificate.

    \n\ +

    Supported URI schemes: file, data

    \n\ +

    The file and data schemas shall refer to a X.509 v3 certificate (see X.509 v3 ITU-T Recommendation X.509 (2005) [39]) in PEM format.

    \n\ +

    Examples:

    \n\ +

    file:identity_ca.pem

    \n\ +

    data:,-----BEGIN CERTIFICATE-----
    \n\ +MIIC3DCCAcQCCQCWE5x+Z...PhovK0mp2ohhRLYI0ZiyYQ==
    \n\ +-----END CERTIFICATE-----

    ") }, + { LEAF ("PrivateKey"), 1, NULL, RELOFF (config_omg_security_listelem, cfg.authentication_properties.private_key), 0, uf_string, ff_free, pf_string, + BLURB("

    URI to access the private Private Key for all of the participants in the OSPL federation.

    \n\ +

    Supported URI schemes: file, data

    \n\ +

    Examples:

    \n\ +

    file:identity_ca_private_key.pem

    \n\ +

    data:,-----BEGIN RSA PRIVATE KEY-----
    \n\ +MIIEpAIBAAKCAQEA3HIh...AOBaaqSV37XBUJg==
    \n\ +-----END RSA PRIVATE KEY-----

    ") }, + { LEAF ("Password"), 1, "", RELOFF (config_omg_security_listelem, cfg.authentication_properties.password), 0, uf_string, ff_free, pf_string, + BLURB("

    A password used to decrypt the private_key.

    \n\ +The value of the password property shall be interpreted as the Base64 encoding of the AES-128 key that shall be used to decrypt the private_key using AES128-CBC.

    \n\ +If the password property is not present, then the value supplied in the private_key property must contain the unencrypted private key.

    ") }, + { LEAF ("TrustedCADirectory"), 1, "", RELOFF (config_omg_security_listelem, cfg.authentication_properties.trusted_ca_dir), 0, uf_string, ff_free, pf_string, + BLURB("

    Trusted CA Directory which contains trusted CA certificates as separated files.

    ") }, + { LEAF ("IncludeOptionalFields"), 1, "false", RELOFF (config_omg_security_listelem, cfg.authentication_properties.include_optional_fields), 0, uf_boolean, 0, pf_boolean, + BLURB("

    The authentication handshake tokens may contain optional fields to be included for finding interoperability problems.\n\ +If this parameter is set to true the optional fields are included in the handshake token exchange.

    ") }, + END_MARKER +}; + +static const struct cfgelem access_control_config_elements[] = { + { LEAF_W_ATTRS("Library", access_control_library_attributes), 1, "", RELOFF (config_omg_security_listelem, cfg.access_control_plugin), 0, 0, 0, pf_string, + BLURB("

    This element specifies the library to be loaded as the DDS Security Access Control plugin.

    ") }, + { LEAF ("PermissionsCA"), 1, "", RELOFF (config_omg_security_listelem, cfg.access_control_properties.permissions_ca), 0, uf_string, ff_free, pf_string, + BLURB("

    URI to a X509 certificate for the PermissionsCA in PEM format.

    \n\ +

    Supported URI schemes: file, data

    \n\ +

    The file and data schemas shall refer to a X.509 v3 certificate (see X.509 v3 ITU-T Recommendation X.509 (2005) [39]) in PEM format.


    \n\ +

    Examples:


    \n\ +

    file:permissions_ca.pem

    \n\ +

    file:/home/myuser/permissions_ca.pem


    \n\ +

    data:,-----BEGIN CERTIFICATE-----

    \n\ +

    MIIC3DCCAcQCCQCWE5x+Z ... PhovK0mp2ohhRLYI0ZiyYQ==

    \n\ +

    -----END CERTIFICATE-----

    ") }, + { LEAF ("Governance"), 1, "", RELOFF (config_omg_security_listelem, cfg.access_control_properties.governance), 0, uf_string, ff_free, pf_string, + BLURB("

    URI to the shared Governance Document signed by the Permissions CA in S/MIME format

    \n\ +

    URI schemes: file, data


    \n\ +

    Examples file URIs:

    \n\ +

    file:governance.smime

    \n\ +

    file:/home/myuser/governance.smime


    \n\ +

    \n\ +

    Content-Type: multipart/signed; protocol=\"application/x-pkcs7-signature\"; micalg=\"sha-256\"; boundary=\"----F9A8A198D6F08E1285A292ADF14DD04F\"

    \n\ +

    This is an S/MIME signed message

    \n\ +

    ------F9A8A198D6F08E1285A292ADF14DD04F

    \n\ +

    \n\ +

    \n\ +

    xsi:noNamespaceSchemaLocation=\"omg_shared_ca_governance.xsd\">

    \n\ +

    \n\ +

    . . .

    \n\ +

    \n\ +

    \n\ +

    ...

    \n\ +

    ------F9A8A198D6F08E1285A292ADF14DD04F

    \n\ +

    Content-Type: application/x-pkcs7-signature; name=\"smime.p7s\"

    \n\ +

    Content-Transfer-Encoding: base64

    \n\ +

    Content-Disposition: attachment; filename=\"smime.p7s\"

    \n\ +

    MIIDuAYJKoZIhv ...al5s=

    \n\ +

    ------F9A8A198D6F08E1285A292ADF14DD04F-]]

    ") }, + { LEAF ("Permissions"), 1, "", RELOFF (config_omg_security_listelem, cfg.access_control_properties.permissions), 0, uf_string, ff_free, pf_string, + BLURB("

    URI to the DomainParticipant permissions document signed by the Permissions CA in S/MIME format

    \n\ +

    The permissions document specifies the permissions to be applied to a domain.


    \n\ +

    Example file URIs:

    \n\ +

    file:permissions_document.p7s

    \n\ +

    file:/path_to/permissions_document.p7s

    \n\ +

    Example data URI:

    \n\ +

    ") }, + END_MARKER +}; + +static const struct cfgelem cryptography_config_elements[] = { + { LEAF_W_ATTRS("Library", cryptography_library_attributes), 1, "", RELOFF (config_omg_security_listelem, cfg.cryptography_plugin), 0, 0, 0, pf_string, + BLURB("

    This element specifies the library to be loaded as the DDS Security Cryptographic plugin.

    ") }, + END_MARKER +}; + +static const struct cfgelem security_omg_config_elements[] = { + { GROUP ("Authentication", authentication_config_elements), + BLURB("

    This element configures the Authentication plugin of the DDS Security specification.

    ") }, + { GROUP ("AccessControl", access_control_config_elements), + BLURB("

    This element configures the Access Control plugin of the DDS Security specification.

    ") }, + { GROUP ("Cryptographic", cryptography_config_elements), + BLURB("

    This element configures the Cryptographic plugin of the DDS Security specification.

    ") }, + END_MARKER +}; +#endif /* DDSI_INCLUDE_SECURITY */ + + #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS static const struct cfgelem networkpartition_cfgattrs[] = { { ATTR("Name"), 1, NULL, RELOFF(config_networkpartition_listelem, name), 0, uf_string, ff_free, pf_string, @@ -382,6 +530,7 @@ static const struct cfgelem thread_properties_cfgattrs[] = {
  • dq.builtins: delivery thread for DDSI-builtin data, primarily for discovery;
  • \n\
  • lease: DDSI liveliness monitoring;
  • \n\
  • tev: general timed-event handling, retransmits and discovery;
  • \n\ +
  • fsm: finite state machine thread for handling security handshake;
  • \n\
  • xmit.CHAN: transmit thread for channel CHAN;
  • \n\
  • dq.CHAN: delivery thread for channel CHAN;
  • \n\
  • tev.CHAN: timed-event thread for channel CHAN.
  • ") }, @@ -579,7 +728,7 @@ static const struct cfgelem internal_cfgelems[] = { BLURB("

    Do not use.

    ") }, { LEAF("SendAsync"), 1, "false", ABSOFF(xpack_send_async), 0, uf_boolean, 0, pf_boolean, BLURB("

    This element controls whether the actual sending of packets occurs on the same thread that prepares them, or is done asynchronously by another thread.

    ") }, - { LEAF_W_ATTRS("RediscoveryBlacklistDuration", rediscovery_blacklist_duration_attrs), 1, "10s", ABSOFF(prune_deleted_ppant.delay), 0, uf_duration_inf, 0, pf_duration, + { LEAF_W_ATTRS("RediscoveryBlacklistDuration", rediscovery_blacklist_duration_attrs), 1, "0s", ABSOFF(prune_deleted_ppant.delay), 0, uf_duration_inf, 0, pf_duration, BLURB("

    This element controls for how long a remote participant that was previously deleted will remain on a blacklist to prevent rediscovery, giving the software on a node time to perform any cleanup actions it needs to do. To some extent this delay is required internally by DDSI2E, but in the default configuration with the 'enforce' attribute set to false, DDSI2E will reallow rediscovery as soon as it has cleared its internal administration. Setting it to too small a value may result in the entry being pruned from the blacklist before DDSI2E is ready, it is therefore recommended to set it to at least several seconds.

    ") }, { LEAF_W_ATTRS("MultipleReceiveThreads", multiple_recv_threads_attrs), 1, "default", ABSOFF(multiple_recv_threads), 0, uf_boolean_default, 0, pf_boolean_default, BLURB("

    This element controls whether all traffic is handled by a single receive thread (false) or whether multiple receive threads may be used to improve latency (true). By default it is disabled on Windows because it appears that one cannot count on being able to send packets to oneself, which is necessary to stop the thread during shutdown. Currently multiple receive threads are only used for connectionless transport (e.g., UDP) and ManySocketsMode not set to single (the default).

    ") }, @@ -716,8 +865,6 @@ static const struct cfgelem discovery_cfgelems[] = { BLURB("

    This element specifies the interval between spontaneous transmissions of participant discovery packets.

    ") }, { LEAF("DefaultMulticastAddress"), 1, "auto", ABSOFF(defaultMulticastAddressString), 0, uf_networkAddress, 0, pf_networkAddress, BLURB("

    This element specifies the default multicast address for all traffic other than participant discovery packets. It defaults to Discovery/SPDPMulticastAddress.

    ") }, - { LEAF("EnableTopicDiscovery"), 1, "true", ABSOFF(do_topic_discovery), 0, uf_boolean, 0, pf_boolean, - BLURB("

    Do not use.

    ") }, { GROUP("Ports", discovery_ports_cfgelems), BLURB("

    The Ports element allows specifying various parameters related to the port numbers used for discovery. These all have default values specified by the DDSI 2.1 specification and rarely need to be changed.

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

    The General element specifies overall DDSI2E service settings.

    ") }, +#ifdef DDSI_INCLUDE_SECURITY + { MGROUP ("DDSSecurity", security_omg_config_elements, NULL), INT_MAX, NULL, ABSOFF(omg_security_configuration), if_omg_security, 0, 0, 0, + BLURB("

    This element is used to configure DDSI2E with the DDS Security specification plugins and settings.

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

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

    ") }, @@ -822,6 +973,9 @@ static const struct cfgelem root_cfgelems[] = { { MOVED("Internal|Unsupported", "CycloneDDS/Domain/Internal") }, { MOVED("TCP", "CycloneDDS/Domain/TCP") }, { MOVED("ThreadPool", "CycloneDDS/Domain/ThreadPool") }, +#ifdef DDSI_INCLUDE_SECURITY + { MOVED("DDSSecurity", "CycloneDDS/Domain/DDSSecurity") }, +#endif #ifdef DDSI_INCLUDE_SSL { MOVED("SSL", "CycloneDDS/Domain/SSL") }, #endif @@ -1234,20 +1388,30 @@ static int if_network_partition (struct cfgst *cfgst, void *parent, struct cfgel if (new == NULL) return -1; new->address_string = NULL; + new->as = NULL; + new->name = NULL; + new->partitionId = 0; + new->connected = 0; return 0; } static int if_ignored_partition (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) { + struct config_ignoredpartition_listelem *new = if_common (cfgst, parent, cfgelem, sizeof(*new)); if (if_common (cfgst, parent, cfgelem, sizeof (struct config_ignoredpartition_listelem)) == NULL) return -1; + new->DCPSPartitionTopic = NULL; return 0; } static int if_partition_mapping (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) { - if (if_common (cfgst, parent, cfgelem, sizeof (struct config_partitionmapping_listelem)) == NULL) + struct config_partitionmapping_listelem *new = if_common (cfgst, parent, cfgelem, sizeof(*new)); + if (new == NULL) return -1; + new->DCPSPartitionTopic = NULL; + new->networkPartition = NULL; + new->partition = NULL; return 0; } #endif /* DDSI_INCLUDE_NETWORK_PARTITIONS */ @@ -1261,6 +1425,17 @@ static int if_peer (struct cfgst *cfgst, void *parent, struct cfgelem const * co return 0; } +#ifdef DDSI_INCLUDE_SECURITY +static int if_omg_security (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) +{ + struct config_omg_security_listelem *new = if_common (cfgst, parent, cfgelem, sizeof (struct config_omg_security_listelem)); + if (new == NULL) + return -1; + memset(&new->cfg, 0, sizeof(new->cfg)); + return 0; +} +#endif + static void ff_free (struct cfgst *cfgst, void *parent, struct cfgelem const * const cfgelem) { void ** const elem = cfg_address (cfgst, parent, cfgelem); @@ -2081,14 +2256,13 @@ static int set_defaults (struct cfgst *cfgst, void *parent, int isattr, struct c int ok = 1; for (const struct cfgelem *ce = cfgelem; ce && ce->name; ce++) { - struct cfgst_node *n; struct cfgst_nodekey key; key.e = ce; key.p = parent; cfgst_push (cfgst, isattr, ce, parent); if (ce->multiplicity <= 1) { - if ((n = ddsrt_avl_lookup (&cfgst_found_treedef, &cfgst->found, &key)) == NULL) + if (ddsrt_avl_lookup (&cfgst_found_treedef, &cfgst->found, &key) == NULL) { if (ce->update) { @@ -2773,6 +2947,7 @@ struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domi /* Compatibility settings of IPv6, TCP -- a bit too complicated for the poor framework */ + if (ok) { int ok1 = 1; switch (cfgst->cfg->transport_selector) @@ -2782,7 +2957,7 @@ struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domi cfgst->cfg->transport_selector = (cfgst->cfg->compat_use_ipv6 == BOOLDEF_TRUE) ? TRANS_TCP6 : TRANS_TCP; else cfgst->cfg->transport_selector = (cfgst->cfg->compat_use_ipv6 == BOOLDEF_TRUE) ? TRANS_UDP6 : TRANS_UDP; - break; + break; case TRANS_TCP: ok1 = !(cfgst->cfg->compat_tcp_enable == BOOLDEF_FALSE || cfgst->cfg->compat_use_ipv6 == BOOLDEF_TRUE); break; @@ -2809,14 +2984,18 @@ struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domi #ifdef DDSI_INCLUDE_NETWORK_CHANNELS /* Default channel gets set outside set_defaults -- a bit too complicated for the poor framework */ - if (set_default_channel (cfgst->cfg) < 0) - ok = 0; - if (cfgst->cfg->channels && sort_channels_check_nodups (cfgst->cfg) < 0) - ok = 0; + if (ok) + { + if (set_default_channel (cfgst->cfg) < 0) + ok = 0; + if (cfgst->cfg->channels && sort_channels_check_nodups (cfgst->cfg) < 0) + ok = 0; + } #endif #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS /* Assign network partition ids */ + if (ok) { struct config_networkpartition_listelem *p = cfgst->cfg->networkPartitions; cfgst->cfg->nof_networkPartitions = 0; @@ -2830,6 +3009,7 @@ struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domi /* Create links from the partitionmappings to the network partitions and signal errors if partitions do not exist */ + if (ok) { struct config_partitionmapping_listelem * m = cfgst->cfg->partitionMappings; while (m) diff --git a/src/core/ddsi/src/q_ddsi_discovery.c b/src/core/ddsi/src/q_ddsi_discovery.c index 67a8d62..1f031d2 100644 --- a/src/core/ddsi/src/q_ddsi_discovery.c +++ b/src/core/ddsi/src/q_ddsi_discovery.c @@ -32,6 +32,7 @@ #include "dds/ddsi/q_xevent.h" #include "dds/ddsi/q_addrset.h" #include "dds/ddsi/q_ddsi_discovery.h" +#include "dds/ddsi/ddsi_serdata_plist.h" #include "dds/ddsi/q_radmin.h" #include "dds/ddsi/ddsi_entity_index.h" @@ -43,7 +44,11 @@ #include "dds/ddsi/q_lease.h" #include "dds/ddsi/ddsi_serdata_default.h" #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) { @@ -171,60 +176,22 @@ static void maybe_add_pp_as_meta_to_as_disc (struct ddsi_domaingv *gv, const str } } -static int write_mpayload (struct writer *wr, int alive, nn_parameterid_t keyparam, struct nn_xmsg *mpayload) +void get_participant_builtin_topic_data (const struct participant *pp, ddsi_plist_t *dst, struct participant_builtin_topic_data_locators *locs) { - struct thread_state1 * const ts1 = lookup_thread_state (); - struct ddsi_plist_sample plist_sample; - struct ddsi_serdata *serdata; - nn_xmsg_payload_to_plistsample (&plist_sample, keyparam, mpayload); - serdata = ddsi_serdata_from_sample (wr->e.gv->plist_topic, alive ? SDK_DATA : SDK_KEY, &plist_sample); - serdata->statusinfo = alive ? 0 : NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER; - serdata->timestamp = ddsrt_time_wallclock (); - return write_sample_nogc_notk (ts1, NULL, wr, serdata); -} - -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.prefix, 0, NN_XMSG_KIND_DATA); - - ddsi_plist_init_empty (&ps); - ps.present |= PP_PARTICIPANT_GUID | PP_BUILTIN_ENDPOINT_SET | + ddsi_plist_init_empty (dst); + dst->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; + dst->participant_guid = pp->e.guid; + dst->builtin_endpoint_set = pp->bes; + dst->protocol_version.major = RTPS_MAJOR; + dst->protocol_version.minor = RTPS_MINOR; + dst->vendorid = NN_VENDORID_ECLIPSE; + dst->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 @@ -232,34 +199,34 @@ int spdp_write (struct participant *pp) 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; + dst->present |= PP_DOMAIN_TAG; + dst->aliased |= PP_DOMAIN_TAG; + dst->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; + dst->default_unicast_locators.n = 1; + dst->default_unicast_locators.first = + dst->default_unicast_locators.last = &locs->def_uni_loc_one; + dst->metatraffic_unicast_locators.n = 1; + dst->metatraffic_unicast_locators.first = + dst->metatraffic_unicast_locators.last = &locs->meta_uni_loc_one; + locs->def_uni_loc_one.next = NULL; + locs->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; + locs->def_uni_loc_one.loc = pp->m_locator; + locs->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; + locs->def_uni_loc_one.loc = pp->e.gv->loc_default_uc; + locs->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; + dst->present |= PP_DEFAULT_UNICAST_LOCATOR | PP_METATRAFFIC_UNICAST_LOCATOR; + dst->aliased |= PP_DEFAULT_UNICAST_LOCATOR | PP_METATRAFFIC_UNICAST_LOCATOR; } if (pp->e.gv->config.allowMulticast) @@ -280,85 +247,130 @@ int spdp_write (struct participant *pp) #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; + dst->present |= PP_DEFAULT_MULTICAST_LOCATOR | PP_METATRAFFIC_MULTICAST_LOCATOR; + dst->aliased |= PP_DEFAULT_MULTICAST_LOCATOR | PP_METATRAFFIC_MULTICAST_LOCATOR; + dst->default_multicast_locators.n = 1; + dst->default_multicast_locators.first = + dst->default_multicast_locators.last = &locs->def_multi_loc_one; + dst->metatraffic_multicast_locators.n = 1; + dst->metatraffic_multicast_locators.first = + dst->metatraffic_multicast_locators.last = &locs->meta_multi_loc_one; + locs->def_multi_loc_one.next = NULL; + locs->def_multi_loc_one.loc = pp->e.gv->loc_default_mc; + locs->meta_multi_loc_one.next = NULL; + locs->meta_multi_loc_one.loc = pp->e.gv->loc_meta_mc; } } - ps.participant_lease_duration = pp->lease_duration; + dst->participant_lease_duration = pp->lease_duration; /* Add Adlink specific version information */ { - ps.present |= PP_ADLINK_PARTICIPANT_VERSION_INFO; - memset (&ps.adlink_participant_version_info, 0, sizeof (ps.adlink_participant_version_info)); - ps.adlink_participant_version_info.version = 0; - ps.adlink_participant_version_info.flags = + dst->present |= PP_ADLINK_PARTICIPANT_VERSION_INFO; + memset (&dst->adlink_participant_version_info, 0, sizeof (dst->adlink_participant_version_info)); + dst->adlink_participant_version_info.version = 0; + dst->adlink_participant_version_info.flags = NN_ADLINK_FL_DDSI2_PARTICIPANT_FLAG | NN_ADLINK_FL_PTBES_FIXED_0 | NN_ADLINK_FL_SUPPORTS_STATUSINFOX; if (pp->e.gv->config.besmode == BESMODE_MINIMAL) - ps.adlink_participant_version_info.flags |= NN_ADLINK_FL_MINIMAL_BES_MODE; + dst->adlink_participant_version_info.flags |= NN_ADLINK_FL_MINIMAL_BES_MODE; ddsrt_mutex_lock (&pp->e.gv->privileged_pp_lock); if (pp->is_ddsi2_pp) - ps.adlink_participant_version_info.flags |= NN_ADLINK_FL_PARTICIPANT_IS_DDSI2; + dst->adlink_participant_version_info.flags |= NN_ADLINK_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.adlink_participant_version_info.internals = ddsrt_malloc(size); - (void) snprintf(ps.adlink_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.adlink_participant_version_info.internals); + dst->adlink_participant_version_info.internals = ddsrt_malloc(size); + (void) snprintf(dst->adlink_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), dst->adlink_participant_version_info.internals); } - /* Participant QoS's insofar as they are set, different from the default. Currently, that means just USER_DATA. */ +#ifdef DDSI_INCLUDE_SECURITY + /* Add Security specific information. */ + if (q_omg_get_participant_security_info(pp, &(dst->participant_security_info))) { + dst->present |= PP_PARTICIPANT_SECURITY_INFO; + dst->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 Adlink-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 (mpayload, &ps, ~(uint64_t)0, 0); - ddsi_plist_addtomsg (mpayload, pp->plist, 0, qosdiff); - nn_xmsg_addpar_sentinel (mpayload); - ddsi_plist_fini (&ps); + assert (dst->qos.present == 0); + ddsi_plist_mergein_missing (dst, pp->plist, 0, qosdiff); +#ifdef DDSI_INCLUDE_SECURITY + if (q_omg_participant_is_secure(pp)) + ddsi_plist_mergein_missing (dst, pp->plist, PP_IDENTITY_TOKEN | PP_PERMISSIONS_TOKEN, 0); +#endif +} - ret = write_mpayload (wr, 1, PID_PARTICIPANT_GUID, mpayload); - nn_xmsg_free (mpayload); - return ret; +static int write_and_fini_plist (struct writer *wr, ddsi_plist_t *ps, bool alive) +{ + struct ddsi_serdata *serdata = ddsi_serdata_from_sample (wr->topic, alive ? SDK_DATA : SDK_KEY, ps); + ddsi_plist_fini (ps); + serdata->statusinfo = alive ? 0 : (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER); + serdata->timestamp = ddsrt_time_wallclock (); + return write_sample_nogc_notk (lookup_thread_state (), NULL, wr, serdata); +} + +int spdp_write (struct participant *pp) +{ + struct writer *wr; + ddsi_plist_t ps; + struct participant_builtin_topic_data_locators locs; + + 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; + } + + get_participant_builtin_topic_data (pp, &ps, &locs); + return write_and_fini_plist (wr, &ps, true); +} + +static int spdp_dispose_unregister_with_wr (struct participant *pp, unsigned entityid) +{ + ddsi_plist_t ps; + struct writer *wr; + + if ((wr = get_builtin_writer (pp, entityid)) == NULL) + { + ETRACE (pp, "spdp_dispose_unregister("PGUIDFMT") - builtin participant %s writer not found\n", + PGUID (pp->e.guid), + entityid == NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER ? "secure" : ""); + return 0; + } + + ddsi_plist_init_empty (&ps); + ps.present |= PP_PARTICIPANT_GUID; + ps.participant_guid = pp->e.guid; + return write_and_fini_plist (wr, &ps, false); } int spdp_dispose_unregister (struct participant *pp) { - struct nn_xmsg *mpayload; - ddsi_plist_t ps; - struct writer *wr; - int ret; - - if ((wr = get_builtin_writer (pp, NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER)) == NULL) + /* + * When disposing a participant, it should be announced on both the + * non-secure and secure writers. + * The receiver will decide from which writer it accepts the dispose. + */ + int ret = spdp_dispose_unregister_with_wr(pp, NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER); + if ((ret > 0) && q_omg_participant_is_secure(pp)) { - ETRACE (pp, "spdp_dispose_unregister("PGUIDFMT") - builtin participant writer not found\n", PGUID (pp->e.guid)); - return 0; + ret = spdp_dispose_unregister_with_wr(pp, NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER); } - - mpayload = nn_xmsg_new (pp->e.gv->xmsgpool, &pp->e.guid.prefix, 0, NN_XMSG_KIND_DATA); - ddsi_plist_init_empty (&ps); - ps.present |= PP_PARTICIPANT_GUID; - ps.participant_guid = pp->e.guid; - ddsi_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, ~(uint64_t)0); - nn_xmsg_addpar_sentinel (mpayload); - ddsi_plist_fini (&ps); - - ret = write_mpayload (wr, 0, PID_PARTICIPANT_GUID, mpayload); - nn_xmsg_free (mpayload); return ret; } @@ -416,7 +428,7 @@ static void respond_to_spdp (const struct ddsi_domaingv *gv, const ddsi_guid_t * entidx_enum_participant_fini (&est); } -static int handle_SPDP_dead (const struct receiver_state *rst, ddsrt_wctime_t timestamp, const ddsi_plist_t *datap, unsigned statusinfo) +static int handle_SPDP_dead (const struct receiver_state *rst, ddsi_entityid_t pwr_entityid, ddsrt_wctime_t timestamp, const ddsi_plist_t *datap, unsigned statusinfo) { struct ddsi_domaingv * const gv = rst->gv; ddsi_guid_t guid; @@ -428,13 +440,20 @@ static int handle_SPDP_dead (const struct receiver_state *rst, ddsrt_wctime_t ti guid = datap->participant_guid; GVLOGDISC (" %"PRIx32":%"PRIx32":%"PRIx32":%"PRIx32, PGUID (guid)); assert (guid.entityid.u == NN_ENTITYID_PARTICIPANT); - if (delete_proxy_participant_by_guid (gv, &guid, timestamp, 0) < 0) + if (is_proxy_participant_deletion_allowed(gv, &guid, pwr_entityid)) { - GVLOGDISC (" unknown"); + if (delete_proxy_participant_by_guid (gv, &guid, timestamp, 0) < 0) + { + GVLOGDISC (" unknown"); + } + else + { + GVLOGDISC (" delete"); + } } else { - GVLOGDISC (" delete"); + GVLOGDISC (" not allowed"); } } else @@ -619,7 +638,12 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, dds } } - GVLOGDISC ("SPDP ST0 "PGUIDFMT" bes %x NEW", PGUID (datap->participant_guid), builtin_endpoint_set); + const bool is_secure = ((datap->builtin_endpoint_set & NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_SECURE_ANNOUNCER) != 0 && + (datap->present & PP_IDENTITY_TOKEN)); + /* Make sure we don't create any security builtin endpoint when it's considered unsecure. */ + if (!is_secure) + builtin_endpoint_set &= NN_BES_MASK_NON_SECURITY; + GVLOGDISC ("SPDP ST0 "PGUIDFMT" bes %x%s NEW", PGUID (datap->participant_guid), builtin_endpoint_set, is_secure ? " (secure)" : ""); if (datap->present & PP_PARTICIPANT_LEASE_DURATION) { @@ -632,9 +656,6 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, dds } if (datap->present & PP_ADLINK_PARTICIPANT_VERSION_INFO) { - if (datap->adlink_participant_version_info.flags & NN_ADLINK_FL_KERNEL_SEQUENCE_NUMBER) - custom_flags |= CF_INC_KERNEL_SEQUENCE_NUMBERS; - if ((datap->adlink_participant_version_info.flags & NN_ADLINK_FL_DDSI2_PARTICIPANT_FLAG) && (datap->adlink_participant_version_info.flags & NN_ADLINK_FL_PARTICIPANT_IS_DDSI2)) custom_flags |= CF_PARTICIPANT_IS_DDSI2; @@ -743,28 +764,17 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, dds maybe_add_pp_as_meta_to_as_disc (gv, as_meta); - new_proxy_participant - ( - gv, - &datap->participant_guid, - builtin_endpoint_set, - &privileged_pp_guid, - as_default, - as_meta, - datap, - lease_duration, - rst->vendor, - custom_flags, - timestamp, - seq - ); - - /* Force transmission of SPDP messages - we're not very careful - in avoiding the processing of SPDP packets addressed to others - so filter here */ + if (!new_proxy_participant (gv, &datap->participant_guid, builtin_endpoint_set, &privileged_pp_guid, as_default, as_meta, datap, lease_duration, rst->vendor, custom_flags, timestamp, seq)) { - int have_dst = - (rst->dst_guid_prefix.u[0] != 0 || rst->dst_guid_prefix.u[1] != 0 || rst->dst_guid_prefix.u[2] != 0); + /* If no proxy participant was created, don't respond */ + return 0; + } + else + { + /* Force transmission of SPDP messages - we're not very careful + in avoiding the processing of SPDP packets addressed to others + so filter here */ + int have_dst = (rst->dst_guid_prefix.u[0] != 0 || rst->dst_guid_prefix.u[1] != 0 || rst->dst_guid_prefix.u[2] != 0); if (!have_dst) { GVLOGDISC ("broadcasted SPDP packet -> answering"); @@ -774,69 +784,46 @@ static int handle_SPDP_alive (const struct receiver_state *rst, seqno_t seq, dds { GVLOGDISC ("directed SPDP packet -> not responding\n"); } - } - if (custom_flags & CF_PARTICIPANT_IS_DDSI2) - { - /* If we just discovered DDSI2, make sure any existing - participants served by it are made dependent on it */ - make_participants_dependent_on_ddsi2 (gv, &datap->participant_guid, timestamp); - } - else if (privileged_pp_guid.prefix.u[0] || privileged_pp_guid.prefix.u[1] || privileged_pp_guid.prefix.u[2]) - { - /* If we just created a participant dependent on DDSI2, make sure - DDSI2 still exists. There is a risk of racing the lease expiry - of DDSI2. */ - if (entidx_lookup_proxy_participant_guid (gv->entity_index, &privileged_pp_guid) == NULL) + if (custom_flags & CF_PARTICIPANT_IS_DDSI2) { - GVLOGDISC ("make_participants_dependent_on_ddsi2: ddsi2 "PGUIDFMT" is no more, delete "PGUIDFMT"\n", - PGUID (privileged_pp_guid), PGUID (datap->participant_guid)); - delete_proxy_participant_by_guid (gv, &datap->participant_guid, timestamp, 1); + /* If we just discovered DDSI2, make sure any existing + participants served by it are made dependent on it */ + make_participants_dependent_on_ddsi2 (gv, &datap->participant_guid, timestamp); } + else if (privileged_pp_guid.prefix.u[0] || privileged_pp_guid.prefix.u[1] || privileged_pp_guid.prefix.u[2]) + { + /* If we just created a participant dependent on DDSI2, make sure + DDSI2 still exists. There is a risk of racing the lease expiry + of DDSI2. */ + if (entidx_lookup_proxy_participant_guid (gv->entity_index, &privileged_pp_guid) == NULL) + { + GVLOGDISC ("make_participants_dependent_on_ddsi2: ddsi2 "PGUIDFMT" is no more, delete "PGUIDFMT"\n", + PGUID (privileged_pp_guid), PGUID (datap->participant_guid)); + delete_proxy_participant_by_guid (gv, &datap->participant_guid, timestamp, 1); + } + } + return 1; } - return 1; } -static void handle_SPDP (const struct receiver_state *rst, seqno_t seq, ddsrt_wctime_t timestamp, unsigned statusinfo, const void *vdata, uint32_t len) +static void handle_SPDP (const struct receiver_state *rst, ddsi_entityid_t pwr_entityid, seqno_t seq, const struct ddsi_serdata *serdata) { struct ddsi_domaingv * const gv = rst->gv; - const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */ - if (data == NULL) + ddsi_plist_t decoded_data; + if (ddsi_serdata_to_sample (serdata, &decoded_data, NULL, NULL)) { - RSTTRACE ("SPDP ST%x no payload?\n", statusinfo); - return; - } - else - { - ddsi_plist_t decoded_data; - ddsi_plist_src_t src; int interesting = 0; - dds_return_t plist_ret; - src.protocol_version = rst->protocol_version; - src.vendorid = rst->vendor; - src.encoding = data->identifier; - src.buf = (unsigned char *) data + 4; - src.bufsz = len - 4; - src.strict = NN_STRICT_P (gv->config); - src.factory = gv->m_factory; - src.logconfig = &gv->logconfig; - if ((plist_ret = ddsi_plist_init_frommsg (&decoded_data, NULL, ~(uint64_t)0, ~(uint64_t)0, &src)) < 0) - { - if (plist_ret != DDS_RETCODE_UNSUPPORTED) - GVWARNING ("SPDP (vendor %u.%u): invalid qos/parameters\n", src.vendorid.id[0], src.vendorid.id[1]); - return; - } - - switch (statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER)) + switch (serdata->statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER)) { case 0: - interesting = handle_SPDP_alive (rst, seq, timestamp, &decoded_data); + interesting = handle_SPDP_alive (rst, seq, serdata->timestamp, &decoded_data); break; case NN_STATUSINFO_DISPOSE: case NN_STATUSINFO_UNREGISTER: case (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER): - interesting = handle_SPDP_dead (rst, timestamp, &decoded_data, statusinfo); + interesting = handle_SPDP_dead (rst, pwr_entityid, serdata->timestamp, &decoded_data, serdata->statusinfo); break; } @@ -892,14 +879,12 @@ static int sedp_write_endpoint ( struct writer *wr, int alive, const ddsi_guid_t *epguid, const struct entity_common *common, const struct endpoint_common *epcommon, - const dds_qos_t *xqos, struct addrset *as) + const dds_qos_t *xqos, struct addrset *as, nn_security_info_t *security) { struct ddsi_domaingv * const gv = wr->e.gv; const dds_qos_t *defqos = is_writer_entityid (epguid->entityid) ? &gv->default_xqos_wr : &gv->default_xqos_rd; - struct nn_xmsg *mpayload; uint64_t qosdiff; ddsi_plist_t ps; - int ret; ddsi_plist_init_empty (&ps); ps.present |= PP_ENDPOINT_GUID; @@ -912,6 +897,17 @@ static int sedp_write_endpoint ps.entity_name = common->name; } +#ifdef DDSI_INCLUDE_SECURITY + if (security) + { + ps.present |= PP_ENDPOINT_SECURITY_INFO; + memcpy(&ps.endpoint_security_info, security, sizeof(nn_security_info_t)); + } +#else + (void)security; + assert(security == NULL); +#endif + if (!alive) { assert (xqos == NULL); @@ -963,20 +959,9 @@ static int sedp_write_endpoint } } - /* The message is only a temporary thing, used only for encoding - 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.prefix, 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); - ddsi_plist_fini (&ps); - - GVLOGDISC ("sedp: write for "PGUIDFMT" via "PGUIDFMT"\n", PGUID (*epguid), PGUID (wr->e.guid)); - ret = write_mpayload (wr, alive, PID_ENDPOINT_GUID, mpayload); - nn_xmsg_free (mpayload); - return ret; + if (xqos) + ddsi_xqos_mergein_missing (&ps.qos, xqos, qosdiff); + return write_and_fini_plist (wr, &ps, alive); } static struct writer *get_sedp_writer (const struct participant *pp, unsigned entityid) @@ -991,13 +976,22 @@ int sedp_write_writer (struct writer *wr) { if ((!is_builtin_entityid(wr->e.guid.entityid, NN_VENDORID_ECLIPSE)) && (!wr->e.onlylocal)) { - struct writer *sedp_wr = get_sedp_writer (wr->c.pp, NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER); + unsigned entityid = determine_publication_writer(wr); + struct writer *sedp_wr = get_sedp_writer (wr->c.pp, entityid); + nn_security_info_t *security = NULL; #ifdef DDSI_INCLUDE_SSM struct addrset *as = wr->ssm_as; #else struct addrset *as = NULL; #endif - return sedp_write_endpoint (sedp_wr, 1, &wr->e.guid, &wr->e, &wr->c, wr->xqos, as); +#ifdef DDSI_INCLUDE_SECURITY + nn_security_info_t tmp; + if (q_omg_get_writer_security_info(wr, &tmp)) + { + security = &tmp; + } +#endif + return sedp_write_endpoint (sedp_wr, 1, &wr->e.guid, &wr->e, &wr->c, wr->xqos, as, security); } return 0; } @@ -1006,13 +1000,22 @@ int sedp_write_reader (struct reader *rd) { if ((!is_builtin_entityid (rd->e.guid.entityid, NN_VENDORID_ECLIPSE)) && (!rd->e.onlylocal)) { - struct writer *sedp_wr = get_sedp_writer (rd->c.pp, NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER); + unsigned entityid = determine_subscription_writer(rd); + struct writer *sedp_wr = get_sedp_writer (rd->c.pp, entityid); + nn_security_info_t *security = NULL; #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS struct addrset *as = rd->as; #else struct addrset *as = NULL; #endif - return sedp_write_endpoint (sedp_wr, 1, &rd->e.guid, &rd->e, &rd->c, rd->xqos, as); +#ifdef DDSI_INCLUDE_SECURITY + nn_security_info_t tmp; + if (q_omg_get_reader_security_info(rd, &tmp)) + { + security = &tmp; + } +#endif + return sedp_write_endpoint (sedp_wr, 1, &rd->e.guid, &rd->e, &rd->c, rd->xqos, as, security); } return 0; } @@ -1021,8 +1024,9 @@ int sedp_dispose_unregister_writer (struct writer *wr) { if ((!is_builtin_entityid(wr->e.guid.entityid, NN_VENDORID_ECLIPSE)) && (!wr->e.onlylocal)) { - struct writer *sedp_wr = get_sedp_writer (wr->c.pp, NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER); - return sedp_write_endpoint (sedp_wr, 0, &wr->e.guid, NULL, NULL, NULL, NULL); + unsigned entityid = determine_publication_writer(wr); + struct writer *sedp_wr = get_sedp_writer (wr->c.pp, entityid); + return sedp_write_endpoint (sedp_wr, 0, &wr->e.guid, NULL, NULL, NULL, NULL, NULL); } return 0; } @@ -1031,8 +1035,9 @@ int sedp_dispose_unregister_reader (struct reader *rd) { if ((!is_builtin_entityid(rd->e.guid.entityid, NN_VENDORID_ECLIPSE)) && (!rd->e.onlylocal)) { - struct writer *sedp_wr = get_sedp_writer (rd->c.pp, NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER); - return sedp_write_endpoint (sedp_wr, 0, &rd->e.guid, NULL, NULL, NULL, NULL); + unsigned entityid = determine_subscription_writer(rd); + struct writer *sedp_wr = get_sedp_writer (rd->c.pp, entityid); + return sedp_write_endpoint (sedp_wr, 0, &rd->e.guid, NULL, NULL, NULL, NULL, NULL); } return 0; } @@ -1086,7 +1091,7 @@ static struct proxy_participant *implicitly_create_proxypp (struct ddsi_domaingv doing anything about (1). That means we fall back to the legacy mode of locally generating GIDs but leaving the system id unchanged if the remote is OSPL. */ actual_vendorid = (datap->present & PP_VENDORID) ? datap->vendorid : vendorid; - new_proxy_participant(gv, ppguid, 0, &privguid, new_addrset(), new_addrset(), &pp_plist, DDS_INFINITY, actual_vendorid, CF_IMPLICITLY_CREATED_PROXYPP, timestamp, seq); + (void) new_proxy_participant(gv, ppguid, 0, &privguid, new_addrset(), new_addrset(), &pp_plist, DDS_INFINITY, actual_vendorid, CF_IMPLICITLY_CREATED_PROXYPP, timestamp, seq); } else if (ppguid->prefix.u[0] == src_guid_prefix->u[0] && vendor_is_eclipse_or_opensplice (vendorid)) { @@ -1146,9 +1151,7 @@ static void handle_SEDP_alive (const struct receiver_state *rst, seqno_t seq, dd #endif assert (datap); - - if (!(datap->present & PP_ENDPOINT_GUID)) - E (" no guid?\n", err); + assert (datap->present & PP_ENDPOINT_GUID); GVLOGDISC (" "PGUIDFMT, PGUID (datap->endpoint_guid)); ppguid.prefix = datap->endpoint_guid.prefix; @@ -1206,6 +1209,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); @@ -1328,11 +1337,7 @@ static void handle_SEDP_dead (const struct receiver_state *rst, ddsi_plist_t *da { struct ddsi_domaingv * const gv = rst->gv; int res; - if (!(datap->present & PP_ENDPOINT_GUID)) - { - GVLOGDISC (" no guid?\n"); - return; - } + assert (datap->present & PP_ENDPOINT_GUID); GVLOGDISC (" "PGUIDFMT, PGUID (datap->endpoint_guid)); if (is_writer_entityid (datap->endpoint_guid.entityid)) res = delete_proxy_writer (gv, &datap->endpoint_guid, timestamp, 0); @@ -1341,145 +1346,41 @@ static void handle_SEDP_dead (const struct receiver_state *rst, ddsi_plist_t *da GVLOGDISC (" %s\n", (res < 0) ? " unknown" : " delete"); } -static void handle_SEDP (const struct receiver_state *rst, seqno_t seq, ddsrt_wctime_t timestamp, unsigned statusinfo, const void *vdata, uint32_t len) +static void handle_SEDP (const struct receiver_state *rst, seqno_t seq, struct ddsi_serdata *serdata) { - struct ddsi_domaingv * const gv = rst->gv; - const struct CDRHeader *data = vdata; /* built-ins not deserialized (yet) */ - GVLOGDISC ("SEDP ST%x", statusinfo); - if (data == NULL) + ddsi_plist_t decoded_data; + if (ddsi_serdata_to_sample (serdata, &decoded_data, NULL, NULL)) { - GVLOGDISC (" no payload?\n"); - return; - } - else - { - ddsi_plist_t decoded_data; - ddsi_plist_src_t src; - dds_return_t plist_ret; - src.protocol_version = rst->protocol_version; - src.vendorid = rst->vendor; - src.encoding = data->identifier; - src.buf = (unsigned char *) data + 4; - src.bufsz = len - 4; - src.strict = NN_STRICT_P (gv->config); - src.factory = gv->m_factory; - src.logconfig = &gv->logconfig; - if ((plist_ret = ddsi_plist_init_frommsg (&decoded_data, NULL, ~(uint64_t)0, ~(uint64_t)0, &src)) < 0) - { - if (plist_ret != DDS_RETCODE_UNSUPPORTED) - GVWARNING ("SEDP (vendor %u.%u): invalid qos/parameters\n", src.vendorid.id[0], src.vendorid.id[1]); - return; - } - - switch (statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER)) + struct ddsi_domaingv * const gv = rst->gv; + GVLOGDISC ("SEDP ST%x", serdata->statusinfo); + switch (serdata->statusinfo & (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER)) { case 0: - handle_SEDP_alive (rst, seq, &decoded_data, &rst->src_guid_prefix, rst->vendor, timestamp); + handle_SEDP_alive (rst, seq, &decoded_data, &rst->src_guid_prefix, rst->vendor, serdata->timestamp); break; - case NN_STATUSINFO_DISPOSE: case NN_STATUSINFO_UNREGISTER: case (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER): - handle_SEDP_dead (rst, &decoded_data, timestamp); + handle_SEDP_dead (rst, &decoded_data, serdata->timestamp); break; } - ddsi_plist_fini (&decoded_data); } } /****************************************************************************** - *** - *** Topics - *** *****************************************************************************/ -int sedp_write_topic (struct participant *pp, const struct ddsi_plist *datap) -{ - struct writer *sedp_wr; - struct nn_xmsg *mpayload; - uint64_t delta; - int ret; - - assert (datap->qos.present & QP_TOPIC_NAME); - - if (pp->e.onlylocal) { - /* This topic is only locally available. */ - return 0; - } - - 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.prefix, 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; - ddsi_plist_addtomsg (mpayload, datap, ~(uint64_t)0, delta); - nn_xmsg_addpar_sentinel (mpayload); - - ETRACE (pp, "sedp: write topic %s via "PGUIDFMT"\n", datap->qos.topic_name, PGUID (sedp_wr->e.guid)); - ret = write_mpayload (sedp_wr, 1, PID_TOPIC_NAME, mpayload); - nn_xmsg_free (mpayload); - return ret; -} - - -/****************************************************************************** - *****************************************************************************/ - -/* FIXME: defragment is a copy of the one in q_receive.c, but the deserialised should be enhanced to handle fragmented data (and arguably the processing here should be built on proper data readers) */ -static int defragment (unsigned char **datap, const struct nn_rdata *fragchain, uint32_t sz) -{ - if (fragchain->nextfrag == NULL) - { - *datap = NN_RMSG_PAYLOADOFF (fragchain->rmsg, NN_RDATA_PAYLOAD_OFF (fragchain)); - return 0; - } - else - { - unsigned char *buf; - uint32_t off = 0; - buf = ddsrt_malloc (sz); - while (fragchain) - { - assert (fragchain->min <= off); - assert (fragchain->maxp1 <= sz); - if (fragchain->maxp1 > off) - { - /* only copy if this fragment adds data */ - const unsigned char *payload = NN_RMSG_PAYLOADOFF (fragchain->rmsg, NN_RDATA_PAYLOAD_OFF (fragchain)); - memcpy (buf + off, payload + off - fragchain->min, fragchain->maxp1 - off); - off = fragchain->maxp1; - } - fragchain = fragchain->nextfrag; - } - *datap = buf; - return 1; - } -} - int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const struct nn_rdata *fragchain, UNUSED_ARG (const ddsi_guid_t *rdguid), UNUSED_ARG (void *qarg)) { struct ddsi_domaingv * const gv = sampleinfo->rst->gv; struct proxy_writer *pwr; - struct { - struct CDRHeader cdr; - nn_parameter_t p_endpoint_guid; - char kh[16]; - nn_parameter_t p_sentinel; - } keyhash_payload; unsigned statusinfo; int need_keyhash; ddsi_guid_t srcguid; Data_DataFrag_common_t *msg; unsigned char data_smhdr_flags; ddsi_plist_t qos; - unsigned char *datap; - int needs_free; - uint32_t datasz = sampleinfo->size; - ddsrt_wctime_t timestamp; - - needs_free = defragment (&datap, fragchain, sampleinfo->size); /* Luckily, most of the Data and DataFrag headers are the same - and in particular, all that we care about here is the same. The @@ -1495,7 +1396,13 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str pwr = sampleinfo->pwr; if (pwr == NULL) - assert (srcguid.entityid.u == NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER); + { + /* NULL with NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER is normal. It is possible that + * NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER has NULL as well if there + * is a security mismatch being handled. */ + assert ((srcguid.entityid.u == NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER) || + (srcguid.entityid.u == NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER)); + } else { assert (is_builtin_entityid (pwr->e.guid.entityid, pwr->c.vendor)); @@ -1508,7 +1415,7 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str consequently expect to need the keyhash. Then, if sampleinfo says it is a complex qos, or the keyhash is required, extract all we need from the inline qos. */ - need_keyhash = (datasz == 0 || (data_smhdr_flags & (DATA_FLAG_KEYFLAG | DATA_FLAG_DATAFLAG)) == 0); + need_keyhash = (sampleinfo->size == 0 || (data_smhdr_flags & (DATA_FLAG_KEYFLAG | DATA_FLAG_DATAFLAG)) == 0); if (!(sampleinfo->complex_qos || need_keyhash)) { ddsi_plist_init_empty (&qos); @@ -1547,100 +1454,126 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str goto done_upd_deliv; } - /* Built-ins still do their own deserialization (SPDP <=> pwr == - NULL)). */ - if (statusinfo == 0) + /* proxy writers don't reference a topic object, SPDP doesn't have matched readers + but all the GUIDs are known, so be practical and map that */ + const struct ddsi_sertopic *topic; + switch (srcguid.entityid.u) { - if (datasz == 0 || !(data_smhdr_flags & DATA_FLAG_DATAFLAG)) - { - GVWARNING ("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": built-in data but no payload\n", - sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], - PGUID (srcguid), sampleinfo->seq); - goto done_upd_deliv; - } + case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER: + topic = gv->spdp_topic; + break; + case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER: + topic = gv->sedp_writer_topic; + break; + case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER: + topic = gv->sedp_reader_topic; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER: + topic = gv->pmd_topic; + break; +#ifdef DDSI_INCLUDE_SECURITY + case NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER: + topic = gv->spdp_secure_topic; + break; + case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER: + topic = gv->sedp_writer_secure_topic; + break; + case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER: + topic = gv->sedp_reader_secure_topic; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER: + topic = gv->pmd_secure_topic; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER: + topic = gv->pgm_stateless_topic; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER: + topic = gv->pgm_volatile_topic; + break; +#endif + default: + topic = NULL; + break; } - else if (datasz) + if (topic == NULL) { - /* Raw data must be full payload for write, just keys for - dispose and unregister. First has been checked; the second - hasn't been checked fully yet. */ - if (!(data_smhdr_flags & DATA_FLAG_KEYFLAG)) - { - GVWARNING ("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": dispose/unregister of built-in data but payload not just key\n", - sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], - PGUID (srcguid), sampleinfo->seq); - goto done_upd_deliv; - } + /* unrecognized source entity id => ignore */ + goto done_upd_deliv; } + + struct ddsi_serdata *d; + if (data_smhdr_flags & DATA_FLAG_DATAFLAG) + d = ddsi_serdata_from_ser (topic, SDK_DATA, fragchain, sampleinfo->size); + else if (data_smhdr_flags & DATA_FLAG_KEYFLAG) + d = ddsi_serdata_from_ser (topic, SDK_KEY, fragchain, sampleinfo->size); else if ((qos.present & PP_KEYHASH) && !NN_STRICT_P(gv->config)) - { - /* For SPDP/SEDP, fake a parameter list with just a keyhash. For - PMD, just use the keyhash directly. Too hard to fix everything - at the same time ... */ - if (srcguid.entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER) - { - datap = qos.keyhash.value; - datasz = sizeof (qos.keyhash); - } - else - { - nn_parameterid_t pid; - keyhash_payload.cdr.identifier = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? PL_CDR_LE : PL_CDR_BE); - keyhash_payload.cdr.options = 0; - switch (srcguid.entityid.u) - { - case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER: - pid = PID_PARTICIPANT_GUID; - break; - case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER: - pid = PID_ENDPOINT_GUID; - break; - case NN_ENTITYID_SEDP_BUILTIN_TOPIC_WRITER: - case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER: - /* placeholders */ - pid = PID_ENDPOINT_GUID; - break; - default: - GVLOGDISC ("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": mapping keyhash to ENDPOINT_GUID", - sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], - PGUID (srcguid), sampleinfo->seq); - pid = PID_ENDPOINT_GUID; - break; - } - keyhash_payload.p_endpoint_guid.parameterid = pid; - keyhash_payload.p_endpoint_guid.length = sizeof (nn_keyhash_t); - memcpy (keyhash_payload.kh, &qos.keyhash, sizeof (qos.keyhash)); - keyhash_payload.p_sentinel.parameterid = PID_SENTINEL; - keyhash_payload.p_sentinel.length = 0; - datap = (unsigned char *) &keyhash_payload; - datasz = sizeof (keyhash_payload); - } - } + d = ddsi_serdata_from_keyhash (topic, &qos.keyhash); else { - GVWARNING ("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": dispose/unregister with no content\n", + GVLOGDISC ("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": missing payload\n", sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], PGUID (srcguid), sampleinfo->seq); goto done_upd_deliv; } + if (d == NULL) + { + GVLOG (DDS_LC_DISCOVERY | DDS_LC_WARNING, "data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": deserialization failed\n", + sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], + PGUID (srcguid), sampleinfo->seq); + goto done_upd_deliv; + } + + d->timestamp = (sampleinfo->timestamp.v != DDSRT_WCTIME_INVALID.v) ? sampleinfo->timestamp : ddsrt_time_wallclock (); + d->statusinfo = statusinfo; + // set protocol version & vendor id for plist types + // FIXME: find a better way then fixing these up afterward + if (d->ops == &ddsi_serdata_ops_plist) + { + struct ddsi_serdata_plist *d_plist = (struct ddsi_serdata_plist *) d; + d_plist->protoversion = sampleinfo->rst->protocol_version; + d_plist->vendorid = sampleinfo->rst->vendor; + } + + if (gv->logconfig.c.mask & DDS_LC_TRACE) + { + ddsi_guid_t guid; + char tmp[2048]; + size_t res = 0; + tmp[0] = 0; + if (gv->logconfig.c.mask & DDS_LC_CONTENT) + res = ddsi_serdata_print (d, tmp, sizeof (tmp)); + if (pwr) guid = pwr->e.guid; else memset (&guid, 0, sizeof (guid)); + GVTRACE ("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": ST%x %s/%s:%s%s\n", + sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], + PGUID (guid), sampleinfo->seq, statusinfo, d->topic->name, d->topic->type_name, + tmp, res < sizeof (tmp) - 1 ? "" : "(trunc)"); + } - if (sampleinfo->timestamp.v != DDSRT_WCTIME_INVALID.v) - timestamp = sampleinfo->timestamp; - else - timestamp = ddsrt_time_wallclock (); switch (srcguid.entityid.u) { case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER: - handle_SPDP (sampleinfo->rst, sampleinfo->seq, timestamp, statusinfo, datap, datasz); + case NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER: + handle_SPDP (sampleinfo->rst, srcguid.entityid, sampleinfo->seq, d); break; case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER: case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER: - handle_SEDP (sampleinfo->rst, sampleinfo->seq, timestamp, statusinfo, datap, datasz); + case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER: + case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER: + handle_SEDP (sampleinfo->rst, sampleinfo->seq, d); break; case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER: - handle_pmd_message (sampleinfo->rst, timestamp, statusinfo, datap, datasz); + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER: { + handle_pmd_message (sampleinfo->rst, d); break; + } +#ifdef DDSI_INCLUDE_SECURITY + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER: + handle_auth_handshake_message(sampleinfo->rst, srcguid.entityid, d); + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER: + handle_crypto_exchange_message(sampleinfo->rst, d); + break; +#endif default: GVLOGDISC ("data(builtin, vendor %u.%u): "PGUIDFMT" #%"PRId64": not handled\n", sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], @@ -1648,9 +1581,9 @@ int builtins_dqueue_handler (const struct nn_rsample_info *sampleinfo, const str break; } + ddsi_serdata_unref (d); + done_upd_deliv: - if (needs_free) - ddsrt_free (datap); if (pwr) { /* No proxy writer for SPDP */ diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c index d2ecf93..2c3ca90 100644 --- a/src/core/ddsi/src/q_entity.c +++ b/src/core/ddsi/src/q_entity.c @@ -25,6 +25,7 @@ #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_misc.h" #include "dds/ddsi/q_log.h" +#include "dds/ddsi/q_bswap.h" #include "dds/ddsrt/avl.h" #include "dds/ddsi/ddsi_plist.h" #include "dds/ddsi/q_lease.h" @@ -48,6 +49,11 @@ #include "dds__whc.h" #include "dds/ddsi/ddsi_iid.h" #include "dds/ddsi/ddsi_tkmap.h" +#include "dds/ddsi/ddsi_security_omg.h" + +#ifdef DDSI_INCLUDE_SECURITY +#include "dds/ddsi/ddsi_security_msg.h" +#endif struct deleted_participant { ddsrt_avl_node_t avlnode; @@ -94,10 +100,17 @@ static const unsigned builtin_writers_besmask = NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER | NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER; + static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_cbarg); static dds_return_t new_reader_guid (struct reader **rd_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc *rhc, status_cb_t status_cb, void *status_cbarg); static struct participant *ref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity); static void unref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity); +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_handshake *handshake, struct participant *pp, struct proxy_participant *proxypp, enum ddsi_handshake_state result); +static void downgrade_to_nonsecure(struct proxy_participant *proxypp); +#endif static int gcreq_participant (struct participant *pp); static int gcreq_writer (struct writer *wr); @@ -190,6 +203,28 @@ int is_builtin_endpoint (ddsi_entityid_t id, nn_vendorid_t vendorid) return is_builtin_entityid (id, vendorid) && id.u != NN_ENTITYID_PARTICIPANT; } +#ifdef DDSI_INCLUDE_SECURITY +static int is_builtin_volatile_endpoint (ddsi_entityid_t id) +{ + switch (id.u) { + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER: + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER: + return 1; + default: + break; + } + return 0; +} +#else +#ifndef NDEBUG +static int is_builtin_volatile_endpoint (ddsi_entityid_t id) +{ + DDSRT_UNUSED_ARG(id); + return 0; +} +#endif +#endif + bool is_local_orphan_endpoint (const struct entity_common *e) { return (e->guid.prefix.u[0] == 0 && e->guid.prefix.u[1] == 0 && e->guid.prefix.u[2] == 0 && @@ -507,6 +542,184 @@ static void pp_release_entityid(struct participant *pp, ddsi_entityid_t id) ddsrt_mutex_unlock (&pp->e.lock); } +static void force_as_disc_address(struct ddsi_domaingv *gv, const ddsi_guid_t *subguid) +{ + struct writer *wr = entidx_lookup_writer_guid (gv->entity_index, subguid); + assert (wr != NULL); + ddsrt_mutex_lock (&wr->e.lock); + unref_addrset (wr->as); + unref_addrset (wr->as_group); + wr->as = ref_addrset (gv->as_disc); + wr->as_group = ref_addrset (gv->as_disc_group); + ddsrt_mutex_unlock (&wr->e.lock); +} + +#ifdef DDSI_INCLUDE_SECURITY +static void add_security_builtin_endpoints(struct participant *pp, ddsi_guid_t *subguid, const ddsi_guid_t *group_guid, struct ddsi_domaingv *gv, bool add_writers, bool add_readers) +{ + if (add_writers) + { + struct whc_writer_info *wrinfo; + + subguid->entityid = to_entityid (NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER); + wrinfo = whc_make_wrinfo (NULL, &gv->builtin_endpoint_xqos_wr); + new_writer_guid (NULL, subguid, group_guid, pp, gv->spdp_secure_topic, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + whc_free_wrinfo (wrinfo); + /* But we need the as_disc address set for SPDP, because we need to + send it to everyone regardless of the existence of readers. */ + force_as_disc_address(gv, subguid); + pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_SECURE_ANNOUNCER; + + subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER); + wrinfo = whc_make_wrinfo (NULL, &gv->builtin_stateless_xqos_wr); + new_writer_guid (NULL, subguid, group_guid, pp, gv->pgm_stateless_topic, &gv->builtin_stateless_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + whc_free_wrinfo (wrinfo); + pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_STATELESS_MESSAGE_ANNOUNCER; + + subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER); + wrinfo = whc_make_wrinfo (NULL, &gv->builtin_volatile_xqos_wr); + new_writer_guid (NULL, subguid, group_guid, pp, gv->pgm_volatile_topic, &gv->builtin_volatile_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + whc_free_wrinfo (wrinfo); + pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_VOLATILE_SECURE_ANNOUNCER; + + wrinfo = whc_make_wrinfo (NULL, &gv->builtin_endpoint_xqos_wr); + + subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER); + new_writer_guid (NULL, subguid, group_guid, pp, gv->pmd_secure_topic, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_SECURE_ANNOUNCER; + + subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER); + new_writer_guid (NULL, subguid, group_guid, pp, gv->sedp_writer_secure_topic, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + pp->bes |= NN_BUILTIN_ENDPOINT_PUBLICATION_MESSAGE_SECURE_ANNOUNCER; + + subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER); + new_writer_guid (NULL, subguid, group_guid, pp, gv->sedp_reader_secure_topic, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + pp->bes |= NN_BUILTIN_ENDPOINT_SUBSCRIPTION_MESSAGE_SECURE_ANNOUNCER; + + whc_free_wrinfo (wrinfo); + } + + if (add_readers) + { + subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER); + new_reader_guid (NULL, subguid, group_guid, pp, gv->sedp_reader_secure_topic, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); + pp->bes |= NN_BUILTIN_ENDPOINT_SUBSCRIPTION_MESSAGE_SECURE_DETECTOR; + + subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_READER); + new_reader_guid (NULL, subguid, group_guid, pp, gv->sedp_writer_secure_topic, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); + pp->bes |= NN_BUILTIN_ENDPOINT_PUBLICATION_MESSAGE_SECURE_DETECTOR; + } + + /* + * When security is enabled configure the associated necessary builtin readers independent of the + * besmode flag setting, because all participant do require authentication. + */ + subguid->entityid = to_entityid (NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_READER); + new_reader_guid (NULL, subguid, group_guid, pp, gv->spdp_secure_topic, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); + pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_SECURE_DETECTOR; + + subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER); + new_reader_guid (NULL, subguid, group_guid, pp, gv->pgm_volatile_topic, &gv->builtin_volatile_xqos_rd, NULL, NULL, NULL); + pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_VOLATILE_SECURE_DETECTOR; + + subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER); + new_reader_guid (NULL, subguid, group_guid, pp, gv->pgm_stateless_topic, &gv->builtin_stateless_xqos_rd, NULL, NULL, NULL); + pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_STATELESS_MESSAGE_DETECTOR; + + subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER); + new_reader_guid (NULL, subguid, group_guid, pp, gv->pmd_secure_topic, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); + pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_SECURE_DETECTOR; +} +#endif + +static void add_builtin_endpoints(struct participant *pp, ddsi_guid_t *subguid, const ddsi_guid_t *group_guid, struct ddsi_domaingv *gv, bool add_writers, bool add_readers) +{ + if (add_writers) + { + struct whc_writer_info *wrinfo = whc_make_wrinfo (NULL, &gv->builtin_endpoint_xqos_wr); + + /* SEDP writers: */ + subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER); + new_writer_guid (NULL, subguid, group_guid, pp, gv->sedp_reader_topic, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + pp->bes |= NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER; + + subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER); + new_writer_guid (NULL, subguid, group_guid, pp, gv->sedp_writer_topic, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER; + + /* PMD writer: */ + subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER); + new_writer_guid (NULL, subguid, group_guid, pp, gv->pmd_topic, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER; + + whc_free_wrinfo (wrinfo); + } + + /* SPDP, SEDP, PMD readers: */ + if (add_readers) + { + subguid->entityid = to_entityid (NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER); + new_reader_guid (NULL, subguid, group_guid, pp, gv->spdp_topic, &gv->spdp_endpoint_xqos, NULL, NULL, NULL); + pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_DETECTOR; + + subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_READER); + new_reader_guid (NULL, subguid, group_guid, pp, gv->sedp_reader_topic, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); + pp->bes |= NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_DETECTOR; + + subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER); + new_reader_guid (NULL, subguid, group_guid, pp, gv->sedp_writer_topic, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); + pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_DETECTOR; + + subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER); + new_reader_guid (NULL, subguid, group_guid, pp, gv->pmd_topic, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); + pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER; + } + +#ifdef DDSI_INCLUDE_SECURITY + if (q_omg_participant_is_secure (pp)) + add_security_builtin_endpoints (pp, subguid, group_guid, gv, add_writers, add_readers); +#endif +} + +#ifdef DDSI_INCLUDE_SECURITY +static void connect_participant_secure(struct ddsi_domaingv *gv, struct participant *pp) +{ + struct proxy_participant *proxypp; + struct entidx_enum_proxy_participant it; + + 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_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); + } +} + +static void disconnect_participant_secure(struct participant *pp) +{ + struct proxy_participant *proxypp; + struct entidx_enum_proxy_participant it; + struct ddsi_domaingv * const gv = pp->e.gv; + + if (q_omg_participant_is_secure(pp)) + { + entidx_enum_proxy_participant_init (&it, gv->entity_index); + while ((proxypp = entidx_enum_proxy_participant_next (&it)) != NULL) + { + ddsi_handshake_remove(pp, proxypp); + } + entidx_enum_proxy_participant_fini (&it); + } +} +#endif + static void gc_participant_lease (struct gcreq *gcreq) { lease_free (gcreq->arg); @@ -537,7 +750,7 @@ static void participant_add_wr_lease_locked (struct participant * pp, const stru minl_prev = ddsrt_fibheap_min (&lease_fhdef_pp, &pp->leaseheap_man); ddsrt_fibheap_insert (&lease_fhdef_pp, &pp->leaseheap_man, wr->lease); minl_new = ddsrt_fibheap_min (&lease_fhdef_pp, &pp->leaseheap_man); - /* if inserted lease is new shortest lease */ + /* ensure pp->minl_man is equivalent to min(leaseheap_man) */ if (minl_prev != minl_new) { ddsrt_etime_t texp = ddsrt_etime_add_duration (ddsrt_time_elapsed (), minl_new->tdur); @@ -557,21 +770,23 @@ static void participant_add_wr_lease_locked (struct participant * pp, const stru static void participant_remove_wr_lease_locked (struct participant * pp, struct writer * wr) { - struct lease *minl; + struct lease *minl_prev; + struct lease *minl_new; assert (wr->lease != NULL); assert (wr->xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT); - minl = ddsrt_fibheap_min (&lease_fhdef_pp, &pp->leaseheap_man); + minl_prev = ddsrt_fibheap_min (&lease_fhdef_pp, &pp->leaseheap_man); ddsrt_fibheap_delete (&lease_fhdef_pp, &pp->leaseheap_man, wr->lease); - /* if writer with min lease is removed: update participant lease to use new minimal duration */ - if (wr->lease == minl) + minl_new = ddsrt_fibheap_min (&lease_fhdef_pp, &pp->leaseheap_man); + /* ensure pp->minl_man is equivalent to min(leaseheap_man) */ + if (minl_prev != minl_new) { - if ((minl = ddsrt_fibheap_min (&lease_fhdef_pp, &pp->leaseheap_man)) != NULL) + if (minl_new != NULL) { - dds_duration_t trem = minl->tdur - wr->lease->tdur; + dds_duration_t trem = minl_new->tdur - minl_prev->tdur; assert (trem >= 0); ddsrt_etime_t texp = ddsrt_etime_add_duration (ddsrt_time_elapsed(), trem); - struct lease *lnew = lease_new (texp, minl->tdur, minl->entity); + struct lease *lnew = lease_new (texp, minl_new->tdur, minl_new->entity); participant_replace_minl (pp, lnew); lease_register (lnew); } @@ -582,11 +797,87 @@ 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) +#ifdef DDSI_INCLUDE_SECURITY +static dds_return_t check_and_load_security_config (struct ddsi_domaingv * const gv, const ddsi_guid_t *ppguid, dds_qos_t *qos) +{ + /* If some security properties (name starts with dds.sec. conform DDS Security spec 7.2.4.1) + are present in the QoS, all must be and they will be used. If none are, take the settings + from the configuration if it has them. When no security configuration exists anywhere, + create an unsecured participant. + + This may modify "qos" */ + if (ddsi_xqos_has_prop_prefix (qos, "dds.sec.")) + { + char const * const req[] = { + DDS_SEC_PROP_AUTH_IDENTITY_CA, + DDS_SEC_PROP_AUTH_PRIV_KEY, + DDS_SEC_PROP_AUTH_IDENTITY_CERT, + DDS_SEC_PROP_ACCESS_PERMISSIONS_CA, + DDS_SEC_PROP_ACCESS_GOVERNANCE, + DDS_SEC_PROP_ACCESS_PERMISSIONS, + + DDS_SEC_PROP_AUTH_LIBRARY_PATH, + DDS_SEC_PROP_AUTH_LIBRARY_INIT, + DDS_SEC_PROP_AUTH_LIBRARY_FINALIZE, + DDS_SEC_PROP_CRYPTO_LIBRARY_PATH, + DDS_SEC_PROP_CRYPTO_LIBRARY_INIT, + DDS_SEC_PROP_CRYPTO_LIBRARY_FINALIZE, + DDS_SEC_PROP_ACCESS_LIBRARY_PATH, + DDS_SEC_PROP_ACCESS_LIBRARY_INIT, + DDS_SEC_PROP_ACCESS_LIBRARY_FINALIZE + }; + GVLOGDISC ("new_participant("PGUIDFMT"): using security settings from QoS\n", PGUID (*ppguid)); + + /* check if all required security properties exist in qos; report all missing ones, not just the first */ + dds_return_t ret = DDS_RETCODE_OK; + for (size_t i = 0; i < sizeof(req) / sizeof(req[0]); i++) + { + const char *value; + if (!ddsi_xqos_find_prop (qos, req[i], &value) || strlen (value) == 0) + { + GVERROR ("new_participant("PGUIDFMT"): required security property %s missing in Property QoS\n", PGUID (*ppguid), req[i]); + ret = DDS_RETCODE_PRECONDITION_NOT_MET; + } + } + if (ret != DDS_RETCODE_OK) + return ret; + } + else if (gv->config.omg_security_configuration) + { + /* For security, configuration can be provided through the configuration. However, the specification + (and the plugins) expect it to be in the QoS, so merge it in. */ + GVLOGDISC ("new_participant("PGUIDFMT"): using security settings from configuration\n", PGUID (*ppguid)); + ddsi_xqos_mergein_security_config (qos, &gv->config.omg_security_configuration->cfg); + } + else + { + /* No security configuration */ + return DDS_RETCODE_OK; + } + + if (q_omg_is_security_loaded (gv->security_context)) + { + GVLOGDISC ("new_participant("PGUIDFMT"): security is already loaded for this domain\n", PGUID (*ppguid)); + return DDS_RETCODE_OK; + } + else if (q_omg_security_load (gv->security_context, qos, gv) < 0) + { + GVERROR ("Could not load security\n"); + return DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; + } + else + { + return DDS_RETCODE_OK; + } +} +#endif + +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; struct whc_writer_info *wrinfo; + dds_return_t ret = DDS_RETCODE_OK; ddsi_tran_conn_t ppconn; /* no reserved bits may be set */ @@ -636,7 +927,8 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct ddsi_domain GVERROR ("new_participant("PGUIDFMT", %x) failed: max participants reached\n", PGUID (*ppguid), flags); if (ppconn) ddsi_conn_free (ppconn); - return DDS_RETCODE_OUT_OF_RESOURCES; + ret = DDS_RETCODE_OUT_OF_RESOURCES; + goto new_pp_err; } } @@ -657,6 +949,23 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct ddsi_domain ddsi_plist_copy (pp->plist, plist); 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 ((ret = check_and_load_security_config (gv, ppguid, &pp->plist->qos)) != DDS_RETCODE_OK) + goto not_allowed; + if ((ret = q_omg_security_check_create_participant (pp, gv->config.domainId)) != DDS_RETCODE_OK) + goto not_allowed; + *ppguid = pp->e.guid; +#else + if (ddsi_xqos_has_prop_prefix (&pp->plist->qos, "dds.sec.")) + { + /* disallow creating a participant with a security configuration if there is support for security + has been left out */ + ret = DDS_RETCODE_PRECONDITION_NOT_MET; + goto not_allowed; + } +#endif + if (gv->logconfig.c.mask & DDS_LC_DISCOVERY) { GVLOGDISC ("PARTICIPANT "PGUIDFMT" QOS={", PGUID (pp->e.guid)); @@ -682,83 +991,24 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct ddsi_domain subguid.prefix = pp->e.guid.prefix; memset (&group_guid, 0, sizeof (group_guid)); - /* SPDP writer */ - /* Note: skip SEDP <=> skip SPDP because of the way ddsi_discovery.c does things - currently. */ + /* SPDP is very much special and must be done first */ if (!(flags & RTPS_PF_NO_BUILTIN_WRITERS)) { subguid.entityid = to_entityid (NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER); wrinfo = whc_make_wrinfo (NULL, &gv->spdp_endpoint_xqos); - new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->spdp_endpoint_xqos, whc_new(gv, wrinfo), NULL, NULL); + new_writer_guid (NULL, &subguid, &group_guid, pp, gv->spdp_topic, &gv->spdp_endpoint_xqos, whc_new(gv, wrinfo), NULL, NULL); whc_free_wrinfo (wrinfo); /* But we need the as_disc address set for SPDP, because we need to send it to everyone regardless of the existence of readers. */ - { - struct writer *wr = entidx_lookup_writer_guid (gv->entity_index, &subguid); - assert (wr != NULL); - ddsrt_mutex_lock (&wr->e.lock); - unref_addrset (wr->as); - unref_addrset (wr->as_group); - wr->as = ref_addrset (gv->as_disc); - wr->as_group = ref_addrset (gv->as_disc_group); - ddsrt_mutex_unlock (&wr->e.lock); - } + force_as_disc_address (gv, &subguid); pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_ANNOUNCER; } /* Make it globally visible, else the endpoint matching won't work. */ entidx_insert_participant_guid (gv->entity_index, pp); - /* SEDP writers: */ - wrinfo = whc_make_wrinfo (NULL, &gv->builtin_endpoint_xqos_wr); - if (!(flags & RTPS_PF_NO_BUILTIN_WRITERS)) - { - subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER); - new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); - pp->bes |= NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER; - - subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER); - new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); - pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER; - } - - if (gv->config.do_topic_discovery) - { - /* TODO: make this one configurable, we don't want all participants to publish all topics (or even just those that they use themselves) */ - subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_TOPIC_WRITER); - new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); - pp->bes |= NN_DISC_BUILTIN_ENDPOINT_TOPIC_ANNOUNCER; - } - - /* PMD writer: */ - if (!(flags & RTPS_PF_NO_BUILTIN_WRITERS)) - { - subguid.entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER); - new_writer_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); - pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER; - } - - whc_free_wrinfo (wrinfo); - - /* SPDP, SEDP, PMD readers: */ - if (!(flags & RTPS_PF_NO_BUILTIN_READERS)) - { - subguid.entityid = to_entityid (NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER); - new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->spdp_endpoint_xqos, NULL, NULL, NULL); - pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_DETECTOR; - - subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_READER); - new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); - pp->bes |= NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_DETECTOR; - - subguid.entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER); - new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); - pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_DETECTOR; - - subguid.entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER); - new_reader_guid (NULL, &subguid, &group_guid, pp, NULL, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); - pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER; - } + /* add all built-in endpoints other than the SPDP writer */ + add_builtin_endpoints (pp, &subguid, &group_guid, gv, !(flags & RTPS_PF_NO_BUILTIN_WRITERS), !(flags & RTPS_PF_NO_BUILTIN_READERS)); /* If the participant doesn't have the full set of builtin writers it depends on the privileged participant, which must exist, hence @@ -766,7 +1016,8 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct ddsi_domain If it is the privileged participant, set the global variable pointing to it. Except when the participant is only locally available. */ - if (!(flags & RTPS_PF_ONLY_LOCAL)) { + if (!(flags & RTPS_PF_ONLY_LOCAL)) + { ddsrt_mutex_lock (&gv->privileged_pp_lock); if ((pp->bes & builtin_writers_besmask) != builtin_writers_besmask) { @@ -821,7 +1072,29 @@ dds_return_t new_participant_guid (const ddsi_guid_t *ppguid, struct ddsi_domain tsched = (pp->lease_duration == DDS_INFINITY) ? DDSRT_MTIME_NEVER : (ddsrt_mtime_t){0}; pp->pmd_update_xevent = qxev_pmd_update (gv->xevents, tsched, &pp->e.guid); } - return 0; + +#ifdef DDSI_INCLUDE_SECURITY + if (q_omg_participant_is_secure (pp)) + { + connect_participant_secure (gv, pp); + } +#endif + return ret; + +not_allowed: + if (ppconn) + ddsi_conn_free (ppconn); + ddsi_plist_fini (pp->plist); + ddsrt_free (pp->plist); + inverse_uint32_set_fini (&pp->avail_entityids.x); + ddsrt_mutex_destroy (&pp->refc_lock); + entity_common_fini (&pp->e); + ddsrt_free (pp); + ddsrt_mutex_lock (&gv->participant_set_lock); + gv->nparticipants--; + ddsrt_mutex_unlock (&gv->participant_set_lock); +new_pp_err: + return ret; } dds_return_t new_participant (ddsi_guid_t *p_ppguid, struct ddsi_domaingv *gv, unsigned flags, const ddsi_plist_t *plist) @@ -889,6 +1162,19 @@ static void unref_participant (struct participant *pp, const struct ddsi_guid *g NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER, NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_READER, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER, + /* Security ones: */ + NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER, + NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_READER, + NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER, + NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER, + NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER, + NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER, + NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER, + NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER, + NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER, + NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_READER, + NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER, + NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER, }; ddsi_guid_t stguid; @@ -961,7 +1247,7 @@ static void unref_participant (struct participant *pp, const struct ddsi_guid *g if ((pp->bes & builtin_writers_besmask) != builtin_writers_besmask) { /* Participant doesn't have a full complement of built-in - writers, therefore, it relies on gv.privileged_pp, and + writers, therefore, it relies on gv->privileged_pp, and therefore we must decrement the reference count of that one. Why read it with the lock held, only to release it and use it @@ -995,6 +1281,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); @@ -1021,11 +1310,19 @@ dds_return_t delete_participant (struct ddsi_domaingv *gv, const struct ddsi_gui { struct participant *pp; GVLOGDISC ("delete_participant("PGUIDFMT")\n", PGUID (*ppguid)); + ddsrt_mutex_lock (&gv->lock); if ((pp = entidx_lookup_participant_guid (gv->entity_index, ppguid)) == NULL) + { + ddsrt_mutex_unlock (&gv->lock); return DDS_RETCODE_BAD_PARAMETER; + } builtintopic_write (gv->builtin_topic_interface, &pp->e, ddsrt_time_wallclock(), false); remember_deleted_participant_guid (gv->deleted_participants, &pp->e.guid); +#ifdef DDSI_INCLUDE_SECURITY + disconnect_participant_secure (pp); +#endif entidx_remove_participant_guid (gv->entity_index, pp); + ddsrt_mutex_unlock (&gv->lock); gcreq_participant (pp); return 0; } @@ -1050,15 +1347,33 @@ struct writer *get_builtin_writer (const struct participant *pp, unsigned entity case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER: bes_mask = NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER; break; + case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER: + bes_mask = NN_BUILTIN_ENDPOINT_SUBSCRIPTION_MESSAGE_SECURE_ANNOUNCER; + break; case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER: bes_mask = NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER; break; + case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER: + bes_mask = NN_BUILTIN_ENDPOINT_PUBLICATION_MESSAGE_SECURE_ANNOUNCER; + break; case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER: bes_mask = NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER; break; case NN_ENTITYID_SEDP_BUILTIN_TOPIC_WRITER: bes_mask = NN_DISC_BUILTIN_ENDPOINT_TOPIC_ANNOUNCER; break; + case NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER: + bes_mask = NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_SECURE_ANNOUNCER; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER: + bes_mask = NN_BUILTIN_ENDPOINT_PARTICIPANT_STATELESS_MESSAGE_ANNOUNCER; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER: + bes_mask = NN_BUILTIN_ENDPOINT_PARTICIPANT_VOLATILE_SECURE_ANNOUNCER; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER: + bes_mask = NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_SECURE_ANNOUNCER; + break; default: DDS_FATAL ("get_builtin_writer called with entityid %x\n", entityid); return NULL; @@ -1437,7 +1752,7 @@ void rebuild_or_clear_writer_addrsets (struct ddsi_domaingv *gv, int rebuild) else { /* SPDP writers have no matched readers, instead they all use the same address space, - gv.as_disc. Keep as_disc unchanged, and instead make the participants point to the + gv->as_disc. Keep as_disc unchanged, and instead make the participants point to the empty one. */ unref_addrset(wr->as); if (rebuild) @@ -1452,19 +1767,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)) { @@ -1473,7 +1799,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); @@ -1546,8 +1873,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) { @@ -1558,7 +1887,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); } } @@ -1698,7 +2027,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) { @@ -1722,7 +2055,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); } } @@ -1812,9 +2145,11 @@ static void proxy_writer_drop_connection (const struct ddsi_guid *pwr_guid, stru local_reader_ary_remove (&pwr->rdary, rd); } ddsrt_mutex_unlock (&pwr->e.lock); - if (m != NULL) + if (m) { update_reader_init_acknack_count (&rd->e.gv->logconfig, rd->e.gv->entity_index, &rd->e.guid, m->count); + if (m->filtered) + nn_defrag_prune(pwr->defrag, &m->rd_guid.prefix, m->last_seq); } free_pwr_rd_match (m); } @@ -1837,7 +2172,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; @@ -1849,6 +2184,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) @@ -1879,6 +2219,7 @@ static void writer_add_connection (struct writer *wr, struct proxy_reader *prd) m->seq = MAX_SEQ_NUMBER; else m->seq = wr->seq; + m->last_seq = m->seq; if (ddsrt_avl_lookup_ipath (&wr_readers_treedef, &wr->readers, &prd->e.guid, &path)) { ELOGDISC (wr, " writer_add_connection(wr "PGUIDFMT" prd "PGUIDFMT") - already connected\n", @@ -1893,6 +2234,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); @@ -1989,7 +2331,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; @@ -1997,6 +2339,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); @@ -2021,7 +2368,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 @@ -2104,7 +2453,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, ddsrt_mtime_t tnow, nn_count_t init_count) +static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader *rd, ddsrt_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; @@ -2139,11 +2488,19 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader m->t_heartbeat_accepted.v = 0; m->t_last_nack.v = 0; m->seq_last_nack = 0; + 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 */ - if (is_builtin_entityid (rd->e.guid.entityid, NN_VENDORID_ECLIPSE) && !ddsrt_avl_is_empty (&pwr->readers)) + if (is_builtin_entityid (rd->e.guid.entityid, NN_VENDORID_ECLIPSE) && !ddsrt_avl_is_empty (&pwr->readers) && !pwr->filtered) { /* builtins really don't care about multiple copies or anything */ m->in_sync = PRMSS_SYNC; @@ -2198,9 +2555,16 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader hopefully it won't make that much of a difference in practice.) */ if (rd->reliable) { + uint32_t secondary_reorder_maxsamples = pwr->e.gv->config.secondary_reorder_maxsamples; + + if (rd->e.guid.entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER) + { + secondary_reorder_maxsamples = pwr->e.gv->config.primary_reorder_maxsamples; + m->filtered = 1; + } m->acknack_xevent = qxev_acknack (pwr->evq, ddsrt_mtime_add_duration (tnow, pwr->e.gv->config.preemptive_ack_delay), &pwr->e.guid, &rd->e.guid); m->u.not_in_sync.reorder = - nn_reorder_new (&pwr->e.gv->logconfig, NN_REORDER_MODE_NORMAL, pwr->e.gv->config.secondary_reorder_maxsamples, pwr->e.gv->config.late_ack_mode); + nn_reorder_new (&pwr->e.gv->logconfig, NN_REORDER_MODE_NORMAL, secondary_reorder_maxsamples, pwr->e.gv->config.late_ack_mode); pwr->n_reliable_readers++; } else @@ -2213,7 +2577,7 @@ static void proxy_writer_add_connection (struct proxy_writer *pwr, struct reader ddsrt_avl_insert_ipath (&pwr_readers_treedef, &pwr->readers, m, &path); local_reader_ary_insert(&pwr->rdary, rd); ddsrt_mutex_unlock (&pwr->e.lock); - qxev_pwr_entityid (pwr, &rd->e.guid.prefix); + qxev_pwr_entityid (pwr, &rd->e.guid); ELOGDISC (pwr, "\n"); return; @@ -2226,12 +2590,18 @@ already_matched: return; } -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)) { @@ -2242,12 +2612,12 @@ static void proxy_reader_add_connection (struct proxy_reader *prd, struct writer } else { - assert (wr->topic || is_builtin_endpoint (wr->e.guid.entityid, NN_VENDORID_ECLIPSE)); ELOGDISC (prd, " proxy_reader_add_connection(wr "PGUIDFMT" prd "PGUIDFMT")\n", PGUID (wr->e.guid), PGUID (prd->e.guid)); ddsrt_avl_insert_ipath (&prd_writers_treedef, &prd->writers, m, &path); ddsrt_mutex_unlock (&prd->e.lock); - qxev_prd_entityid (prd, &wr->e.guid.prefix); + qxev_prd_entityid (prd, &wr->e.guid); + } } @@ -2292,6 +2662,44 @@ static ddsi_entityid_t builtin_entityid_match (ddsi_entityid_t x) res.u = NN_ENTITYID_UNKNOWN; break; + case NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER: + res.u = NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_READER; + break; + case NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_READER: + res.u = NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER; + break; + + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER: + res.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER: + res.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER: + res.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER: + res.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER: + res.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER; + break; + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER: + res.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER; + break; + case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER: + res.u = NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_READER; + break; + case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_READER: + res.u = NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER; + break; + case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER: + res.u = NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER; + break; + case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER: + res.u = NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER; + break; + default: assert (0); } @@ -2343,11 +2751,40 @@ 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, ddsrt_mtime_t tnow, int64_t crypto_handle) +{ + DDSRT_UNUSED_ARG(tnow); + 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, ddsrt_mtime_t tnow, int64_t crypto_handle) +{ + nn_count_t init_count; + struct alive_state alive_state; + + /* Initialize the reader's tracking information for the writer liveliness state to something + 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, 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. */ + proxy_writer_get_alive_state (pwr, &alive_state); + reader_update_notify_pwr_alive_state (rd, pwr, &alive_state); +} + static void connect_writer_with_proxy_reader (struct writer *wr, struct proxy_reader *prd, ddsrt_mtime_t tnow) { + struct ddsi_domaingv *gv = wr->e.gv; 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; + bool relay_only; + DDSRT_UNUSED_ARG(tnow); if (isb0 != isb1) return; @@ -2358,8 +2795,24 @@ static void connect_writer_with_proxy_reader (struct writer *wr, struct proxy_re writer_qos_mismatch (wr, reason); return; } - proxy_reader_add_connection (prd, wr); - writer_add_connection (wr, prd); + + if (!q_omg_security_check_remote_reader_permissions (prd, wr->e.gv->config.domainId, wr->c.pp, &relay_only)) + { + GVLOGDISC ("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 (relay_only) + { + GVWARNING ("connect_writer_with_proxy_reader (wr "PGUIDFMT") with (prd "PGUIDFMT") relay_only not supported\n", PGUID (wr->e.guid), PGUID (prd->e.guid)); + } + else if (!q_omg_security_match_remote_reader_enabled (wr, prd, relay_only, &crypto_handle)) + { + GVLOGDISC ("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, crypto_handle); + writer_add_connection (wr, prd, crypto_handle); + } } static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct reader *rd, ddsrt_mtime_t tnow) @@ -2369,6 +2822,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) @@ -2379,17 +2834,30 @@ static void connect_proxy_writer_with_reader (struct proxy_writer *pwr, struct r return; } - /* Initialze the reader's tracking information for the writer liveliness state to something - 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); + if (!q_omg_security_check_remote_writer_permissions(pwr, rd->e.gv->config.domainId, rd->c.pp)) + { + 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, &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)); + } + else + { + /* Initialize the reader's tracking information for the writer liveliness state to something + 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, 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. */ - proxy_writer_get_alive_state (pwr, &alive_state); - reader_update_notify_pwr_alive_state (rd, pwr, &alive_state); + /* 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. */ + proxy_writer_get_alive_state (pwr, &alive_state); + reader_update_notify_pwr_alive_state (rd, pwr, &alive_state); + } } static bool ignore_local_p (const ddsi_guid_t *guid1, const ddsi_guid_t *guid2, const struct dds_qos *xqos1, const struct dds_qos *xqos2) @@ -2451,7 +2919,6 @@ static void connect_writer_with_proxy_reader_wrapper (struct entity_common *vwr, struct proxy_reader *prd = (struct proxy_reader *) vprd; assert (wr->e.kind == EK_WRITER); assert (prd->e.kind == EK_PROXY_READER); - assert (is_builtin_endpoint (wr->e.guid.entityid, NN_VENDORID_ECLIPSE) == is_builtin_endpoint (prd->e.guid.entityid, prd->c.vendor)); connect_writer_with_proxy_reader (wr, prd, tnow); } @@ -2461,7 +2928,6 @@ static void connect_proxy_writer_with_reader_wrapper (struct entity_common *vpwr struct reader *rd = (struct reader *) vrd; assert (pwr->e.kind == EK_PROXY_WRITER); assert (rd->e.kind == EK_READER); - assert (is_builtin_endpoint (rd->e.guid.entityid, NN_VENDORID_ECLIPSE) == is_builtin_endpoint (pwr->e.guid.entityid, pwr->c.vendor)); connect_proxy_writer_with_reader (pwr, rd, tnow); } @@ -2471,8 +2937,6 @@ static void connect_writer_with_reader_wrapper (struct entity_common *vwr, struc struct reader *rd = (struct reader *) vrd; assert (wr->e.kind == EK_WRITER); assert (rd->e.kind == EK_READER); - assert (!is_builtin_endpoint (wr->e.guid.entityid, NN_VENDORID_ECLIPSE) || is_local_orphan_endpoint (&wr->e)); - assert (!is_builtin_endpoint (rd->e.guid.entityid, NN_VENDORID_ECLIPSE)); connect_writer_with_reader (wr, rd, tnow); } @@ -2637,13 +3101,135 @@ static void match_proxy_reader_with_writers (struct proxy_reader *prd, ddsrt_mti generic_do_match(&prd->e, tnow, false); } +#ifdef DDSI_INCLUDE_SECURITY + +static void match_volatile_secure_endpoints (struct participant *pp, struct proxy_participant *proxypp) +{ + struct reader *rd; + struct writer *wr; + struct proxy_reader *prd; + struct proxy_writer *pwr; + ddsi_guid_t guid; + ddsrt_mtime_t tnow = ddsrt_time_monotonic (); + + EELOGDISC (&pp->e, "match volatile endpoints (pp "PGUIDFMT") with (proxypp "PGUIDFMT")\n", + PGUID(pp->e.guid), PGUID(proxypp->e.guid)); + + guid = pp->e.guid; + guid.entityid.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER; + if ((rd = entidx_lookup_reader_guid (pp->e.gv->entity_index, &guid)) == NULL) + return; + + guid.entityid.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER; + if ((wr = entidx_lookup_writer_guid (pp->e.gv->entity_index, &guid)) == NULL) + return; + + guid = proxypp->e.guid; + guid.entityid.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER; + if ((prd = entidx_lookup_proxy_reader_guid (pp->e.gv->entity_index, &guid)) == NULL) + return; + + guid.entityid.u = NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER; + if ((pwr = entidx_lookup_proxy_writer_guid (pp->e.gv->entity_index, &guid)) == NULL) + return; + + connect_proxy_writer_with_reader_wrapper(&pwr->e, &rd->e, tnow); + connect_writer_with_proxy_reader_wrapper(&wr->e, &prd->e, tnow); +} + +static struct entity_common * get_entity_parent(struct entity_common *e) +{ + switch (e->kind) + { + case EK_WRITER: + return &((struct writer *)e)->c.pp->e; + case EK_READER: + return &((struct reader *)e)->c.pp->e; + case EK_PROXY_WRITER: + return &((struct proxy_writer *)e)->c.proxypp->e; + case EK_PROXY_READER: + return &((struct proxy_reader *)e)->c.proxypp->e; + case EK_PARTICIPANT: + case EK_PROXY_PARTICIPANT: + return NULL; + } + return NULL; +} + +static void update_proxy_participant_endpoint_matching (struct proxy_participant *proxypp, struct participant *pp) +{ + struct entity_index * const entidx = pp->e.gv->entity_index; + struct proxy_endpoint_common *cep; + ddsi_guid_t guid; + ddsi_entityid_t *endpoint_ids; + uint32_t num = 0, i; + ddsrt_mtime_t tnow = ddsrt_time_monotonic (); + + EELOGDISC (&proxypp->e, "update_proxy_participant_endpoint_matching (proxypp "PGUIDFMT" pp "PGUIDFMT")\n", + PGUID (proxypp->e.guid), PGUID (pp->e.guid)); + + ddsrt_mutex_lock(&proxypp->e.lock); + endpoint_ids = ddsrt_malloc(proxypp->refc * sizeof(ddsi_entityid_t)); + for (cep = proxypp->endpoints; cep != NULL; cep = cep->next_ep) + { + struct entity_common *e = entity_common_from_proxy_endpoint_common (cep); + endpoint_ids[num++] = e->guid.entityid; + } + ddsrt_mutex_unlock(&proxypp->e.lock); + + guid.prefix = proxypp->e.guid.prefix; + + for (i = 0; i < num; i++) + { + struct entity_common *e; + enum entity_kind mkind; + + guid.entityid = endpoint_ids[i]; + if ((e = entidx_lookup_guid_untyped(entidx, &guid)) == NULL) + continue; + + mkind = generic_do_match_mkind (e->kind, false); + if (!is_builtin_entityid (e->guid.entityid, NN_VENDORID_ECLIPSE)) + { + struct entidx_enum it; + struct entity_common *em; + struct match_entities_range_key max; + const char *tp = entity_topic_name (e); + + entidx_enum_init_topic(&it, entidx, mkind, tp, &max); + while ((em = entidx_enum_next_max (&it, &max)) != NULL) + { + if (&pp->e == get_entity_parent(em)) + generic_do_match_connect (e, em, tnow, false); + } + entidx_enum_fini (&it); + } + else + { + const ddsi_entityid_t tgt_ent = builtin_entityid_match (e->guid.entityid); + const ddsi_guid_t tgt_guid = { pp->e.guid.prefix, tgt_ent }; + + if (!is_builtin_volatile_endpoint (tgt_ent)) + { + struct entity_common *ep; + if ((ep = entidx_lookup_guid (entidx, &tgt_guid, mkind)) != NULL) + generic_do_match_connect (e, ep, tnow, false); + } + } + } + + ddsrt_free(endpoint_ids); +} + +#endif + /* ENDPOINT --------------------------------------------------------- */ static void new_reader_writer_common (const struct ddsrt_log_cfg *logcfg, const struct ddsi_guid *guid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos) { const char *partition = "(default)"; const char *partition_suffix = ""; - assert (is_builtin_entityid (guid->entityid, NN_VENDORID_ECLIPSE) ? (topic == NULL) : (topic != NULL)); + assert (topic != NULL); if (is_builtin_entityid (guid->entityid, NN_VENDORID_ECLIPSE)) { /* continue printing it as not being in a partition, the actual @@ -2661,8 +3247,8 @@ static void new_reader_writer_common (const struct ddsrt_log_cfg *logcfg, const is_writer_entityid (guid->entityid) ? "writer" : "reader", PGUID (*guid), partition, partition_suffix, - topic ? topic->name : "(null)", - topic ? topic->type_name : "(null)"); + topic->name, + topic->type_name); } static void endpoint_common_init (struct entity_common *e, struct endpoint_common *c, struct ddsi_domaingv *gv, enum entity_kind kind, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, bool onlylocal) @@ -2691,12 +3277,12 @@ static void endpoint_common_fini (struct entity_common *e, struct endpoint_commo static int set_topic_type_name (dds_qos_t *xqos, const struct ddsi_sertopic * topic) { - if (!(xqos->present & QP_TYPE_NAME) && topic) + if (!(xqos->present & QP_TYPE_NAME)) { xqos->present |= QP_TYPE_NAME; xqos->type_name = ddsrt_strdup (topic->type_name); } - if (!(xqos->present & QP_TOPIC_NAME) && topic) + if (!(xqos->present & QP_TOPIC_NAME)) { xqos->present |= QP_TOPIC_NAME; xqos->topic_name = ddsrt_strdup (topic->name); @@ -2989,6 +3575,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; @@ -2996,11 +3583,15 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se wr->throttle_tracing = 0; wr->rexmit_count = 0; wr->rexmit_lost_count = 0; + wr->force_md5_keyhash = 0; wr->alive = 1; wr->alive_vclock = 0; 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 */ @@ -3017,10 +3608,12 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se assert (wr->xqos->present & QP_RELIABILITY); wr->reliable = (wr->xqos->reliability.kind != DDS_RELIABILITY_BEST_EFFORT); assert (wr->xqos->present & QP_DURABILITY); - if (is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE)) + if (is_builtin_entityid (wr->e.guid.entityid, NN_VENDORID_ECLIPSE) && + (wr->e.guid.entityid.u != NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER)) { assert (wr->xqos->history.kind == DDS_HISTORY_KEEP_LAST); - assert (wr->xqos->durability.kind == DDS_DURABILITY_TRANSIENT_LOCAL); + assert ((wr->xqos->durability.kind == DDS_DURABILITY_TRANSIENT_LOCAL) || + (wr->e.guid.entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER)); } wr->handle_as_transient_local = (wr->xqos->durability.kind == DDS_DURABILITY_TRANSIENT_LOCAL); wr->include_keyhash = @@ -3128,7 +3721,8 @@ 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 (!is_builtin_entityid(wr->e.guid.entityid, NN_VENDORID_ECLIPSE) || (wr->whc_low == wr->whc_high && wr->whc_low == INT32_MAX)); + 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 */ ddsrt_avl_init (&wr_readers_treedef, &wr->readers); @@ -3155,10 +3749,14 @@ static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_g delete_participant won't interfere with our ability to address the participant */ - const bool onlylocal = topic && builtintopic_is_builtintopic (pp->e.gv->builtin_topic_interface, topic); + const bool onlylocal = builtintopic_is_builtintopic (pp->e.gv->builtin_topic_interface, topic); 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 @@ -3213,18 +3811,11 @@ static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_g return 0; } -dds_return_t new_writer (struct writer **wr_out, struct ddsi_domaingv *gv, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, const struct ddsi_guid *ppguid, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg) +dds_return_t new_writer (struct writer **wr_out, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg) { - struct participant *pp; dds_return_t rc; uint32_t kind; - if ((pp = entidx_lookup_participant_guid (gv->entity_index, ppguid)) == NULL) - { - GVLOGDISC ("new_writer - participant "PGUIDFMT" not found\n", PGUID (*ppguid)); - return DDS_RETCODE_BAD_PARAMETER; - } - /* 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) */ @@ -3291,7 +3882,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)) { @@ -3315,6 +3906,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); @@ -3377,16 +3971,30 @@ dds_return_t unblock_throttled_writer (struct ddsi_domaingv *gv, const struct dd return 0; } -dds_return_t writer_wait_for_acks (struct writer *wr, dds_time_t abstimeout) +dds_return_t writer_wait_for_acks (struct writer *wr, const ddsi_guid_t *rdguid, dds_time_t abstimeout) { dds_return_t rc; seqno_t ref_seq; ddsrt_mutex_lock (&wr->e.lock); ref_seq = wr->seq; - while (wr->state == WRST_OPERATIONAL && ref_seq > writer_max_drop_seq (wr)) - if (!ddsrt_cond_waituntil (&wr->throttle_cond, &wr->e.lock, abstimeout)) - break; - rc = (ref_seq <= writer_max_drop_seq (wr)) ? DDS_RETCODE_OK : DDS_RETCODE_TIMEOUT; + if (rdguid == NULL) + { + while (wr->state == WRST_OPERATIONAL && ref_seq > writer_max_drop_seq (wr)) + if (!ddsrt_cond_waituntil (&wr->throttle_cond, &wr->e.lock, abstimeout)) + break; + rc = (ref_seq <= writer_max_drop_seq (wr)) ? DDS_RETCODE_OK : DDS_RETCODE_TIMEOUT; + } + else + { + struct wr_prd_match *m = ddsrt_avl_lookup (&wr_readers_treedef, &wr->readers, rdguid); + while (wr->state == WRST_OPERATIONAL && m && ref_seq > m->seq) + { + if (!ddsrt_cond_waituntil (&wr->throttle_cond, &wr->e.lock, abstimeout)) + break; + m = ddsrt_avl_lookup (&wr_readers_treedef, &wr->readers, rdguid); + } + rc = (m == NULL || ref_seq <= m->seq) ? DDS_RETCODE_OK : DDS_RETCODE_TIMEOUT; + } ddsrt_mutex_unlock (&wr->e.lock); return rc; } @@ -3451,6 +4059,7 @@ 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)); + ddsrt_mutex_lock (&wr->e.lock); delete_writer_nolinger_locked (wr); ddsrt_mutex_unlock (&wr->e.lock); @@ -3637,7 +4246,7 @@ static dds_return_t new_reader_guid if (rd_out) *rd_out = rd; - const bool onlylocal = topic && builtintopic_is_builtintopic (pp->e.gv->builtin_topic_interface, topic); + const bool onlylocal = builtintopic_is_builtintopic (pp->e.gv->builtin_topic_interface, topic); endpoint_common_init (&rd->e, &rd->c, pp->e.gv, EK_READER, guid, group_guid, pp, onlylocal); /* Copy QoS, merging in defaults */ @@ -3656,13 +4265,25 @@ static dds_return_t new_reader_guid assert (rd->xqos->present & QP_RELIABILITY); rd->reliable = (rd->xqos->reliability.kind != DDS_RELIABILITY_BEST_EFFORT); assert (rd->xqos->present & QP_DURABILITY); - rd->handle_as_transient_local = (rd->xqos->durability.kind == DDS_DURABILITY_TRANSIENT_LOCAL); + /* The builtin volatile secure writer applies a filter which is used to send the secure + * crypto token only to the destination reader for which the crypto tokens are applicable. + * Thus the builtin volatile secure reader will receive gaps in the sequence numbers of + * the messages received. Therefore the out-of-order list of the proxy writer cannot be + * used for this reader and reader specific out-of-order list must be used which is + * used for handling transient local data. + */ + rd->handle_as_transient_local = (rd->xqos->durability.kind == DDS_DURABILITY_TRANSIENT_LOCAL) || + (rd->e.guid.entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER); rd->topic = ddsi_sertopic_ref (topic); 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) { @@ -3678,6 +4299,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) @@ -3749,10 +4374,9 @@ static dds_return_t new_reader_guid dds_return_t new_reader ( struct reader **rd_out, - struct ddsi_domaingv *gv, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, - const struct ddsi_guid *ppguid, + struct participant *pp, const struct ddsi_sertopic *topic, const struct dds_qos *xqos, struct ddsi_rhc * rhc, @@ -3760,15 +4384,9 @@ dds_return_t new_reader void * status_cbarg ) { - struct participant * pp; dds_return_t rc; uint32_t kind; - if ((pp = entidx_lookup_participant_guid (gv->entity_index, ppguid)) == NULL) - { - GVLOGDISC ("new_reader - participant "PGUIDFMT" not found\n", PGUID (*ppguid)); - return DDS_RETCODE_BAD_PARAMETER; - } 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) @@ -3788,7 +4406,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)) { @@ -3798,6 +4416,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 @@ -3914,6 +4536,151 @@ void proxy_participant_reassign_lease (struct proxy_participant *proxypp, struct ddsrt_mutex_unlock (&proxypp->e.lock); } +struct bestab { + unsigned besflag; + unsigned entityid; +}; + +static void create_proxy_builtin_endpoints( + struct ddsi_domaingv *gv, + const struct bestab *bestab, + int nbes, + const struct ddsi_guid *ppguid, + struct proxy_participant *proxypp, + ddsrt_wctime_t timestamp, + dds_qos_t *xqos_wr, + dds_qos_t *xqos_rd) +{ + ddsi_plist_t plist_rd, plist_wr; + int i; + /* Note: no entity name or group GUID supplied, but that shouldn't + * matter, as these are internal to DDSI and don't use group + * coherency + */ + ddsi_plist_init_empty (&plist_wr); + ddsi_plist_init_empty (&plist_rd); + ddsi_xqos_copy (&plist_wr.qos, xqos_wr); + ddsi_xqos_copy (&plist_rd.qos, xqos_rd); + for (i = 0; i < nbes; i++) + { + const struct bestab *te = &bestab[i]; + if (proxypp->bes & te->besflag) + { + ddsi_guid_t guid1; + guid1.prefix = proxypp->e.guid.prefix; + guid1.entityid.u = te->entityid; + assert (is_builtin_entityid (guid1.entityid, proxypp->vendor)); + if (is_writer_entityid (guid1.entityid)) + { + new_proxy_writer (gv, ppguid, &guid1, proxypp->as_meta, &plist_wr, gv->builtins_dqueue, gv->xevents, timestamp, 0); + } + else + { +#ifdef DDSI_INCLUDE_SSM + const int ssm = addrset_contains_ssm (gv, proxypp->as_meta); +#else + const int ssm = 0; +#endif + new_proxy_reader (gv, ppguid, &guid1, proxypp->as_meta, &plist_rd, timestamp, 0, ssm); + } + } + } + ddsi_plist_fini (&plist_wr); + ddsi_plist_fini (&plist_rd); +} + + +static void add_proxy_builtin_endpoints( + struct ddsi_domaingv *gv, + const struct ddsi_guid *ppguid, + struct proxy_participant *proxypp, + ddsrt_wctime_t timestamp) +{ + /* Add proxy endpoints based on the advertised (& possibly augmented + ...) built-in endpoint set. */ +#define TE(ap_, a_, bp_, b_) { NN_##ap_##BUILTIN_ENDPOINT_##a_, NN_ENTITYID_##bp_##_BUILTIN_##b_ } +#define LTE(a_, bp_, b_) { NN_##BUILTIN_ENDPOINT_##a_, NN_ENTITYID_##bp_##_BUILTIN_##b_ } + + /* 'Default' proxy endpoints. */ + static const struct bestab bestab_default[] = { +#if 0 + /* SPDP gets special treatment => no need for proxy + writers/readers */ + TE (DISC_, PARTICIPANT_ANNOUNCER, SPDP, PARTICIPANT_WRITER), +#endif + TE (DISC_, PARTICIPANT_DETECTOR, SPDP, PARTICIPANT_READER), + TE (DISC_, PUBLICATION_ANNOUNCER, SEDP, PUBLICATIONS_WRITER), + TE (DISC_, PUBLICATION_DETECTOR, SEDP, PUBLICATIONS_READER), + TE (DISC_, SUBSCRIPTION_ANNOUNCER, SEDP, SUBSCRIPTIONS_WRITER), + TE (DISC_, SUBSCRIPTION_DETECTOR, SEDP, SUBSCRIPTIONS_READER), + LTE (PARTICIPANT_MESSAGE_DATA_WRITER, P2P, PARTICIPANT_MESSAGE_WRITER), + LTE (PARTICIPANT_MESSAGE_DATA_READER, P2P, PARTICIPANT_MESSAGE_READER), + TE (DISC_, TOPIC_ANNOUNCER, SEDP, TOPIC_WRITER), + TE (DISC_, TOPIC_DETECTOR, SEDP, TOPIC_READER), + }; + create_proxy_builtin_endpoints(gv, + bestab_default, + (int)(sizeof (bestab_default) / sizeof (*bestab_default)), + ppguid, + proxypp, + timestamp, + &gv->builtin_endpoint_xqos_wr, + &gv->builtin_endpoint_xqos_rd); + +#ifdef DDSI_INCLUDE_SECURITY + /* Security 'default' proxy endpoints. */ + static const struct bestab bestab_security[] = { + LTE (PUBLICATION_MESSAGE_SECURE_ANNOUNCER, SEDP, PUBLICATIONS_SECURE_WRITER), + LTE (PUBLICATION_MESSAGE_SECURE_DETECTOR, SEDP, PUBLICATIONS_SECURE_READER), + LTE (SUBSCRIPTION_MESSAGE_SECURE_ANNOUNCER, SEDP, SUBSCRIPTIONS_SECURE_WRITER), + LTE (SUBSCRIPTION_MESSAGE_SECURE_DETECTOR, SEDP, SUBSCRIPTIONS_SECURE_READER), + LTE (PARTICIPANT_MESSAGE_SECURE_ANNOUNCER, P2P, PARTICIPANT_MESSAGE_SECURE_WRITER), + LTE (PARTICIPANT_MESSAGE_SECURE_DETECTOR, P2P, PARTICIPANT_MESSAGE_SECURE_READER), + TE (DISC_, PARTICIPANT_SECURE_ANNOUNCER, SPDP_RELIABLE, PARTICIPANT_SECURE_WRITER), + TE (DISC_, PARTICIPANT_SECURE_DETECTOR, SPDP_RELIABLE, PARTICIPANT_SECURE_READER) + }; + create_proxy_builtin_endpoints(gv, + bestab_security, + (int)(sizeof (bestab_security) / sizeof (*bestab_security)), + ppguid, + proxypp, + timestamp, + &gv->builtin_endpoint_xqos_wr, + &gv->builtin_endpoint_xqos_rd); + + /* Security 'volatile' proxy endpoints. */ + static const struct bestab bestab_volatile[] = { + LTE (PARTICIPANT_VOLATILE_SECURE_ANNOUNCER, P2P, PARTICIPANT_VOLATILE_SECURE_WRITER), + LTE (PARTICIPANT_VOLATILE_SECURE_DETECTOR, P2P, PARTICIPANT_VOLATILE_SECURE_READER) + }; + create_proxy_builtin_endpoints(gv, + bestab_volatile, + (int)(sizeof (bestab_volatile) / sizeof (*bestab_volatile)), + ppguid, + proxypp, + timestamp, + &gv->builtin_volatile_xqos_wr, + &gv->builtin_volatile_xqos_rd); + + /* Security 'stateless' proxy endpoints. */ + static const struct bestab bestab_stateless[] = { + LTE (PARTICIPANT_STATELESS_MESSAGE_ANNOUNCER, P2P, PARTICIPANT_STATELESS_MESSAGE_WRITER), + LTE (PARTICIPANT_STATELESS_MESSAGE_DETECTOR, P2P, PARTICIPANT_STATELESS_MESSAGE_READER) + }; + create_proxy_builtin_endpoints(gv, + bestab_stateless, + (int)(sizeof (bestab_stateless) / sizeof (*bestab_stateless)), + ppguid, + proxypp, + timestamp, + &gv->builtin_stateless_xqos_wr, + &gv->builtin_stateless_xqos_rd); +#endif + +#undef TE +#undef LTE +} + static void proxy_participant_add_pwr_lease_locked (struct proxy_participant * proxypp, const struct proxy_writer * pwr) { struct lease *minl_prev; @@ -3927,7 +4694,7 @@ static void proxy_participant_add_pwr_lease_locked (struct proxy_participant * p minl_prev = ddsrt_fibheap_min (&lease_fhdef_pp, lh); ddsrt_fibheap_insert (&lease_fhdef_pp, lh, pwr->lease); minl_new = ddsrt_fibheap_min (&lease_fhdef_pp, lh); - /* if inserted lease is new shortest lease */ + /* ensure proxypp->minl_man/minl_auto is equivalent to min(leaseheap_man/auto) */ if (proxypp->owns_lease && minl_prev != minl_new) { ddsrt_etime_t texp = ddsrt_etime_add_duration (ddsrt_time_elapsed (), minl_new->tdur); @@ -3948,24 +4715,26 @@ static void proxy_participant_add_pwr_lease_locked (struct proxy_participant * p static void proxy_participant_remove_pwr_lease_locked (struct proxy_participant * proxypp, struct proxy_writer * pwr) { - struct lease *minl; + struct lease *minl_prev; + struct lease *minl_new; bool manbypp; ddsrt_fibheap_t *lh; assert (pwr->lease != NULL); manbypp = (pwr->c.xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT); lh = manbypp ? &proxypp->leaseheap_man : &proxypp->leaseheap_auto; - minl = ddsrt_fibheap_min (&lease_fhdef_pp, lh); + minl_prev = ddsrt_fibheap_min (&lease_fhdef_pp, lh); ddsrt_fibheap_delete (&lease_fhdef_pp, lh, pwr->lease); - /* if pwr with min lease is removed: update proxypp lease to use new minimal duration */ - if (proxypp->owns_lease && pwr->lease == minl) + minl_new = ddsrt_fibheap_min (&lease_fhdef_pp, lh); + /* ensure proxypp->minl_man/minl_auto is equivalent to min(leaseheap_man/auto) */ + if (proxypp->owns_lease && minl_prev != minl_new) { - if ((minl = ddsrt_fibheap_min (&lease_fhdef_pp, lh)) != NULL) + if (minl_new != NULL) { - dds_duration_t trem = minl->tdur - pwr->lease->tdur; + dds_duration_t trem = minl_new->tdur - minl_prev->tdur; assert (trem >= 0); ddsrt_etime_t texp = ddsrt_etime_add_duration (ddsrt_time_elapsed(), trem); - struct lease *lnew = lease_new (texp, minl->tdur, minl->entity); + struct lease *lnew = lease_new (texp, minl_new->tdur, minl_new->entity); proxy_participant_replace_minl (proxypp, manbypp, lnew); lease_register (lnew); } @@ -3976,12 +4745,147 @@ static void proxy_participant_remove_pwr_lease_locked (struct proxy_participant } } -void new_proxy_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid, uint32_t bes, const struct ddsi_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const ddsi_plist_t *plist, dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, ddsrt_wctime_t timestamp, seqno_t seq) +#ifdef DDSI_INCLUDE_SECURITY + +void handshake_end_cb(struct ddsi_handshake *handshake, struct participant *pp, struct proxy_participant *proxypp, enum ddsi_handshake_state result) +{ + const struct ddsi_domaingv * const gv = pp->e.gv; + int64_t shared_secret; + + 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 (pp->e.guid), PGUID (proxypp->e.guid)); + if (q_omg_security_register_remote_participant(pp, proxypp, shared_secret)) { + match_volatile_secure_endpoints(pp, proxypp); + q_omg_security_set_remote_participant_authenticated(pp, proxypp); + } + break; + + case STATE_HANDSHAKE_SEND_TOKENS: + 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 (pp->e.guid), PGUID (proxypp->e.guid)); + update_proxy_participant_endpoint_matching(proxypp, pp); + ddsi_handshake_remove(pp, proxypp); + break; + + case STATE_HANDSHAKE_TIMED_OUT: + 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); + } + ddsi_handshake_remove(pp, proxypp); + break; + case STATE_HANDSHAKE_FAILED: + 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); + } + ddsi_handshake_remove(pp, proxypp); + break; + default: + 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); + break; + } +} + +static bool proxy_participant_has_pp_match(struct ddsi_domaingv *gv, struct proxy_participant *proxypp) +{ + bool match = false; + struct participant *pp; + struct entidx_enum_participant est; + + entidx_enum_participant_init (&est, gv->entity_index); + while ((pp = entidx_enum_participant_next (&est)) != NULL && !match) + { + /* remote secure pp can possibly match with local non-secured pp in case allow-unauthenticated pp + is enabled in the remote pp's security settings */ + match = !q_omg_participant_is_secure (pp) || q_omg_is_similar_participant_security_info (pp, proxypp); + } + entidx_enum_participant_fini (&est); + return match; +} + +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_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); + } + entidx_enum_participant_fini (&it); + } +} +#endif + +static void free_proxy_participant(struct proxy_participant *proxypp) +{ + if (proxypp->owns_lease) + { + struct lease * minl_auto = ddsrt_atomic_ldvoidp (&proxypp->minl_auto); + ddsrt_fibheap_delete (&lease_fhdef_pp, &proxypp->leaseheap_auto, proxypp->lease); + assert (ddsrt_fibheap_min (&lease_fhdef_pp, &proxypp->leaseheap_auto) == NULL); + assert (ddsrt_fibheap_min (&lease_fhdef_pp, &proxypp->leaseheap_man) == NULL); + assert (ddsrt_atomic_ldvoidp (&proxypp->minl_man) == NULL); + assert (!compare_guid (&minl_auto->entity->guid, &proxypp->e.guid)); + /* if the lease hasn't been registered yet (which is the case when + new_proxy_participant calls this, it is marked as such and calling + lease_unregister is ok */ + lease_unregister (minl_auto); + lease_free (minl_auto); + 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); + unref_addrset (proxypp->as_meta); + ddsi_plist_fini (proxypp->plist); + ddsrt_free (proxypp->plist); + entity_common_fini (&proxypp->e); + ddsrt_free (proxypp); +} + +bool new_proxy_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid, uint32_t bes, const struct ddsi_guid *privileged_pp_guid, struct addrset *as_default, struct addrset *as_meta, const ddsi_plist_t *plist, dds_duration_t tlease_dur, nn_vendorid_t vendor, unsigned custom_flags, ddsrt_wctime_t timestamp, seqno_t seq) { /* No locking => iff all participants use unique guids, and sedp runs on a single thread, it can't go wrong. FIXME, maybe? The same holds for the other functions for creating entities. */ struct proxy_participant *proxypp; + const bool is_secure = ((bes & NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_SECURE_ANNOUNCER) != 0); + assert (!is_secure || (plist->present & PP_IDENTITY_TOKEN)); + assert (is_secure || (bes & ~NN_BES_MASK_NON_SECURITY) == 0); + (void) is_secure; assert (ppguid->entityid.u == NN_ENTITYID_PARTICIPANT); assert (entidx_lookup_proxy_participant_guid (gv->entity_index, ppguid) == NULL); @@ -4015,6 +4919,8 @@ void new_proxy_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *pp proxypp->minimal_bes_mode = 1; else proxypp->minimal_bes_mode = 0; + proxypp->implicitly_created = ((custom_flags & CF_IMPLICITLY_CREATED_PROXYPP) != 0); + proxypp->proxypp_have_spdp = ((custom_flags & CF_PROXYPP_NO_SPDP) == 0); { struct proxy_participant *privpp; @@ -4065,86 +4971,25 @@ void new_proxy_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *pp ddsi_xqos_mergein_missing (&proxypp->plist->qos, &gv->default_plist_pp.qos, ~(uint64_t)0); ddsrt_avl_init (&proxypp_groups_treedef, &proxypp->groups); - if (custom_flags & CF_INC_KERNEL_SEQUENCE_NUMBERS) - proxypp->kernel_sequence_numbers = 1; - else - proxypp->kernel_sequence_numbers = 0; - if (custom_flags & CF_IMPLICITLY_CREATED_PROXYPP) - proxypp->implicitly_created = 1; - else - proxypp->implicitly_created = 0; - - if (custom_flags & CF_PROXYPP_NO_SPDP) - proxypp->proxypp_have_spdp = 0; - else - proxypp->proxypp_have_spdp = 1; - - /* Proxy participant must be in the hash tables for - new_proxy_{writer,reader} to work */ - entidx_insert_proxy_participant_guid (gv->entity_index, proxypp); - - /* Add proxy endpoints based on the advertised (& possibly augmented - ...) built-in endpoint set. */ +#ifdef DDSI_INCLUDE_SECURITY + proxypp->sec_attr = NULL; + set_proxy_participant_security_info (proxypp, plist); + if (is_secure) { -#define TE(ap_, a_, bp_, b_) { NN_##ap_##BUILTIN_ENDPOINT_##a_, NN_ENTITYID_##bp_##_BUILTIN_##b_ } -#define LTE(a_, bp_, b_) { NN_##BUILTIN_ENDPOINT_##a_, NN_ENTITYID_##bp_##_BUILTIN_##b_ } - static const struct bestab { - unsigned besflag; - unsigned entityid; - } bestab[] = { -#if 0 - /* SPDP gets special treatment => no need for proxy - writers/readers */ - TE (DISC_, PARTICIPANT_ANNOUNCER, SPDP, PARTICIPANT_WRITER), -#endif - TE (DISC_, PARTICIPANT_DETECTOR, SPDP, PARTICIPANT_READER), - TE (DISC_, PUBLICATION_ANNOUNCER, SEDP, PUBLICATIONS_WRITER), - TE (DISC_, PUBLICATION_DETECTOR, SEDP, PUBLICATIONS_READER), - TE (DISC_, SUBSCRIPTION_ANNOUNCER, SEDP, SUBSCRIPTIONS_WRITER), - TE (DISC_, SUBSCRIPTION_DETECTOR, SEDP, SUBSCRIPTIONS_READER), - LTE (PARTICIPANT_MESSAGE_DATA_WRITER, P2P, PARTICIPANT_MESSAGE_WRITER), - LTE (PARTICIPANT_MESSAGE_DATA_READER, P2P, PARTICIPANT_MESSAGE_READER), - TE (DISC_, TOPIC_ANNOUNCER, SEDP, TOPIC_WRITER), - TE (DISC_, TOPIC_DETECTOR, SEDP, TOPIC_READER) - }; -#undef TE -#undef LTE - ddsi_plist_t plist_rd, plist_wr; - int i; - /* Note: no entity name or group GUID supplied, but that shouldn't - matter, as these are internal to DDSI and don't use group - coherency */ - ddsi_plist_init_empty (&plist_wr); - ddsi_plist_init_empty (&plist_rd); - ddsi_xqos_copy (&plist_wr.qos, &gv->builtin_endpoint_xqos_wr); - ddsi_xqos_copy (&plist_rd.qos, &gv->builtin_endpoint_xqos_rd); - for (i = 0; i < (int) (sizeof (bestab) / sizeof (*bestab)); i++) + q_omg_security_init_remote_participant (proxypp); + /* check if the proxy participant has a match with a local participant */ + if (!proxy_participant_has_pp_match (gv, proxypp)) { - const struct bestab *te = &bestab[i]; - if (proxypp->bes & te->besflag) - { - ddsi_guid_t guid1; - guid1.prefix = proxypp->e.guid.prefix; - guid1.entityid.u = te->entityid; - assert (is_builtin_entityid (guid1.entityid, proxypp->vendor)); - if (is_writer_entityid (guid1.entityid)) - { - new_proxy_writer (gv, ppguid, &guid1, proxypp->as_meta, &plist_wr, gv->builtins_dqueue, gv->xevents, timestamp, 0); - } - else - { -#ifdef DDSI_INCLUDE_SSM - const int ssm = addrset_contains_ssm (gv, proxypp->as_meta); - new_proxy_reader (gv, ppguid, &guid1, proxypp->as_meta, &plist_rd, timestamp, 0, ssm); -#else - new_proxy_reader (gv, ppguid, &guid1, proxypp->as_meta, &plist_rd, timestamp, 0); -#endif - } - } + GVWARNING ("Remote secure participant "PGUIDFMT" not allowed\n", PGUID (*ppguid)); + free_proxy_participant (proxypp); + return false; } - ddsi_plist_fini (&plist_wr); - ddsi_plist_fini (&plist_rd); } +#endif + + /* Proxy participant must be in the hash tables for new_proxy_{writer,reader} to work */ + entidx_insert_proxy_participant_guid (gv->entity_index, proxypp); + add_proxy_builtin_endpoints(gv, ppguid, proxypp, timestamp); /* write DCPSParticipant topic before the lease can expire */ builtintopic_write (gv->builtin_topic_interface, &proxypp->e, timestamp, true); @@ -4156,6 +5001,14 @@ void new_proxy_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *pp if (proxypp->owns_lease) lease_register (ddsrt_atomic_ldvoidp (&proxypp->minl_auto)); ddsrt_mutex_unlock (&proxypp->e.lock); + +#ifdef DDSI_INCLUDE_SECURITY + if (is_secure) + { + proxy_participant_create_handshakes (gv, proxypp); + } +#endif + return true; } int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, seqno_t seq, const struct ddsi_plist *datap, ddsrt_wctime_t timestamp) @@ -4230,28 +5083,13 @@ static void unref_proxy_participant (struct proxy_participant *proxypp, struct p if (refc == 0) { + struct ddsi_domaingv * const gv = proxypp->e.gv; + const ddsi_guid_t pp_guid = proxypp->e.guid; assert (proxypp->endpoints == NULL); - if (proxypp->owns_lease) - { - struct lease * minl_auto = ddsrt_atomic_ldvoidp (&proxypp->minl_auto); - ddsrt_fibheap_delete (&lease_fhdef_pp, &proxypp->leaseheap_auto, proxypp->lease); - assert (ddsrt_fibheap_min (&lease_fhdef_pp, &proxypp->leaseheap_auto) == NULL); - assert (ddsrt_fibheap_min (&lease_fhdef_pp, &proxypp->leaseheap_man) == NULL); - assert (ddsrt_atomic_ldvoidp (&proxypp->minl_man) == NULL); - assert (!compare_guid (&minl_auto->entity->guid, &proxypp->e.guid)); - lease_unregister (minl_auto); - lease_free (minl_auto); - lease_free (proxypp->lease); - } ddsrt_mutex_unlock (&proxypp->e.lock); ELOGDISC (proxypp, "unref_proxy_participant("PGUIDFMT"): refc=0, freeing\n", PGUID (proxypp->e.guid)); - unref_addrset (proxypp->as_default); - unref_addrset (proxypp->as_meta); - ddsi_plist_fini (proxypp->plist); - ddsrt_free (proxypp->plist); - entity_common_fini (&proxypp->e); - remove_deleted_participant_guid (proxypp->e.gv->deleted_participants, &proxypp->e.guid, DPG_LOCAL | DPG_REMOTE); - ddsrt_free (proxypp); + free_proxy_participant (proxypp); + remove_deleted_participant_guid (gv->deleted_participants, &pp_guid, DPG_LOCAL | DPG_REMOTE); } else if (proxypp->endpoints == NULL && proxypp->implicitly_created) { @@ -4367,6 +5205,61 @@ static void delete_ppt (struct proxy_participant *proxypp, ddsrt_wctime_t timest gcreq_proxy_participant (proxypp); } +#ifdef DDSI_INCLUDE_SECURITY + +struct setab { + enum entity_kind kind; + uint32_t id; +}; + + +static void downgrade_to_nonsecure(struct proxy_participant *proxypp) +{ + const ddsrt_wctime_t tnow = ddsrt_time_wallclock (); + struct ddsi_guid guid; + static const struct setab setab[] = { + {EK_PROXY_WRITER, NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER}, + {EK_PROXY_READER, NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_READER}, + {EK_PROXY_WRITER, NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER}, + {EK_PROXY_READER, NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER}, + {EK_PROXY_WRITER, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER}, + {EK_PROXY_READER, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER}, + {EK_PROXY_WRITER, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER}, + {EK_PROXY_READER, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER}, + {EK_PROXY_WRITER, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER}, + {EK_PROXY_READER, NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER}, + {EK_PROXY_WRITER, NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER}, + {EK_PROXY_READER, NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_READER} + }; + int i; + + DDS_CWARNING (&proxypp->e.gv->logconfig, "downgrade participant "PGUIDFMT" to non-secure\n", PGUID (proxypp->e.guid)); + + guid.prefix = proxypp->e.guid.prefix; + /* Remove security related endpoints. */ + for (i = 0; i < (int)(sizeof(setab)/sizeof(*setab)); i++) + { + guid.entityid.u = setab[i].id; + switch (setab[i].kind) + { + case EK_PROXY_READER: + (void)delete_proxy_reader (proxypp->e.gv, &guid, tnow, 0); + break; + case EK_PROXY_WRITER: + (void)delete_proxy_writer (proxypp->e.gv, &guid, tnow, 0); + break; + default: + assert(0); + } + } + + /* Cleanup all kinds of related security information. */ + q_omg_security_deregister_remote_participant(proxypp); + proxypp->bes &= NN_BES_MASK_NON_SECURITY; +} +#endif + + typedef struct proxy_purge_data { struct proxy_participant *proxypp; const nn_locator_t *loc; @@ -4462,6 +5355,10 @@ static int proxy_endpoint_common_init (struct entity_common *e, struct proxy_end else memset (&c->group_guid, 0, sizeof (c->group_guid)); +#ifdef DDSI_INCLUDE_SECURITY + q_omg_get_proxy_endpoint_security_info(e, &proxypp->security_info, plist, &c->security_info); +#endif + if ((ret = ref_proxy_participant (proxypp, c)) != DDS_RETCODE_OK) { ddsi_xqos_fini (c->xqos); @@ -4485,12 +5382,27 @@ static void proxy_endpoint_common_fini (struct entity_common *e, struct proxy_en /* PROXY-WRITER ----------------------------------------------------- */ +static enum nn_reorder_mode +get_proxy_writer_reorder_mode(const ddsi_entityid_t pwr_entityid, int isreliable) +{ + if (isreliable) + { + return NN_REORDER_MODE_NORMAL; + } + if (pwr_entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER) + { + return NN_REORDER_MODE_ALWAYS_DELIVER; + } + return NN_REORDER_MODE_MONOTONICALLY_INCREASING; +} + int new_proxy_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid, const struct ddsi_guid *guid, struct addrset *as, const ddsi_plist_t *plist, struct nn_dqueue *dqueue, struct xeventq *evq, ddsrt_wctime_t timestamp, seqno_t seq) { struct proxy_participant *proxypp; struct proxy_writer *pwr; int isreliable; ddsrt_mtime_t tnow = ddsrt_time_monotonic (); + enum nn_reorder_mode reorder_mode; int ret; assert (is_writer_entityid (guid->entityid)); @@ -4518,6 +5430,7 @@ int new_proxy_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid, pwr->last_fragnum_reset = 0; pwr->alive = 1; pwr->alive_vclock = 0; + pwr->filtered = 0; ddsrt_atomic_st32 (&pwr->next_deliv_seq_lowword, 1); if (is_builtin_entityid (pwr->e.guid.entityid, pwr->c.vendor)) { /* The DDSI built-in proxy writers always deliver @@ -4564,17 +5477,31 @@ int new_proxy_writer (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid, if (isreliable) { pwr->defrag = nn_defrag_new (&gv->logconfig, NN_DEFRAG_DROP_LATEST, gv->config.defrag_reliable_maxsamples); - pwr->reorder = nn_reorder_new (&gv->logconfig, NN_REORDER_MODE_NORMAL, gv->config.primary_reorder_maxsamples, gv->config.late_ack_mode); } else { pwr->defrag = nn_defrag_new (&gv->logconfig, NN_DEFRAG_DROP_OLDEST, gv->config.defrag_unreliable_maxsamples); - pwr->reorder = nn_reorder_new (&gv->logconfig, NN_REORDER_MODE_MONOTONICALLY_INCREASING, gv->config.primary_reorder_maxsamples, gv->config.late_ack_mode); } + reorder_mode = get_proxy_writer_reorder_mode(pwr->e.guid.entityid, isreliable); + pwr->reorder = nn_reorder_new (&gv->logconfig, reorder_mode, gv->config.primary_reorder_maxsamples, gv->config.late_ack_mode); + + if (pwr->e.guid.entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER) + { + /* for the builtin_volatile_secure proxy writer which uses a content filter set the next expected + * sequence number of the reorder administration to the maximum sequence number to ensure that effectively + * the reorder administration of the builtin_volatile_secure proxy writer is not used and because the corresponding + * reader is always considered out of sync the reorder administration of the corresponding reader will be used + * instead. + */ + nn_reorder_set_next_seq(pwr->reorder, MAX_SEQ_NUMBER); + pwr->filtered = 1; + } + pwr->dqueue = dqueue; pwr->evq = evq; pwr->ddsi2direct_cb = 0; pwr->ddsi2direct_cbarg = 0; + local_reader_ary_init (&pwr->rdary); /* locking the entity prevents matching while the built-in topic hasn't been published yet */ @@ -4618,7 +5545,7 @@ void update_proxy_writer (struct proxy_writer *pwr, seqno_t seq, struct addrset rd = entidx_lookup_reader_guid (pwr->e.gv->entity_index, &m->rd_guid); if (rd) { - qxev_pwr_entityid (pwr, &rd->e.guid.prefix); + qxev_pwr_entityid (pwr, &rd->e.guid); } m = ddsrt_avl_iter_next (&iter); } @@ -4675,7 +5602,7 @@ void update_proxy_reader (struct proxy_reader *prd, seqno_t seq, struct addrset ddsrt_mutex_lock (&wr->e.lock); rebuild_writer_addrset (wr); ddsrt_mutex_unlock (&wr->e.lock); - qxev_prd_entityid (prd, &wr->e.guid.prefix); + qxev_prd_entityid (prd, &wr->e.guid); } wrguid = guid_next; ddsrt_mutex_lock (&prd->e.lock); @@ -4703,6 +5630,9 @@ static void gc_delete_proxy_writer (struct gcreq *gcreq) local_reader_ary_fini (&pwr->rdary); if (pwr->c.xqos->liveliness.lease_duration != DDS_INFINITY) lease_free (pwr->lease); +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_deregister_remote_writer(pwr); +#endif proxy_endpoint_common_fini (&pwr->e, &pwr->c); nn_defrag_free (pwr->defrag); nn_reorder_free (pwr->reorder); @@ -4854,6 +5784,15 @@ int new_proxy_reader (struct ddsi_domaingv *gv, const struct ddsi_guid *ppguid, ddsrt_avl_init (&prd_writers_treedef, &prd->writers); +#ifdef DDSI_INCLUDE_SECURITY + if (prd->e.guid.entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER) + prd->filter = volatile_secure_data_filter; + else + prd->filter = NULL; +#else + prd->filter = NULL; +#endif + /* locking the entity prevents matching while the built-in topic hasn't been published yet */ ddsrt_mutex_lock (&prd->e.lock); entidx_insert_proxy_reader_guid (gv->entity_index, prd); @@ -4925,7 +5864,9 @@ static void gc_delete_proxy_reader (struct gcreq *gcreq) writer_drop_connection (&m->wr_guid, prd); free_prd_wr_match (m); } - +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_deregister_remote_reader(prd); +#endif 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 d2479a3..46571cc 100644 --- a/src/core/ddsi/src/q_init.c +++ b/src/core/ddsi/src/q_init.c @@ -50,6 +50,7 @@ #include "dds/ddsi/q_debmon.h" #include "dds/ddsi/q_init.h" #include "dds/ddsi/ddsi_threadmon.h" +#include "dds/ddsi/ddsi_pmd.h" #include "dds/ddsi/ddsi_tran.h" #include "dds/ddsi/ddsi_udp.h" @@ -57,11 +58,16 @@ #include "dds/ddsi/ddsi_raweth.h" #include "dds/ddsi/ddsi_mcgroup.h" #include "dds/ddsi/ddsi_serdata_default.h" +#include "dds/ddsi/ddsi_serdata_pserop.h" +#include "dds/ddsi/ddsi_serdata_plist.h" +#include "dds/ddsi/ddsi_security_omg.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds__whc.h" #include "dds/ddsi/ddsi_iid.h" +#include "dds/ddsi/ddsi_security_omg.h" + static void add_peer_addresses (const struct ddsi_domaingv *gv, struct addrset *as, const struct config_peer_listelem *list) { while (list) @@ -133,6 +139,29 @@ static void make_builtin_endpoint_xqos (dds_qos_t *q, const dds_qos_t *template) q->durability.kind = DDS_DURABILITY_TRANSIENT_LOCAL; } +#ifdef DDSI_INCLUDE_SECURITY +static void make_builtin_volatile_endpoint_xqos (dds_qos_t *q, const dds_qos_t *template) +{ + ddsi_xqos_copy (q, template); + q->reliability.kind = DDS_RELIABILITY_RELIABLE; + q->reliability.max_blocking_time = DDS_MSECS (100); + q->durability.kind = DDS_DURABILITY_VOLATILE; + q->history.kind = DDS_HISTORY_KEEP_ALL; +} + +static void add_property_to_xqos(dds_qos_t *q, const char *name, const char *value) +{ + assert(!(q->present & QP_PROPERTY_LIST)); + q->present |= QP_PROPERTY_LIST; + q->property.value.n = 1; + q->property.value.props = ddsrt_malloc(sizeof(dds_property_t)); + q->property.binary_value.n = 0; + q->property.binary_value.props = NULL; + q->property.value.props[0].name = ddsrt_strdup(name); + q->property.value.props[0].value = ddsrt_strdup(value); +} +#endif + static int set_recvips (struct ddsi_domaingv *gv) { gv->recvips = NULL; @@ -374,10 +403,10 @@ static int known_channel_p (const struct ddsi_domaingv *gv, const char *name) static int check_thread_properties (const struct ddsi_domaingv *gv) { #ifdef DDSI_INCLUDE_NETWORK_CHANNELS - static const char *fixed[] = { "recv", "tev", "gc", "lease", "dq.builtins", "debmon", NULL }; + static const char *fixed[] = { "recv", "tev", "gc", "lease", "dq.builtins", "debmon", "fsm", NULL }; static const char *chanprefix[] = { "xmit.", "tev.","dq.",NULL }; #else - static const char *fixed[] = { "recv", "tev", "gc", "lease", "dq.builtins", "xmit.user", "dq.user", "debmon", NULL }; + static const char *fixed[] = { "recv", "tev", "gc", "lease", "dq.builtins", "xmit.user", "dq.user", "debmon", "fsm", NULL }; #endif const struct config_thread_properties_listelem *e; int ok = 1, i; @@ -762,38 +791,75 @@ static void wait_for_receive_threads (struct ddsi_domaingv *gv) } } -static struct ddsi_sertopic *make_special_topic (const char *name, struct serdatapool *serpool, uint16_t enc_id, const struct ddsi_serdata_ops *ops) +static struct ddsi_sertopic *make_special_topic_pserop (const char *name, const char *typename, size_t memsize, size_t nops, const enum pserop *ops, size_t nops_key, const enum pserop *ops_key) { - /* FIXME: two things (at least) - - it claims there is a key, but the underlying type description is missing - that only works as long as it ends up comparing the keyhash field ... - the keyhash field should be eliminated; but this can simply be moved over to an alternate - topic class, it need not use the "default" one, that's mere expediency - - initialising/freeing them here, in this manner, is not very clean - it should be moved to somewhere in the topic implementation - (kinda natural if they stop being "default" ones) */ - struct ddsi_sertopic_default *st = ddsrt_malloc (sizeof (*st)); + struct ddsi_sertopic_pserop *st = ddsrt_malloc (sizeof (*st)); memset (st, 0, sizeof (*st)); - ddsi_sertopic_init (&st->c, name, name, &ddsi_sertopic_ops_default, ops, false); - st->native_encoding_identifier = enc_id; - st->serpool = serpool; + ddsi_sertopic_init (&st->c, name, typename, &ddsi_sertopic_ops_pserop, &ddsi_serdata_ops_pserop, nops_key == 0); + st->native_encoding_identifier = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN) ? CDR_LE : CDR_BE; + st->memsize = memsize; + st->nops = nops; + st->ops = ops; + st->nops_key = nops_key; + st->ops_key = ops_key; + return (struct ddsi_sertopic *) st; +} + +static struct ddsi_sertopic *make_special_topic_plist (const char *name, const char *typename, nn_parameterid_t keyparam) +{ + struct ddsi_sertopic_plist *st = ddsrt_malloc (sizeof (*st)); + memset (st, 0, sizeof (*st)); + ddsi_sertopic_init (&st->c, name, typename, &ddsi_sertopic_ops_plist, &ddsi_serdata_ops_plist, false); + st->native_encoding_identifier = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN) ? PL_CDR_LE : PL_CDR_BE; + st->keyparam = keyparam; return (struct ddsi_sertopic *) st; } static void free_special_topics (struct ddsi_domaingv *gv) { - ddsi_sertopic_unref (gv->plist_topic); - ddsi_sertopic_unref (gv->rawcdr_topic); +#ifdef DDSI_INCLUDE_SECURITY + ddsi_sertopic_unref (gv->pgm_volatile_topic); + ddsi_sertopic_unref (gv->pgm_stateless_topic); + ddsi_sertopic_unref (gv->pmd_secure_topic); + ddsi_sertopic_unref (gv->spdp_secure_topic); + ddsi_sertopic_unref (gv->sedp_reader_secure_topic); + ddsi_sertopic_unref (gv->sedp_writer_secure_topic); +#endif + ddsi_sertopic_unref (gv->pmd_topic); + ddsi_sertopic_unref (gv->spdp_topic); + ddsi_sertopic_unref (gv->sedp_reader_topic); + ddsi_sertopic_unref (gv->sedp_writer_topic); } static void make_special_topics (struct ddsi_domaingv *gv) { - gv->plist_topic = make_special_topic ("plist", gv->serpool, DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? PL_CDR_LE : PL_CDR_BE, &ddsi_serdata_ops_plist); - gv->rawcdr_topic = make_special_topic ("rawcdr", gv->serpool, DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? CDR_LE : CDR_BE, &ddsi_serdata_ops_rawcdr); + gv->spdp_topic = make_special_topic_plist ("DCPSParticipant", "ParticipantBuiltinTopicData", PID_PARTICIPANT_GUID); + gv->sedp_reader_topic = make_special_topic_plist ("DCPSSubscription", "SubscriptionBuiltinTopicData", PID_ENDPOINT_GUID); + gv->sedp_writer_topic = make_special_topic_plist ("DCPSPublication", "PublicationBuiltinTopicData", PID_ENDPOINT_GUID); + gv->pmd_topic = make_special_topic_pserop ("DCPSParticipantMessage", "ParticipantMessageData", sizeof (ParticipantMessageData_t), participant_message_data_nops, participant_message_data_ops, participant_message_data_nops_key, participant_message_data_ops_key); + +#ifdef DDSI_INCLUDE_SECURITY + gv->spdp_secure_topic = make_special_topic_plist ("DCPSParticipantsSecure", "ParticipantBuiltinTopicDataSecure", PID_PARTICIPANT_GUID); + gv->sedp_reader_secure_topic = make_special_topic_plist ("DCPSSubscriptionsSecure", "SubscriptionBuiltinTopicDataSecure", PID_ENDPOINT_GUID); + gv->sedp_writer_secure_topic = make_special_topic_plist ("DCPSPublicationsSecure", "PublicationBuiltinTopicDataSecure", PID_ENDPOINT_GUID); + gv->pmd_secure_topic = make_special_topic_pserop ("DCPSParticipantMessageSecure", "ParticipantMessageDataSecure", sizeof (ParticipantMessageData_t), participant_message_data_nops, participant_message_data_ops, participant_message_data_nops_key, participant_message_data_ops_key); + gv->pgm_stateless_topic = make_special_topic_pserop ("DCPSParticipantStatelessMessage", "ParticipantStatelessMessage", sizeof (nn_participant_generic_message_t), pserop_participant_generic_message_nops, pserop_participant_generic_message, 0, NULL); + gv->pgm_volatile_topic = make_special_topic_pserop ("DCPSParticipantVolatileMessageSecure", "ParticipantVolatileMessageSecure", sizeof (nn_participant_generic_message_t), pserop_participant_generic_message_nops, pserop_participant_generic_message, 0, NULL); +#endif ddsrt_mutex_lock (&gv->sertopics_lock); - ddsi_sertopic_register_locked (gv, gv->plist_topic); - ddsi_sertopic_register_locked (gv, gv->rawcdr_topic); + ddsi_sertopic_register_locked (gv, gv->spdp_topic); + ddsi_sertopic_register_locked (gv, gv->sedp_reader_topic); + ddsi_sertopic_register_locked (gv, gv->sedp_writer_topic); + ddsi_sertopic_register_locked (gv, gv->pmd_topic); +#ifdef DDSI_INCLUDE_SECURITY + ddsi_sertopic_register_locked (gv, gv->spdp_secure_topic); + ddsi_sertopic_register_locked (gv, gv->sedp_reader_secure_topic); + ddsi_sertopic_register_locked (gv, gv->sedp_writer_secure_topic); + ddsi_sertopic_register_locked (gv, gv->pmd_secure_topic); + ddsi_sertopic_register_locked (gv, gv->pgm_stateless_topic); + ddsi_sertopic_register_locked (gv, gv->pgm_volatile_topic); +#endif ddsrt_mutex_unlock (&gv->sertopics_lock); /* register increments refcount (which is reasonable), but at some point @@ -1121,6 +1187,19 @@ int rtps_init (struct ddsi_domaingv *gv) gv->spdp_endpoint_xqos.durability.kind = DDS_DURABILITY_TRANSIENT_LOCAL; make_builtin_endpoint_xqos (&gv->builtin_endpoint_xqos_rd, &gv->default_xqos_rd); make_builtin_endpoint_xqos (&gv->builtin_endpoint_xqos_wr, &gv->default_xqos_wr); +#ifdef DDSI_INCLUDE_SECURITY + make_builtin_volatile_endpoint_xqos(&gv->builtin_volatile_xqos_rd, &gv->default_xqos_rd); + make_builtin_volatile_endpoint_xqos(&gv->builtin_volatile_xqos_wr, &gv->default_xqos_wr); + ddsi_xqos_copy (&gv->builtin_stateless_xqos_rd, &gv->default_xqos_rd); + ddsi_xqos_copy (&gv->builtin_stateless_xqos_wr, &gv->default_xqos_wr); + gv->builtin_stateless_xqos_wr.reliability.kind = DDS_RELIABILITY_BEST_EFFORT; + gv->builtin_stateless_xqos_wr.durability.kind = DDS_DURABILITY_VOLATILE; + + /* Setting these properties allows the CryptoKeyFactory to recognize + * the entities (see DDS Security spec chapter 8.8.8.1). */ + 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"); +#endif ddsrt_mutex_init (&gv->sertopics_lock); gv->sertopics = ddsrt_hh_new (1, ddsi_sertopic_hash_wrap, ddsi_sertopic_equal_wrap); @@ -1389,6 +1468,10 @@ int rtps_init (struct ddsi_domaingv *gv) #endif ); +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_init(gv); +#endif + gv->as_disc = new_addrset (); if (gv->config.allowMulticast & AMC_SPDP) add_to_addrset (gv, gv->as_disc, &gv->loc_spdp_mc); @@ -1476,6 +1559,15 @@ err_unicast_sockets: #endif ddsrt_hh_free (gv->sertopics); ddsrt_mutex_destroy (&gv->sertopics_lock); +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_stop (gv); // should be a no-op as it starts lazily + q_omg_security_deinit(gv->security_context); + q_omg_security_free (gv); + ddsi_xqos_fini (&gv->builtin_stateless_xqos_wr); + ddsi_xqos_fini (&gv->builtin_stateless_xqos_rd); + ddsi_xqos_fini (&gv->builtin_volatile_xqos_wr); + ddsi_xqos_fini (&gv->builtin_volatile_xqos_rd); +#endif ddsi_xqos_fini (&gv->builtin_endpoint_xqos_wr); ddsi_xqos_fini (&gv->builtin_endpoint_xqos_rd); ddsi_xqos_fini (&gv->spdp_endpoint_xqos); @@ -1487,6 +1579,7 @@ err_unicast_sockets: ddsi_xqos_fini (&gv->default_xqos_rd); ddsi_plist_fini (&gv->default_local_plist_pp); ddsi_plist_fini (&gv->default_plist_pp); + ddsi_serdatapool_free (gv->serpool); nn_xmsgpool_free (gv->xmsgpool); #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS @@ -1699,6 +1792,12 @@ void rtps_stop (struct ddsi_domaingv *gv) thread_state_asleep (ts1); } + /* Stop background (handshake) processing in security implementation, + do this only once we know no new events will be coming in. */ +#if DDSI_INCLUDE_SECURITY + q_omg_security_stop (gv); +#endif + /* Wait until all participants are really gone => by then we can be certain that no new GC requests will be added, short of what we do here */ @@ -1739,6 +1838,10 @@ void rtps_fini (struct ddsi_domaingv *gv) nn_dqueue_free (gv->user_dqueue); #endif +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_deinit (gv->security_context); +#endif + xeventq_free (gv->xevents); if (gv->config.xpack_send_async) @@ -1804,7 +1907,6 @@ void rtps_fini (struct ddsi_domaingv *gv) } ddsi_tkmap_free (gv->m_tkmap); - entity_index_free (gv->entity_index); gv->entity_index = NULL; deleted_participants_admin_free (gv->deleted_participants); @@ -1822,6 +1924,13 @@ void rtps_fini (struct ddsi_domaingv *gv) ddsrt_hh_free (gv->sertopics); ddsrt_mutex_destroy (&gv->sertopics_lock); +#ifdef DDSI_INCLUDE_SECURITY + q_omg_security_free (gv); + ddsi_xqos_fini (&gv->builtin_stateless_xqos_wr); + ddsi_xqos_fini (&gv->builtin_stateless_xqos_rd); + ddsi_xqos_fini (&gv->builtin_volatile_xqos_wr); + ddsi_xqos_fini (&gv->builtin_volatile_xqos_rd); +#endif ddsi_xqos_fini (&gv->builtin_endpoint_xqos_wr); ddsi_xqos_fini (&gv->builtin_endpoint_xqos_rd); ddsi_xqos_fini (&gv->spdp_endpoint_xqos); diff --git a/src/core/ddsi/src/q_misc.c b/src/core/ddsi/src/q_misc.c index f0b6df1..dac4cbe 100644 --- a/src/core/ddsi/src/q_misc.c +++ b/src/core/ddsi/src/q_misc.c @@ -42,6 +42,21 @@ 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]; +} + +int guid_eq (const struct ddsi_guid *a, const struct ddsi_guid *b) +{ + return guid_prefix_eq(&a->prefix, &b->prefix) && (a->entityid.u == b->entityid.u); +} + int ddsi2_patmatch (const char *pat, const char *str) { while (*pat) diff --git a/src/core/ddsi/src/q_radmin.c b/src/core/ddsi/src/q_radmin.c index 5aaa6c7..99f9120 100644 --- a/src/core/ddsi/src/q_radmin.c +++ b/src/core/ddsi/src/q_radmin.c @@ -1547,6 +1547,28 @@ int nn_defrag_nackmap (struct nn_defrag *defrag, seqno_t seq, uint32_t maxfragnu return (int) map->numbits; } +/* There is only one defrag per proxy writer. However for the Volatile Secure writer a filter + * is applied to filter on the destination participant. Note that there will be one + * builtin Volatile Secure reader for each local participant. When this local participant + * is deleted the defrag buffer may still contain fragments for the associated reader. + * The nn_defrag_prune is used to remove these fragments and should only be used when + * the Volatile Secure reader is deleted. + */ +void nn_defrag_prune (struct nn_defrag *defrag, ddsi_guid_prefix_t *dst, seqno_t min) +{ + struct nn_rsample *s = ddsrt_avl_lookup_succ_eq (&defrag_sampletree_treedef, &defrag->sampletree, &min); + while (s) + { + struct nn_rsample *s1 = ddsrt_avl_find_succ (&defrag_sampletree_treedef, &defrag->sampletree, s); + if (guid_prefix_eq(&s->u.defrag.sampleinfo->rst->dst_guid_prefix, dst)) + { + defrag_rsample_drop (defrag, s); + } + s = s1; + } + defrag->max_sample = ddsrt_avl_find_max (&defrag_sampletree_treedef, &defrag->sampletree); +} + /* REORDER ------------------------------------------------------------- The reorder index tracks out-of-order messages as non-overlapping, @@ -2368,6 +2390,11 @@ seqno_t nn_reorder_next_seq (const struct nn_reorder *reorder) return reorder->next_seq; } +void nn_reorder_set_next_seq (struct nn_reorder *reorder, seqno_t seq) +{ + reorder->next_seq = seq; +} + /* DQUEUE -------------------------------------------------------------- */ struct nn_dqueue { diff --git a/src/core/ddsi/src/q_receive.c b/src/core/ddsi/src/q_receive.c index 2f209e1..f85403c 100644 --- a/src/core/ddsi/src/q_receive.c +++ b/src/core/ddsi/src/q_receive.c @@ -54,6 +54,7 @@ #include "dds/ddsi/ddsi_mcgroup.h" #include "dds/ddsi/ddsi_serdata.h" #include "dds/ddsi/ddsi_serdata_default.h" /* FIXME: get rid of this */ +#include "dds/ddsi/ddsi_security_omg.h" #include "dds/ddsi/sysdeps.h" #include "dds__whc.h" @@ -93,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; } @@ -281,7 +285,34 @@ static void set_sampleinfo_proxy_writer (struct nn_rsample_info *sampleinfo, dds sampleinfo->pwr = pwr; } -static int valid_Data (const struct receiver_state *rst, struct nn_rmsg *rmsg, Data_t *msg, size_t size, int byteswap, struct nn_rsample_info *sampleinfo, unsigned char **payloadp) +static int set_sampleinfo_bswap (struct nn_rsample_info *sampleinfo, struct CDRHeader *hdr) +{ + if (hdr) + { + switch (hdr->identifier) + { + case CDR_BE: + case PL_CDR_BE: + { + sampleinfo->bswap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN) ? 1 : 0; + break; + } + case CDR_LE: + case PL_CDR_LE: + { + sampleinfo->bswap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN) ? 0 : 1; + break; + } + default: + { + return 0; + } + } + } + return 1; +} + +static int valid_Data (const struct receiver_state *rst, struct nn_rmsg *rmsg, Data_t *msg, size_t size, int byteswap, struct nn_rsample_info *sampleinfo, unsigned char **payloadp, uint32_t *payloadsz) { /* on success: sampleinfo->{seq,rst,statusinfo,bswap,complex_qos} all set */ ddsi_guid_t pwr_guid; @@ -355,6 +386,7 @@ static int valid_Data (const struct receiver_state *rst, struct nn_rmsg *rmsg, D { /*TRACE (("no payload\n"));*/ *payloadp = NULL; + *payloadsz = 0; sampleinfo->size = 0; } else if ((size_t) ((char *) ptr + 4 - (char *) msg) > size) @@ -364,35 +396,15 @@ static int valid_Data (const struct receiver_state *rst, struct nn_rmsg *rmsg, D } else { - struct CDRHeader *hdr; sampleinfo->size = (uint32_t) ((char *) msg + size - (char *) ptr); + *payloadsz = sampleinfo->size; *payloadp = ptr; - hdr = (struct CDRHeader *) ptr; - switch (hdr->identifier) - { - case CDR_BE: - case PL_CDR_BE: - { - sampleinfo->bswap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? 1 : 0); - break; - } - case CDR_LE: - case PL_CDR_LE: - { - sampleinfo->bswap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? 0 : 1); - break; - } - default: - return 0; - } } return 1; } -static int valid_DataFrag (const struct receiver_state *rst, struct nn_rmsg *rmsg, DataFrag_t *msg, size_t size, int byteswap, struct nn_rsample_info *sampleinfo, unsigned char **payloadp) +static int valid_DataFrag (const struct receiver_state *rst, struct nn_rmsg *rmsg, DataFrag_t *msg, size_t size, int byteswap, struct nn_rsample_info *sampleinfo, unsigned char **payloadp, uint32_t *payloadsz) { - /* on success: sampleinfo->{rst,statusinfo,bswap,complex_qos} all set */ - uint32_t payloadsz; ddsi_guid_t pwr_guid; unsigned char *ptr; @@ -473,18 +485,17 @@ static int valid_DataFrag (const struct receiver_state *rst, struct nn_rmsg *rms } *payloadp = ptr; - payloadsz = (uint32_t) ((char *) msg + size - (char *) ptr); - if ((uint32_t) msg->fragmentsInSubmessage * msg->fragmentSize <= payloadsz) + *payloadsz = (uint32_t) ((char *) msg + size - (char *) ptr); + if ((uint32_t) msg->fragmentsInSubmessage * msg->fragmentSize <= (*payloadsz)) ; /* all spec'd fragments fit in payload */ - else if ((uint32_t) (msg->fragmentsInSubmessage - 1) * msg->fragmentSize >= payloadsz) + else if ((uint32_t) (msg->fragmentsInSubmessage - 1) * msg->fragmentSize >= (*payloadsz)) return 0; /* I can live with a short final fragment, but _only_ the final one */ - else if ((uint32_t) (msg->fragmentStartingNum - 1) * msg->fragmentSize + payloadsz >= msg->sampleSize) + else if ((uint32_t) (msg->fragmentStartingNum - 1) * msg->fragmentSize + (*payloadsz) >= msg->sampleSize) ; /* final fragment is long enough to cover rest of sample */ else return 0; if (msg->fragmentStartingNum == 1) { - struct CDRHeader *hdr = (struct CDRHeader *) ptr; if ((size_t) ((char *) ptr + 4 - (char *) msg) > size) { /* no space for the header -- technically, allowing small @@ -492,28 +503,11 @@ static int valid_DataFrag (const struct receiver_state *rst, struct nn_rmsg *rms prefer this */ return 0; } - switch (hdr->identifier) - { - case CDR_BE: - case PL_CDR_BE: - { - sampleinfo->bswap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? 1 : 0); - break; - } - case CDR_LE: - case PL_CDR_LE: - { - sampleinfo->bswap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN ? 0 : 1); - break; - } - default: - return 0; - } } return 1; } -static int add_Gap (struct nn_xmsg *msg, struct writer *wr, struct proxy_reader *prd, seqno_t start, seqno_t base, uint32_t numbits, const uint32_t *bits) +int add_Gap (struct nn_xmsg *msg, struct writer *wr, struct proxy_reader *prd, seqno_t start, seqno_t base, uint32_t numbits, const uint32_t *bits) { struct nn_xmsg_marker sm_marker; Gap_t *gap; @@ -527,6 +521,7 @@ static int add_Gap (struct nn_xmsg *msg, struct writer *wr, struct proxy_reader gap->gapList.numbits = numbits; memcpy (gap->bits, bits, NN_SEQUENCE_NUMBER_SET_BITS_SIZE (numbits)); nn_xmsg_submsg_setnext (msg, sm_marker); + encode_datawriter_submsg(msg, sm_marker, wr); return 0; } @@ -537,7 +532,7 @@ static void force_heartbeat_to_peer (struct writer *wr, const struct whc_state * ASSERT_MUTEX_HELD (&wr->e.lock); assert (wr->reliable); - m = nn_xmsg_new (wr->e.gv->xmsgpool, &wr->e.guid.prefix, 0, NN_XMSG_KIND_CONTROL); + m = nn_xmsg_new (wr->e.gv->xmsgpool, &wr->e.guid, wr->c.pp, 0, NN_XMSG_KIND_CONTROL); if (nn_xmsg_setdstPRD (m, prd) < 0) { /* If we don't have an address, give up immediately */ @@ -610,7 +605,83 @@ static int accept_ack_or_hb_w_timeout (nn_count_t new_count, nn_count_t *exp_cou return 1; } -static int handle_AckNack (struct receiver_state *rst, ddsrt_etime_t tnow, const AckNack_t *msg, ddsrt_wctime_t timestamp) +void nn_gap_info_init(struct nn_gap_info *gi) +{ + gi->gapstart = -1; + gi->gapend = -1; + gi->gapnumbits = 0; + memset(gi->gapbits, 0, sizeof(gi->gapbits)); +} + +void nn_gap_info_update(struct ddsi_domaingv *gv, struct nn_gap_info *gi, int64_t seqnr) +{ + if (gi->gapstart == -1) + { + GVTRACE (" M%"PRId64, seqnr); + gi->gapstart = seqnr; + gi->gapend = gi->gapstart + 1; + } + else if (seqnr == gi->gapend) + { + GVTRACE (" M%"PRId64, seqnr); + gi->gapend = seqnr + 1; + } + else if (seqnr - gi->gapend < 256) + { + unsigned idx = (unsigned) (seqnr - gi->gapend); + GVTRACE (" M%"PRId64, seqnr); + gi->gapnumbits = idx + 1; + nn_bitset_set (gi->gapnumbits, gi->gapbits, idx); + } +} + +struct nn_xmsg * nn_gap_info_create_gap(struct writer *wr, struct proxy_reader *prd, struct nn_gap_info *gi) +{ + struct nn_xmsg *m; + + if (gi->gapstart <= 0) + return NULL; + + if (gi->gapnumbits == 0) + { + /* Avoid sending an invalid bitset */ + gi->gapnumbits = 1; + nn_bitset_set (gi->gapnumbits, gi->gapbits, 0); + gi->gapend--; + } + + m = nn_xmsg_new (wr->e.gv->xmsgpool, &wr->e.guid, wr->c.pp, 0, NN_XMSG_KIND_CONTROL); + +#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS + nn_xmsg_setencoderid (m, wr->partition_id); +#endif + + if (nn_xmsg_setdstPRD (m, prd) < 0) + { + nn_xmsg_free (m); + m = NULL; + } + else + { + add_Gap (m, wr, prd, gi->gapstart, gi->gapend, gi->gapnumbits, gi->gapbits); + if (nn_xmsg_size(m) == 0) + { + nn_xmsg_free (m); + m = NULL; + } + else + { + unsigned i; + ETRACE (wr, " FXGAP%"PRId64"..%"PRId64"/%d:", gi->gapstart, gi->gapend, gi->gapnumbits); + for (i = 0; i < gi->gapnumbits; i++) + ETRACE (wr, "%c", nn_bitset_isset (gi->gapnumbits, gi->gapbits, i) ? '1' : '0'); + } + } + + return m; +} + +static int handle_AckNack (struct receiver_state *rst, ddsrt_etime_t tnow, const AckNack_t *msg, ddsrt_wctime_t timestamp, SubmessageKind_t prev_smid) { struct proxy_reader *prd; struct wr_prd_match *rn; @@ -619,10 +690,9 @@ static int handle_AckNack (struct receiver_state *rst, ddsrt_etime_t tnow, const ddsi_guid_t src, dst; seqno_t seqbase; seqno_t seq_xmit; + seqno_t max_seq_available; nn_count_t *countp; - seqno_t gapstart = -1, gapend = -1; - unsigned gapnumbits = 0; - uint32_t gapbits[256 / 32]; + struct nn_gap_info gi; int accelerate_rexmit = 0; int is_pure_ack; int is_pure_nonhist_ack; @@ -634,7 +704,6 @@ static int handle_AckNack (struct receiver_state *rst, ddsrt_etime_t tnow, const struct whc_node *deferred_free_list = NULL; struct whc_state whcst; int hb_sent_in_response = 0; - memset (gapbits, 0, sizeof (gapbits)); countp = (nn_count_t *) ((char *) msg + offsetof (AckNack_t, bits) + NN_SEQUENCE_NUMBER_SET_BITS_SIZE (msg->readerSNState.numbits)); src.prefix = rst->src_guid_prefix; src.entityid = msg->readerId; @@ -667,8 +736,15 @@ static int handle_AckNack (struct receiver_state *rst, ddsrt_etime_t tnow, const return 1; } + if (!validate_msg_decoding(&(prd->e), &(prd->c), prd->c.proxypp, rst, prev_smid)) + { + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" clear submsg from protected src)", PGUID (src), PGUID (dst)); + return 1; + } + if ((lease = ddsrt_atomic_ldvoidp (&prd->c.proxypp->minl_auto)) != NULL) lease_renew (lease, tnow); + if (!wr->reliable) /* note: reliability can't be changed */ { RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" not a reliable writer!)", PGUID (src), PGUID (dst)); @@ -837,6 +913,7 @@ static int handle_AckNack (struct receiver_state *rst, ddsrt_etime_t tnow, const a future request'll fix it. */ enqueued = 1; seq_xmit = writer_read_seq_xmit (wr); + nn_gap_info_init(&gi); const bool gap_for_already_acked = vendor_is_eclipse (rst->vendor) && prd->c.xqos->durability.kind == DDS_DURABILITY_VOLATILE && seqbase <= rn->seq; const seqno_t min_seq_to_rexmit = gap_for_already_acked ? rn->seq + 1 : 0; for (uint32_t i = 0; i < numbits && seqbase + i <= seq_xmit && enqueued; i++) @@ -854,7 +931,7 @@ static int handle_AckNack (struct receiver_state *rst, ddsrt_etime_t tnow, const if (!wr->retransmitting && sample.unacked) writer_set_retransmitting (wr); - if (rst->gv->config.retransmit_merging != REXMIT_MERGE_NEVER && rn->assumed_in_sync) + if (rst->gv->config.retransmit_merging != REXMIT_MERGE_NEVER && rn->assumed_in_sync && !prd->filter) { /* send retransmit to all receivers, but skip if recently done */ ddsrt_mtime_t tstamp = ddsrt_time_monotonic (); @@ -876,77 +953,54 @@ static int handle_AckNack (struct receiver_state *rst, ddsrt_etime_t tnow, const } else { - /* no merging, send directed retransmit */ - RSTTRACE (" RX%"PRId64"", seqbase + i); - enqueued = (enqueue_sample_wrlock_held (wr, seq, sample.plist, sample.serdata, prd, 0) >= 0); - if (enqueued) + /* Is this a volatile reader with a filter? + * If so, call the filter to see if we should re-arrange the sequence gap when needed. */ + if (prd->filter && !prd->filter (wr, prd, sample.serdata)) + nn_gap_info_update (rst->gv, &gi, seqbase + i); + else { - max_seq_in_reply = seqbase + i; - msgs_sent++; - sample.rexmit_count++; + /* no merging, send directed retransmit */ + RSTTRACE (" RX%"PRId64"", seqbase + i); + enqueued = (enqueue_sample_wrlock_held (wr, seq, sample.plist, sample.serdata, prd, 0) >= 0); + if (enqueued) + { + max_seq_in_reply = seqbase + i; + msgs_sent++; + sample.rexmit_count++; + } } } - whc_return_sample(wr->whc, &sample, true); } - else if (gapstart == -1) + else { - RSTTRACE (" M%"PRId64, seqbase + i); - gapstart = seqbase + i; - gapend = gapstart + 1; - msgs_lost++; - } - else if (seqbase + i == gapend) - { - RSTTRACE (" M%"PRId64, seqbase + i); - gapend = seqbase + i + 1; - msgs_lost++; - } - else if (seqbase + i - gapend < 256) - { - uint32_t idx = (uint32_t) (seqbase + i - gapend); - RSTTRACE (" M%"PRId64, seqbase + i); - gapnumbits = idx + 1; - nn_bitset_set (gapnumbits, gapbits, idx); + nn_gap_info_update (rst->gv, &gi, seqbase + i); msgs_lost++; } } } + if (!enqueued) RSTTRACE (" rexmit-limit-hit"); /* Generate a Gap message if some of the sequence is missing */ - if (gapstart > 0) + if (gi.gapstart > 0) { - struct nn_xmsg *m; - if (gapend == seqbase + msg->readerSNState.numbits) + struct nn_xmsg *gap; + + if (gi.gapend == seqbase + msg->readerSNState.numbits) + gi.gapend = grow_gap_to_next_seq (wr, gi.gapend); + + if (gi.gapend-1 + gi.gapnumbits > max_seq_in_reply) + max_seq_in_reply = gi.gapend-1 + gi.gapnumbits; + + gap = nn_gap_info_create_gap (wr, prd, &gi); + if (gap) { - /* We automatically grow a gap as far as we can -- can't - retransmit those messages anyway, so no need for round-trip - to the remote reader. */ - gapend = grow_gap_to_next_seq (wr, gapend); + qxev_msg (wr->evq, gap); + msgs_sent++; } - /* The non-bitmap part of a gap message says everything <= - gapend-1 is no more (so the maximum sequence number it informs - the peer of is gapend-1); each bit adds one sequence number to - that. */ - if (gapend-1 + gapnumbits > max_seq_in_reply) - max_seq_in_reply = gapend-1 + gapnumbits; - RSTTRACE (" XGAP%"PRId64"..%"PRId64"/%u:", gapstart, gapend, gapnumbits); - for (uint32_t i = 0; i < gapnumbits; i++) - RSTTRACE ("%c", nn_bitset_isset (gapnumbits, gapbits, i) ? '1' : '0'); - m = nn_xmsg_new (rst->gv->xmsgpool, &wr->e.guid.prefix, 0, NN_XMSG_KIND_CONTROL); -#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS - nn_xmsg_setencoderid (m, wr->partition_id); -#endif - if (nn_xmsg_setdstPRD (m, prd) < 0) - nn_xmsg_free (m); - else - { - add_Gap (m, wr, prd, gapstart, gapend, gapnumbits, gapbits); - qxev_msg (wr->evq, m); - } - msgs_sent++; } + wr->rexmit_count += msgs_sent; wr->rexmit_lost_count += msgs_lost; /* If rexmits and/or a gap message were sent, and if the last @@ -954,7 +1008,8 @@ static int handle_AckNack (struct receiver_state *rst, ddsrt_etime_t tnow, const less than the last sequence number transmitted by the writer, tell the peer to acknowledge quickly. Not sure if that helps, but it might ... [NB writer->seq is the last msg sent so far] */ - if (msgs_sent && max_seq_in_reply < seq_xmit) + max_seq_available = (prd->filter ? rn->last_seq : seq_xmit); + if (msgs_sent && max_seq_in_reply < max_seq_available) { RSTTRACE (" rexmit#%"PRIu32" maxseq:%"PRId64"<%"PRId64"<=%"PRId64"", msgs_sent, max_seq_in_reply, seq_xmit, wr->seq); force_heartbeat_to_peer (wr, &whcst, prd, 1); @@ -1040,7 +1095,7 @@ static void handle_Heartbeat_helper (struct pwr_rd_match * const wn, struct hand struct receiver_state * const rst = arg->rst; Heartbeat_t const * const msg = arg->msg; struct proxy_writer * const pwr = arg->pwr; - seqno_t refseq; + seqno_t refseq, last_seq; ASSERT_MUTEX_HELD (&pwr->e.lock); @@ -1054,7 +1109,7 @@ static void handle_Heartbeat_helper (struct pwr_rd_match * const wn, struct hand /* Reference sequence number for determining whether or not to Ack/Nack unfortunately depends on whether the reader is in sync. */ - if (wn->in_sync != PRMSS_OUT_OF_SYNC) + if (wn->in_sync != PRMSS_OUT_OF_SYNC && !wn->filtered) refseq = nn_reorder_next_seq (pwr->reorder) - 1; else refseq = nn_reorder_next_seq (wn->u.not_in_sync.reorder) - 1; @@ -1070,7 +1125,12 @@ static void handle_Heartbeat_helper (struct pwr_rd_match * const wn, struct hand if (wn->acknack_xevent) { ddsrt_mtime_t tsched = DDSRT_MTIME_NEVER; - if (pwr->last_seq > refseq) + + if (wn->filtered) + last_seq = wn->last_seq; + else + last_seq = pwr->last_seq; + if (last_seq > refseq) { RSTTRACE ("/NAK"); if (arg->tnow_mt.v >= wn->t_last_nack.v + rst->gv->config.nack_delay || refseq >= wn->seq_last_nack) @@ -1093,7 +1153,7 @@ static void handle_Heartbeat_helper (struct pwr_rd_match * const wn, struct hand } } -static int handle_Heartbeat (struct receiver_state *rst, ddsrt_etime_t tnow, struct nn_rmsg *rmsg, const Heartbeat_t *msg, ddsrt_wctime_t timestamp) +static int handle_Heartbeat (struct receiver_state *rst, ddsrt_etime_t tnow, struct nn_rmsg *rmsg, const Heartbeat_t *msg, ddsrt_wctime_t timestamp, SubmessageKind_t prev_smid) { /* We now cheat: and process the heartbeat for _all_ readers, always, regardless of the destination address in the Heartbeat @@ -1132,8 +1192,16 @@ static int handle_Heartbeat (struct receiver_state *rst, ddsrt_etime_t tnow, str RSTTRACE (PGUIDFMT"? -> "PGUIDFMT")", PGUID (src), PGUID (dst)); return 1; } + + if (!validate_msg_decoding(&(pwr->e), &(pwr->c), pwr->c.proxypp, rst, prev_smid)) + { + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" clear submsg from protected src)", PGUID (src), PGUID (dst)); + return 1; + } + if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto)) != NULL) lease_renew (lease, tnow); + RSTTRACE (PGUIDFMT" -> "PGUIDFMT":", PGUID (src), PGUID (dst)); ddsrt_mutex_lock (&pwr->e.lock); if (msg->smhdr.flags & HEARTBEAT_FLAG_LIVELINESS && @@ -1194,44 +1262,73 @@ static int handle_Heartbeat (struct receiver_state *rst, ddsrt_etime_t tnow, str int refc_adjust = 0; nn_reorder_result_t res; gap = nn_rdata_newgap (rmsg); - if ((res = nn_reorder_gap (&sc, pwr->reorder, gap, 1, firstseq, &refc_adjust)) > 0) + int filtered = 0; + + if (pwr->filtered && !is_null_guid(&dst)) { - if (pwr->deliver_synchronously) - deliver_user_data_synchronously (&sc, NULL); - else - nn_dqueue_enqueue (pwr->dqueue, &sc, res); - } - for (wn = ddsrt_avl_find_min (&pwr_readers_treedef, &pwr->readers); wn; wn = ddsrt_avl_find_succ (&pwr_readers_treedef, &pwr->readers, wn)) - if (wn->in_sync != PRMSS_SYNC) + for (wn = ddsrt_avl_find_min (&pwr_readers_treedef, &pwr->readers); wn; wn = ddsrt_avl_find_succ (&pwr_readers_treedef, &pwr->readers, wn)) { - seqno_t last_deliv_seq = 0; - switch (wn->in_sync) + if (guid_eq(&wn->rd_guid, &dst)) { - case PRMSS_SYNC: - assert(0); - break; - case PRMSS_TLCATCHUP: - last_deliv_seq = nn_reorder_next_seq (pwr->reorder) - 1; - break; - case PRMSS_OUT_OF_SYNC: { + if (wn->filtered) + { struct nn_reorder *ro = wn->u.not_in_sync.reorder; if ((res = nn_reorder_gap (&sc, ro, gap, 1, firstseq, &refc_adjust)) > 0) + nn_dqueue_enqueue1 (pwr->dqueue, &wn->rd_guid, &sc, res); + if (fromSN (msg->lastSN) > wn->last_seq) { - if (pwr->deliver_synchronously) - deliver_user_data_synchronously (&sc, &wn->rd_guid); - else - nn_dqueue_enqueue1 (pwr->dqueue, &wn->rd_guid, &sc, res); + wn->last_seq = fromSN (msg->lastSN); } - last_deliv_seq = nn_reorder_next_seq (wn->u.not_in_sync.reorder) - 1; + filtered = 1; } + break; } - if (wn->u.not_in_sync.end_of_tl_seq == MAX_SEQ_NUMBER) - { - wn->u.not_in_sync.end_of_tl_seq = fromSN (msg->lastSN); - RSTTRACE (" end-of-tl-seq(rd "PGUIDFMT" #%"PRId64")", PGUID(wn->rd_guid), wn->u.not_in_sync.end_of_tl_seq); - } - maybe_set_reader_in_sync (pwr, wn, last_deliv_seq); } + } + + if (!filtered) + { + if ((res = nn_reorder_gap (&sc, pwr->reorder, gap, 1, firstseq, &refc_adjust)) > 0) + { + if (pwr->deliver_synchronously) + deliver_user_data_synchronously (&sc, NULL); + else + nn_dqueue_enqueue (pwr->dqueue, &sc, res); + } + for (wn = ddsrt_avl_find_min (&pwr_readers_treedef, &pwr->readers); wn; wn = ddsrt_avl_find_succ (&pwr_readers_treedef, &pwr->readers, wn)) + { + if (wn->in_sync != PRMSS_SYNC) + { + seqno_t last_deliv_seq = 0; + switch (wn->in_sync) + { + case PRMSS_SYNC: + assert(0); + break; + case PRMSS_TLCATCHUP: + last_deliv_seq = nn_reorder_next_seq (pwr->reorder) - 1; + break; + case PRMSS_OUT_OF_SYNC: { + struct nn_reorder *ro = wn->u.not_in_sync.reorder; + if ((res = nn_reorder_gap (&sc, ro, gap, 1, firstseq, &refc_adjust)) > 0) + { + if (pwr->deliver_synchronously) + deliver_user_data_synchronously (&sc, &wn->rd_guid); + else + nn_dqueue_enqueue1 (pwr->dqueue, &wn->rd_guid, &sc, res); + } + last_deliv_seq = nn_reorder_next_seq (wn->u.not_in_sync.reorder) - 1; + } + } + if (wn->u.not_in_sync.end_of_tl_seq == MAX_SEQ_NUMBER) + { + wn->u.not_in_sync.end_of_tl_seq = fromSN (msg->lastSN); + RSTTRACE (" end-of-tl-seq(rd "PGUIDFMT" #%"PRId64")", PGUID(wn->rd_guid), wn->u.not_in_sync.end_of_tl_seq); + } + maybe_set_reader_in_sync (pwr, wn, last_deliv_seq); + } + } + } nn_fragchain_adjust_refcount (gap, refc_adjust); } @@ -1248,7 +1345,7 @@ static int handle_Heartbeat (struct receiver_state *rst, ddsrt_etime_t tnow, str return 1; } -static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(ddsrt_etime_t tnow), const HeartbeatFrag_t *msg) +static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(ddsrt_etime_t tnow), const HeartbeatFrag_t *msg, SubmessageKind_t prev_smid) { const seqno_t seq = fromSN (msg->writerSN); const nn_fragment_number_t fragnum = msg->lastFragmentNum - 1; /* we do 0-based */ @@ -1274,8 +1371,15 @@ static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(ddsrt_et return 1; } + if (!validate_msg_decoding(&(pwr->e), &(pwr->c), pwr->c.proxypp, rst, prev_smid)) + { + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" clear submsg from protected src)", PGUID (src), PGUID (dst)); + return 1; + } + if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto)) != NULL) lease_renew (lease, tnow); + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT"", PGUID (src), PGUID (dst)); ddsrt_mutex_lock (&pwr->e.lock); @@ -1359,7 +1463,7 @@ static int handle_HeartbeatFrag (struct receiver_state *rst, UNUSED_ARG(ddsrt_et return 1; } -static int handle_NackFrag (struct receiver_state *rst, ddsrt_etime_t tnow, const NackFrag_t *msg) +static int handle_NackFrag (struct receiver_state *rst, ddsrt_etime_t tnow, const NackFrag_t *msg, SubmessageKind_t prev_smid) { struct proxy_reader *prd; struct wr_prd_match *rn; @@ -1401,8 +1505,15 @@ static int handle_NackFrag (struct receiver_state *rst, ddsrt_etime_t tnow, cons return 1; } + if (!validate_msg_decoding(&(prd->e), &(prd->c), prd->c.proxypp, rst, prev_smid)) + { + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" clear submsg from protected src)", PGUID (src), PGUID (dst)); + return 1; + } + if ((lease = ddsrt_atomic_ldvoidp (&prd->c.proxypp->minl_auto)) != NULL) lease_renew (lease, tnow); + if (!wr->reliable) /* note: reliability can't be changed */ { RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" not a reliable writer)", PGUID (src), PGUID (dst)); @@ -1450,7 +1561,7 @@ static int handle_NackFrag (struct receiver_state *rst, ddsrt_etime_t tnow, cons static uint32_t zero = 0; struct nn_xmsg *m; RSTTRACE (" msg not available: scheduling Gap\n"); - m = nn_xmsg_new (rst->gv->xmsgpool, &wr->e.guid.prefix, 0, NN_XMSG_KIND_CONTROL); + m = nn_xmsg_new (rst->gv->xmsgpool, &wr->e.guid, wr->c.pp, 0, NN_XMSG_KIND_CONTROL); #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS nn_xmsg_setencoderid (m, wr->partition_id); #endif @@ -1533,22 +1644,26 @@ static int handle_InfoTS (const struct receiver_state *rst, const InfoTS_t *msg, static int handle_one_gap (struct proxy_writer *pwr, struct pwr_rd_match *wn, seqno_t a, seqno_t b, struct nn_rdata *gap, int *refc_adjust) { struct nn_rsample_chain sc; - nn_reorder_result_t res; + nn_reorder_result_t res = 0; int gap_was_valuable = 0; ASSERT_MUTEX_HELD (&pwr->e.lock); /* Clean up the defrag admin: no fragments of a missing sample will be arriving in the future */ - nn_defrag_notegap (pwr->defrag, a, b); - - /* Primary reorder: the gap message may cause some samples to become - deliverable. */ - if ((res = nn_reorder_gap (&sc, pwr->reorder, gap, a, b, refc_adjust)) > 0) + if (!(wn && wn->filtered)) { - if (pwr->deliver_synchronously) - deliver_user_data_synchronously (&sc, NULL); - else - nn_dqueue_enqueue (pwr->dqueue, &sc, res); + nn_defrag_notegap (pwr->defrag, a, b); + + /* Primary reorder: the gap message may cause some samples to become + deliverable. */ + + if ((res = nn_reorder_gap (&sc, pwr->reorder, gap, a, b, refc_adjust)) > 0) + { + if (pwr->deliver_synchronously) + deliver_user_data_synchronously (&sc, NULL); + else + nn_dqueue_enqueue (pwr->dqueue, &sc, res); + } } /* If the result was REJECT or TOO_OLD, then this gap didn't add @@ -1594,7 +1709,7 @@ static int handle_one_gap (struct proxy_writer *pwr, struct pwr_rd_match *wn, se return gap_was_valuable; } -static int handle_Gap (struct receiver_state *rst, ddsrt_etime_t tnow, struct nn_rmsg *rmsg, const Gap_t *msg) +static int handle_Gap (struct receiver_state *rst, ddsrt_etime_t tnow, struct nn_rmsg *rmsg, const Gap_t *msg, SubmessageKind_t prev_smid) { /* Option 1: Process the Gap for the proxy writer and all out-of-sync readers: what do I care which reader is being @@ -1648,8 +1763,15 @@ static int handle_Gap (struct receiver_state *rst, ddsrt_etime_t tnow, struct nn return 1; } + if (!validate_msg_decoding(&(pwr->e), &(pwr->c), pwr->c.proxypp, rst, prev_smid)) + { + RSTTRACE (" "PGUIDFMT" -> "PGUIDFMT" clear submsg from protected src)", PGUID (src), PGUID (dst)); + return 1; + } + if ((lease = ddsrt_atomic_ldvoidp (&pwr->c.proxypp->minl_auto)) != NULL) lease_renew (lease, tnow); + ddsrt_mutex_lock (&pwr->e.lock); if ((wn = ddsrt_avl_lookup (&pwr_readers_treedef, &pwr->readers, &dst)) == NULL) { @@ -1714,6 +1836,14 @@ static int handle_Gap (struct receiver_state *rst, ddsrt_etime_t tnow, struct nn pwr->last_fragnum = ~0u; pwr->last_fragnum_reset = 0; } + + if (wn && wn->filtered) + { + if (listbase + last_included_rel > wn->last_seq) + { + wn->last_seq = listbase + last_included_rel; + } + } RSTTRACE (")"); ddsrt_mutex_unlock (&pwr->e.lock); return 1; @@ -1795,6 +1925,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 @@ -1840,7 +1976,7 @@ static struct ddsi_serdata *remote_make_sample (struct ddsi_tkmap_instance **tk, GVTRACE ("data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": ST%x %s/%s:%s%s", sampleinfo->rst->vendor.id[0], sampleinfo->rst->vendor.id[1], PGUID (guid), sampleinfo->seq, statusinfo, topic->name, topic->type_name, - tmp, res < sizeof (tmp) ? "" : "(trunc)"); + tmp, res < sizeof (tmp) - 1 ? "" : "(trunc)"); } } return sample; @@ -2139,108 +2275,138 @@ static void handle_regular (struct receiver_state *rst, ddsrt_etime_t tnow, stru int refc_adjust = 0; struct nn_rsample_chain sc; struct nn_rdata *fragchain = nn_rsample_fragchain (rsample); - nn_reorder_result_t rres; + nn_reorder_result_t rres, rres2; + struct pwr_rd_match *wn; + int filtered = 0; - rres = nn_reorder_rsample (&sc, pwr->reorder, rsample, &refc_adjust, 0); // nn_dqueue_is_full (pwr->dqueue)); - - if (rres == NN_REORDER_ACCEPT && pwr->n_reliable_readers == 0) + if (pwr->filtered && !is_null_guid(&dst)) { - /* If no reliable readers but the reorder buffer accepted the - sample, it must be a reliable proxy writer with only - unreliable readers. "Inserting" a Gap [1, sampleinfo->seq) - will force delivery of this sample, and not cause the gap to - be added to the reorder admin. */ - int gap_refc_adjust = 0; - rres = nn_reorder_gap (&sc, pwr->reorder, rdata, 1, sampleinfo->seq, &gap_refc_adjust); - assert (rres > 0); - assert (gap_refc_adjust == 0); - } - - if (rres > 0) - { - /* Enqueue or deliver with pwr->e.lock held: to ensure no other - receive thread's data gets interleaved -- arguably delivery - needn't be exactly in-order, which would allow us to do this - without pwr->e.lock held. - Note that PMD is also handled here, but the pwr for PMD does not - use no synchronous delivery, so deliver_user_data_synchronously - (which asserts pwr is not built-in) is not used for PMD handling. */ - if (pwr->deliver_synchronously) + for (wn = ddsrt_avl_find_min (&pwr_readers_treedef, &pwr->readers); wn != NULL; wn = ddsrt_avl_find_succ (&pwr_readers_treedef, &pwr->readers, wn)) { - /* FIXME: just in case the synchronous delivery runs into a delay caused - by the current mishandling of resource limits */ - if (*deferred_wakeup) - dd_dqueue_enqueue_trigger (*deferred_wakeup); - deliver_user_data_synchronously (&sc, NULL); - } - else - { - if (nn_dqueue_enqueue_deferred_wakeup (pwr->dqueue, &sc, rres)) + if (guid_eq(&wn->rd_guid, &dst)) { - if (*deferred_wakeup && *deferred_wakeup != pwr->dqueue) - dd_dqueue_enqueue_trigger (*deferred_wakeup); - *deferred_wakeup = pwr->dqueue; + if (wn->filtered) + { + rres2 = nn_reorder_rsample (&sc, wn->u.not_in_sync.reorder, rsample, &refc_adjust, nn_dqueue_is_full (pwr->dqueue)); + if (sampleinfo->seq > wn->last_seq) + { + wn->last_seq = sampleinfo->seq; + } + if (rres2 > 0) + { + if (!pwr->deliver_synchronously) + nn_dqueue_enqueue1 (pwr->dqueue, &wn->rd_guid, &sc, rres2); + else + deliver_user_data_synchronously (&sc, &wn->rd_guid); + } + filtered = 1; + } + break; } } } - if (pwr->n_readers_out_of_sync > 0) + if (!filtered) { - /* Those readers catching up with TL but in sync with the proxy - writer may have become in sync with the proxy writer and the - writer; those catching up with TL all by themselves go through - the "TOO_OLD" path below. */ - ddsrt_avl_iter_t it; - struct pwr_rd_match *wn; - struct nn_rsample *rsample_dup = NULL; - int reuse_rsample_dup = 0; - for (wn = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); wn != NULL; wn = ddsrt_avl_iter_next (&it)) + rres = nn_reorder_rsample (&sc, pwr->reorder, rsample, &refc_adjust, 0); // nn_dqueue_is_full (pwr->dqueue)); + + if (rres == NN_REORDER_ACCEPT && pwr->n_reliable_readers == 0) { - nn_reorder_result_t rres2; - if (wn->in_sync == PRMSS_SYNC) - continue; - /* only need to get a copy of the first sample, because that's the one - that triggered delivery */ - if (!reuse_rsample_dup) - rsample_dup = nn_reorder_rsample_dup_first (rmsg, rsample); - rres2 = nn_reorder_rsample (&sc, wn->u.not_in_sync.reorder, rsample_dup, &refc_adjust, nn_dqueue_is_full (pwr->dqueue)); - switch (rres2) + /* If no reliable readers but the reorder buffer accepted the + sample, it must be a reliable proxy writer with only + unreliable readers. "Inserting" a Gap [1, sampleinfo->seq) + will force delivery of this sample, and not cause the gap to + be added to the reorder admin. */ + int gap_refc_adjust = 0; + rres = nn_reorder_gap (&sc, pwr->reorder, rdata, 1, sampleinfo->seq, &gap_refc_adjust); + assert (rres > 0); + assert (gap_refc_adjust == 0); + } + + if (rres > 0) + { + /* Enqueue or deliver with pwr->e.lock held: to ensure no other + receive thread's data gets interleaved -- arguably delivery + needn't be exactly in-order, which would allow us to do this + without pwr->e.lock held. + Note that PMD is also handled here, but the pwr for PMD does not + use no synchronous delivery, so deliver_user_data_synchronously + (which asserts pwr is not built-in) is not used for PMD handling. */ + if (pwr->deliver_synchronously) { - case NN_REORDER_TOO_OLD: - case NN_REORDER_REJECT: - reuse_rsample_dup = 1; - break; - case NN_REORDER_ACCEPT: - reuse_rsample_dup = 0; - break; - default: - assert (rres2 > 0); - /* note: can't deliver to a reader, only to a group */ - maybe_set_reader_in_sync (pwr, wn, sampleinfo->seq); - reuse_rsample_dup = 0; - /* No need to deliver old data to out-of-sync readers - synchronously -- ordering guarantees don't change - as fresh data will be delivered anyway and hence - the old data will never be guaranteed to arrive - in-order, and those few microseconds can't hurt in - catching up on transient-local data. See also - NN_REORDER_DELIVER case in outer switch. */ - if (pwr->deliver_synchronously) - { - /* FIXME: just in case the synchronous delivery runs into a delay caused - by the current mishandling of resource limits */ - deliver_user_data_synchronously (&sc, &wn->rd_guid); - } - else - { - if (*deferred_wakeup && *deferred_wakeup != pwr->dqueue) + /* FIXME: just in case the synchronous delivery runs into a delay caused + by the current mishandling of resource limits */ + if (*deferred_wakeup) + dd_dqueue_enqueue_trigger (*deferred_wakeup); + deliver_user_data_synchronously (&sc, NULL); + } + else + { + if (nn_dqueue_enqueue_deferred_wakeup (pwr->dqueue, &sc, rres)) + { + if (*deferred_wakeup && *deferred_wakeup != pwr->dqueue) + dd_dqueue_enqueue_trigger (*deferred_wakeup); + *deferred_wakeup = pwr->dqueue; + } + } + } + + if (pwr->n_readers_out_of_sync > 0) + { + /* Those readers catching up with TL but in sync with the proxy + writer may have become in sync with the proxy writer and the + writer; those catching up with TL all by themselves go through + the "TOO_OLD" path below. */ + ddsrt_avl_iter_t it; + struct nn_rsample *rsample_dup = NULL; + int reuse_rsample_dup = 0; + for (wn = ddsrt_avl_iter_first (&pwr_readers_treedef, &pwr->readers, &it); wn != NULL; wn = ddsrt_avl_iter_next (&it)) + { + if (wn->in_sync == PRMSS_SYNC) + continue; + /* only need to get a copy of the first sample, because that's the one + that triggered delivery */ + if (!reuse_rsample_dup) + rsample_dup = nn_reorder_rsample_dup_first (rmsg, rsample); + rres2 = nn_reorder_rsample (&sc, wn->u.not_in_sync.reorder, rsample_dup, &refc_adjust, nn_dqueue_is_full (pwr->dqueue)); + switch (rres2) + { + case NN_REORDER_TOO_OLD: + case NN_REORDER_REJECT: + reuse_rsample_dup = 1; + break; + case NN_REORDER_ACCEPT: + reuse_rsample_dup = 0; + break; + default: + assert (rres2 > 0); + /* note: can't deliver to a reader, only to a group */ + maybe_set_reader_in_sync (pwr, wn, sampleinfo->seq); + reuse_rsample_dup = 0; + /* No need to deliver old data to out-of-sync readers + synchronously -- ordering guarantees don't change + as fresh data will be delivered anyway and hence + the old data will never be guaranteed to arrive + in-order, and those few microseconds can't hurt in + catching up on transient-local data. See also + NN_REORDER_DELIVER case in outer switch. */ + if (pwr->deliver_synchronously) { - dd_dqueue_enqueue_trigger (*deferred_wakeup); - *deferred_wakeup = NULL; + /* FIXME: just in case the synchronous delivery runs into a delay caused + by the current mishandling of resource limits */ + deliver_user_data_synchronously (&sc, &wn->rd_guid); } - nn_dqueue_enqueue1 (pwr->dqueue, &wn->rd_guid, &sc, rres2); - } - break; + else + { + if (*deferred_wakeup && *deferred_wakeup != pwr->dqueue) + { + dd_dqueue_enqueue_trigger (*deferred_wakeup); + *deferred_wakeup = NULL; + } + nn_dqueue_enqueue1 (pwr->dqueue, &wn->rd_guid, &sc, rres2); + } + break; + } } } } @@ -2277,7 +2443,8 @@ static void drop_oversize (struct receiver_state *rst, struct nn_rmsg *rmsg, con /* No proxy writer means nothing really gets done with, unless it is SPDP. SPDP is periodic, so oversize discovery packets would cause periodic warnings. */ - if (msg->writerId.u == NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER) + if ((msg->writerId.u == NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER) || + (msg->writerId.u == NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER)) { DDS_CWARNING (&rst->gv->logconfig, "dropping oversize (%"PRIu32" > %"PRIu32") SPDP sample %"PRId64" from remote writer "PGUIDFMT"\n", sampleinfo->size, rst->gv->config.max_sample_size, sampleinfo->seq, @@ -2317,7 +2484,7 @@ static void drop_oversize (struct receiver_state *rst, struct nn_rmsg *rmsg, con } } -static int handle_Data (struct receiver_state *rst, ddsrt_etime_t tnow, struct nn_rmsg *rmsg, const Data_t *msg, size_t size, struct nn_rsample_info *sampleinfo, unsigned char *datap, struct nn_dqueue **deferred_wakeup) +static int handle_Data (struct receiver_state *rst, ddsrt_etime_t tnow, struct nn_rmsg *rmsg, const Data_t *msg, size_t size, struct nn_rsample_info *sampleinfo, unsigned char *datap, struct nn_dqueue **deferred_wakeup, SubmessageKind_t prev_smid) { RSTTRACE ("DATA("PGUIDFMT" -> "PGUIDFMT" #%"PRId64, PGUIDPREFIX (rst->src_guid_prefix), msg->x.writerId.u, @@ -2329,6 +2496,15 @@ static int handle_Data (struct receiver_state *rst, ddsrt_etime_t tnow, struct n return 1; } + if (sampleinfo->pwr) + { + if (!validate_msg_decoding(&(sampleinfo->pwr->e), &(sampleinfo->pwr->c), sampleinfo->pwr->c.proxypp, rst, prev_smid)) + { + RSTTRACE (" clear submsg from protected src "PGUIDFMT")", PGUID (sampleinfo->pwr->e.guid)); + return 1; + } + } + if (sampleinfo->size > rst->gv->config.max_sample_size) drop_oversize (rst, rmsg, &msg->x, sampleinfo); else @@ -2349,10 +2525,14 @@ static int handle_Data (struct receiver_state *rst, ddsrt_etime_t tnow, struct n switch (msg->x.writerId.u) { case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER: + /* fall through */ + case NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER: /* SPDP needs special treatment: there are no proxy writers for it and we accept data from unknown sources */ handle_SPDP (sampleinfo, rdata); break; case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER: + /* fall through */ + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER: /* Handle PMD as a regular message, but without renewing the leases on proxypp */ renew_manbypp_lease = false; /* fall through */ @@ -2369,7 +2549,7 @@ static int handle_Data (struct receiver_state *rst, ddsrt_etime_t tnow, struct n return 1; } -static int handle_DataFrag (struct receiver_state *rst, ddsrt_etime_t tnow, struct nn_rmsg *rmsg, const DataFrag_t *msg, size_t size, struct nn_rsample_info *sampleinfo, unsigned char *datap, struct nn_dqueue **deferred_wakeup) +static int handle_DataFrag (struct receiver_state *rst, ddsrt_etime_t tnow, struct nn_rmsg *rmsg, const DataFrag_t *msg, size_t size, struct nn_rsample_info *sampleinfo, unsigned char *datap, struct nn_dqueue **deferred_wakeup, SubmessageKind_t prev_smid) { RSTTRACE ("DATAFRAG("PGUIDFMT" -> "PGUIDFMT" #%"PRId64"/[%u..%u]", PGUIDPREFIX (rst->src_guid_prefix), msg->x.writerId.u, @@ -2382,6 +2562,15 @@ static int handle_DataFrag (struct receiver_state *rst, ddsrt_etime_t tnow, stru return 1; } + if (sampleinfo->pwr) + { + if (!validate_msg_decoding(&(sampleinfo->pwr->e), &(sampleinfo->pwr->c), sampleinfo->pwr->c.proxypp, rst, prev_smid)) + { + RSTTRACE (" clear submsg from protected src "PGUIDFMT")", PGUID (sampleinfo->pwr->e.guid)); + return 1; + } + } + if (sampleinfo->size > rst->gv->config.max_sample_size) drop_oversize (rst, rmsg, &msg->x, sampleinfo); else @@ -2395,11 +2584,15 @@ static int handle_DataFrag (struct receiver_state *rst, ddsrt_etime_t tnow, stru switch (msg->x.writerId.u) { case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER: + /* fall through */ + case NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER: DDS_CWARNING (&rst->gv->logconfig, "DATAFRAG("PGUIDFMT" #%"PRId64" -> "PGUIDFMT") - fragmented builtin data not yet supported\n", PGUIDPREFIX (rst->src_guid_prefix), msg->x.writerId.u, fromSN (msg->x.writerSN), PGUIDPREFIX (rst->dst_guid_prefix), msg->x.readerId.u); return 1; case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER: + /* fall through */ + case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER: renew_manbypp_lease = false; } } @@ -2590,7 +2783,8 @@ static int handle_submsg_sequence unsigned char * const msg /* NOT const - we may byteswap it */, const size_t len, unsigned char * submsg /* aliases somewhere in msg */, - struct nn_rmsg * const rmsg + struct nn_rmsg * const rmsg, + bool rtps_encoded /* indicate if the message was rtps encoded */ ) { const char *state; @@ -2602,6 +2796,7 @@ static int handle_submsg_sequence size_t submsg_size = 0; unsigned char * end = msg + len; struct nn_dqueue *deferred_wakeup = NULL; + SubmessageKind_t prev_smid = SMID_PAD; /* Receiver state is dynamically allocated with lifetime bound to the message. Updates cause a new copy to be created if the @@ -2623,6 +2818,7 @@ static int handle_submsg_sequence false at any time. That's ok: it's real purpose is to filter out discovery data accidentally sent by Cloud */ rst->forme = 1; + rst->rtps_encoded = rtps_encoded; rst->vendor = hdr->vendorid; rst->protocol_version = hdr->version; rst->srcloc = *srcloc; @@ -2684,14 +2880,14 @@ static int handle_submsg_sequence state = "parse:acknack"; if (!valid_AckNack (rst, &sm->acknack, submsg_size, byteswap)) goto malformed; - handle_AckNack (rst, tnowE, &sm->acknack, ts_for_latmeas ? timestamp : DDSRT_WCTIME_INVALID); + handle_AckNack (rst, tnowE, &sm->acknack, ts_for_latmeas ? timestamp : DDSRT_WCTIME_INVALID, prev_smid); ts_for_latmeas = 0; break; case SMID_HEARTBEAT: state = "parse:heartbeat"; if (!valid_Heartbeat (&sm->heartbeat, submsg_size, byteswap)) goto malformed; - handle_Heartbeat (rst, tnowE, rmsg, &sm->heartbeat, ts_for_latmeas ? timestamp : DDSRT_WCTIME_INVALID); + handle_Heartbeat (rst, tnowE, rmsg, &sm->heartbeat, ts_for_latmeas ? timestamp : DDSRT_WCTIME_INVALID, prev_smid); ts_for_latmeas = 0; break; case SMID_GAP: @@ -2703,7 +2899,7 @@ static int handle_submsg_sequence rst after inserting the gap in the admin. */ if (!valid_Gap (&sm->gap, submsg_size, byteswap)) goto malformed; - handle_Gap (rst, tnowE, rmsg, &sm->gap); + handle_Gap (rst, tnowE, rmsg, &sm->gap, prev_smid); ts_for_latmeas = 0; break; case SMID_INFO_TS: @@ -2747,27 +2943,37 @@ static int handle_submsg_sequence state = "parse:nackfrag"; if (!valid_NackFrag (&sm->nackfrag, submsg_size, byteswap)) goto malformed; - handle_NackFrag (rst, tnowE, &sm->nackfrag); + handle_NackFrag (rst, tnowE, &sm->nackfrag, prev_smid); ts_for_latmeas = 0; break; case SMID_HEARTBEAT_FRAG: state = "parse:heartbeatfrag"; if (!valid_HeartbeatFrag (&sm->heartbeatfrag, submsg_size, byteswap)) goto malformed; - handle_HeartbeatFrag (rst, tnowE, &sm->heartbeatfrag); + handle_HeartbeatFrag (rst, tnowE, &sm->heartbeatfrag, prev_smid); ts_for_latmeas = 0; break; case SMID_DATA_FRAG: state = "parse:datafrag"; { struct nn_rsample_info sampleinfo; + uint32_t datasz = 0; unsigned char *datap; + size_t submsg_len = submsg_size; /* valid_DataFrag does not validate the payload */ - if (!valid_DataFrag (rst, rmsg, &sm->datafrag, submsg_size, byteswap, &sampleinfo, &datap)) + if (!valid_DataFrag (rst, rmsg, &sm->datafrag, submsg_size, byteswap, &sampleinfo, &datap, &datasz)) goto malformed; + /* This only decodes the payload when needed (possibly reducing the submsg size). */ + if (!decode_DataFrag (rst->gv, &sampleinfo, datap, datasz, &submsg_len)) + goto malformed; + /* Set the sample bswap according to the payload info (only first fragment has proper header). */ + if (sm->datafrag.fragmentStartingNum == 1) { + if (!set_sampleinfo_bswap(&sampleinfo, (struct CDRHeader *)datap)) + goto malformed; + } sampleinfo.timestamp = timestamp; sampleinfo.reception_timestamp = tnowWC; - handle_DataFrag (rst, tnowE, rmsg, &sm->datafrag, submsg_size, &sampleinfo, datap, &deferred_wakeup); + handle_DataFrag (rst, tnowE, rmsg, &sm->datafrag, submsg_len, &sampleinfo, datap, &deferred_wakeup, prev_smid); rst_live = 1; ts_for_latmeas = 0; } @@ -2777,12 +2983,20 @@ static int handle_submsg_sequence { struct nn_rsample_info sampleinfo; unsigned char *datap; + uint32_t datasz = 0; + size_t submsg_len = submsg_size; /* valid_Data does not validate the payload */ - if (!valid_Data (rst, rmsg, &sm->data, submsg_size, byteswap, &sampleinfo, &datap)) + if (!valid_Data (rst, rmsg, &sm->data, submsg_size, byteswap, &sampleinfo, &datap, &datasz)) + goto malformed; + /* This only decodes the payload when needed (possibly reducing the submsg size). */ + if (!decode_Data (rst->gv, &sampleinfo, datap, datasz, &submsg_len)) + goto malformed; + /* Set the sample bswap according to the payload info. */ + if (!set_sampleinfo_bswap(&sampleinfo, (struct CDRHeader *)datap)) goto malformed; sampleinfo.timestamp = timestamp; sampleinfo.reception_timestamp = tnowWC; - handle_Data (rst, tnowE, rmsg, &sm->data, submsg_size, &sampleinfo, datap, &deferred_wakeup); + handle_Data (rst, tnowE, rmsg, &sm->data, submsg_len, &sampleinfo, datap, &deferred_wakeup, prev_smid); rst_live = 1; ts_for_latmeas = 0; } @@ -2803,6 +3017,38 @@ static int handle_submsg_sequence GVTRACE ("ENTITY_ID"); break; } + case SMID_SEC_PREFIX: + state = "parse:sec_prefix"; + { + GVTRACE ("SEC_PREFIX "); + if (!decode_SecPrefix(rst, submsg, submsg_size, end, &rst->src_guid_prefix, &rst->dst_guid_prefix, byteswap)) + goto malformed; + } + break; + case SMID_SEC_BODY: + { + /* Ignore: because it should have been handled by SMID_SEC_PREFIX. */ + GVTRACE ("SEC_BODY"); + } + break; + case SMID_SEC_POSTFIX: + { + /* Ignore: because it should have been handled by SMID_SEC_PREFIX. */ + GVTRACE ("SEC_POSTFIX"); + } + break; + case SMID_SRTPS_PREFIX: + { + /* Ignore: it should already have been handled. */ + GVTRACE ("SRTPS_PREFIX"); + } + break; + case SMID_SRTPS_POSTFIX: + { + /* Ignore: it should already have been handled. */ + GVTRACE ("SRTPS_POSTFIX"); + } + break; default: state = "parse:undefined"; GVTRACE ("UNDEFINED(%x)", sm->smhdr.submessageId); @@ -2833,6 +3079,7 @@ static int handle_submsg_sequence ts_for_latmeas = 0; break; } + prev_smid = state_smkind; submsg += submsg_size; GVTRACE ("\n"); } @@ -2971,8 +3218,16 @@ static bool do_packet (struct thread_state1 * const ts1, struct ddsi_domaingv *g GVTRACE ("HDR(%"PRIx32":%"PRIx32":%"PRIx32" vendor %d.%d) len %lu from %s\n", PGUIDPREFIX (hdr->guid_prefix), hdr->vendorid.id[0], hdr->vendorid.id[1], (unsigned long) sz, addrstr); } - - handle_submsg_sequence (ts1, gv, conn, &srcloc, ddsrt_time_wallclock (), ddsrt_time_elapsed (), &hdr->guid_prefix, guidprefix, buff, (size_t) sz, buff + RTPS_MESSAGE_HEADER_SIZE, rmsg); + nn_rtps_msg_state_t res = decode_rtps_message (ts1, gv, &rmsg, &hdr, &buff, &sz, rbpool, conn->m_stream); + if (res != NN_RTPS_MSG_STATE_ERROR) + { + handle_submsg_sequence (ts1, gv, conn, &srcloc, ddsrt_time_wallclock (), ddsrt_time_elapsed (), &hdr->guid_prefix, guidprefix, buff, (size_t) sz, buff + RTPS_MESSAGE_HEADER_SIZE, rmsg, res == NN_RTPS_MSG_STATE_ENCODED); + } + else + { + /* drop message */ + sz = 1; + } } } nn_rmsg_commit (rmsg); diff --git a/src/core/ddsi/src/q_transmit.c b/src/core/ddsi/src/q_transmit.c index 8cd0508..4a52fdb 100644 --- a/src/core/ddsi/src/q_transmit.c +++ b/src/core/ddsi/src/q_transmit.c @@ -10,6 +10,7 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ #include +#include #include #include "dds/ddsrt/heap.h" @@ -31,10 +32,12 @@ #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_unused.h" #include "dds/ddsi/q_hbcontrol.h" +#include "dds/ddsi/q_receive.h" #include "dds/ddsi/q_lease.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds/ddsi/ddsi_serdata.h" #include "dds/ddsi/ddsi_sertopic.h" +#include "dds/ddsi/ddsi_security_omg.h" #include "dds/ddsi/sysdeps.h" #include "dds__whc.h" @@ -141,7 +144,7 @@ struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const stru assert (wr->reliable); assert (hbansreq >= 0); - if ((msg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid.prefix, sizeof (InfoTS_t) + sizeof (Heartbeat_t), NN_XMSG_KIND_CONTROL)) == NULL) + if ((msg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid, wr->c.pp, sizeof (InfoTS_t) + sizeof (Heartbeat_t), NN_XMSG_KIND_CONTROL)) == NULL) /* out of memory at worst slows down traffic */ return NULL; @@ -219,6 +222,13 @@ struct nn_xmsg *writer_hbcontrol_create_heartbeat (struct writer *wr, const stru add_Heartbeat (msg, wr, whcst, hbansreq, 0, prd_guid->entityid, issync); } + /* It is possible that the encoding removed the submessage(s). */ + if (nn_xmsg_size(msg) == 0) + { + nn_xmsg_free (msg); + msg = NULL; + } + writer_hbcontrol_note_hb (wr, tnow, hbansreq); return msg; } @@ -308,12 +318,53 @@ struct nn_xmsg *writer_hbcontrol_piggyback (struct writer *wr, const struct whc_ (hbc->tsched.v == DDS_NEVER) ? INFINITY : (double) (hbc->tsched.v - tnow.v) / 1e9, ddsrt_avl_is_empty (&wr->readers) ? -1 : root_rdmatch (wr)->min_seq, ddsrt_avl_is_empty (&wr->readers) || root_rdmatch (wr)->all_have_replied_to_hb ? "" : "!", - whcst->max_seq, writer_read_seq_xmit (wr)); + whcst->max_seq, writer_read_seq_xmit(wr)); } return msg; } +#ifdef DDSI_INCLUDE_SECURITY +struct nn_xmsg *writer_hbcontrol_p2p(struct writer *wr, const struct whc_state *whcst, int hbansreq, struct proxy_reader *prd) +{ + struct ddsi_domaingv const * const gv = wr->e.gv; + struct nn_xmsg *msg; + + ASSERT_MUTEX_HELD (&wr->e.lock); + assert (wr->reliable); + + if ((msg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid, wr->c.pp, sizeof (InfoTS_t) + sizeof (Heartbeat_t), NN_XMSG_KIND_CONTROL)) == NULL) + return NULL; + + ETRACE (wr, "writer_hbcontrol_p2p: wr "PGUIDFMT" unicasting to prd "PGUIDFMT" ", PGUID (wr->e.guid), PGUID (prd->e.guid)); + ETRACE (wr, "(rel-prd %d seq-eq-max %d seq %"PRId64" maxseq %"PRId64")\n", + wr->num_reliable_readers, + ddsrt_avl_is_empty (&wr->readers) ? -1 : root_rdmatch (wr)->num_reliable_readers_where_seq_equals_max, + wr->seq, + ddsrt_avl_is_empty (&wr->readers) ? (int64_t) -1 : root_rdmatch (wr)->max_seq); + + /* set the destination explicitly to the unicast destination and the fourth + param of add_Heartbeat needs to be the guid of the reader */ + if (nn_xmsg_setdstPRD (msg, prd) < 0) + { + nn_xmsg_free (msg); + return NULL; + } +#ifdef DDSI_INCLUDE_NETWORK_PARTITIONS + nn_xmsg_setencoderid (msg, wr->partition_id); +#endif + add_Heartbeat (msg, wr, whcst, hbansreq, 0, prd->e.guid.entityid, 1); + + if (nn_xmsg_size(msg) == 0) + { + nn_xmsg_free (msg); + msg = NULL; + } + + return msg; +} +#endif + void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_state *whcst, int hbansreq, int hbliveliness, ddsi_entityid_t dst, int issync) { struct ddsi_domaingv const * const gv = wr->e.gv; @@ -383,6 +434,7 @@ void add_Heartbeat (struct nn_xmsg *msg, struct writer *wr, const struct whc_sta hb->count = ++wr->hbcount; nn_xmsg_submsg_setnext (msg, sm_marker); + encode_datawriter_submsg(msg, sm_marker, wr); } static dds_return_t create_fragment_message_simple (struct writer *wr, seqno_t seq, struct ddsi_serdata *serdata, struct nn_xmsg **pmsg) @@ -415,7 +467,7 @@ static dds_return_t create_fragment_message_simple (struct writer *wr, seqno_t s ASSERT_MUTEX_HELD (&wr->e.lock); /* INFO_TS: 12 bytes, Data_t: 24 bytes, expected inline QoS: 32 => should be single chunk */ - if ((*pmsg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid.prefix, sizeof (InfoTimestamp_t) + sizeof (Data_t) + expected_inline_qos_size, NN_XMSG_KIND_DATA)) == NULL) + if ((*pmsg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid, wr->c.pp, sizeof (InfoTimestamp_t) + sizeof (Data_t) + expected_inline_qos_size, NN_XMSG_KIND_DATA)) == NULL) return DDS_RETCODE_OUT_OF_RESOURCES; #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS @@ -441,7 +493,7 @@ static dds_return_t create_fragment_message_simple (struct writer *wr, seqno_t s /* Adding parameters means potential reallocing, so sm, ddcmn now likely become invalid */ if (wr->include_keyhash) - nn_xmsg_addpar_keyhash (*pmsg, serdata); + nn_xmsg_addpar_keyhash (*pmsg, serdata, wr->force_md5_keyhash); if (serdata->statusinfo) nn_xmsg_addpar_statusinfo (*pmsg, serdata->statusinfo); if (nn_xmsg_addpar_sentinel_ifparam (*pmsg) > 0) @@ -452,9 +504,9 @@ static dds_return_t create_fragment_message_simple (struct writer *wr, seqno_t s #if TEST_KEYHASH if (serdata->kind != SDK_KEY || !wr->include_keyhash) - nn_xmsg_serdata (*pmsg, serdata, 0, ddsi_serdata_size (serdata)); + nn_xmsg_serdata (*pmsg, serdata, 0, ddsi_serdata_size (serdata), wr); #else - nn_xmsg_serdata (*pmsg, serdata, 0, ddsi_serdata_size (serdata)); + nn_xmsg_serdata (*pmsg, serdata, 0, ddsi_serdata_size (serdata), wr); #endif nn_xmsg_submsg_setnext (*pmsg, sm_marker); return 0; @@ -501,7 +553,7 @@ dds_return_t create_fragment_message (struct writer *wr, seqno_t seq, const stru fragging = (gv->config.fragment_size < size); /* INFO_TS: 12 bytes, DataFrag_t: 36 bytes, expected inline QoS: 32 => should be single chunk */ - if ((*pmsg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid.prefix, sizeof (InfoTimestamp_t) + sizeof (DataFrag_t) + expected_inline_qos_size, xmsg_kind)) == NULL) + if ((*pmsg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid, wr->c.pp, sizeof (InfoTimestamp_t) + sizeof (DataFrag_t) + expected_inline_qos_size, xmsg_kind)) == NULL) return DDS_RETCODE_OUT_OF_RESOURCES; #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS @@ -608,7 +660,7 @@ dds_return_t create_fragment_message (struct writer *wr, seqno_t seq, const stru /* Adding parameters means potential reallocing, so sm, ddcmn now likely become invalid */ if (wr->include_keyhash) { - nn_xmsg_addpar_keyhash (*pmsg, serdata); + nn_xmsg_addpar_keyhash (*pmsg, serdata, wr->force_md5_keyhash); } if (serdata->statusinfo) { @@ -622,7 +674,7 @@ dds_return_t create_fragment_message (struct writer *wr, seqno_t seq, const stru } } - nn_xmsg_serdata (*pmsg, serdata, fragstart, fraglen); + nn_xmsg_serdata (*pmsg, serdata, fragstart, fraglen, wr); nn_xmsg_submsg_setnext (*pmsg, sm_marker); #if 0 GVTRACE ("queue data%s "PGUIDFMT" #%lld/%u[%u..%u)\n", @@ -630,6 +682,15 @@ dds_return_t create_fragment_message (struct writer *wr, seqno_t seq, const stru seq, fragnum+1, fragstart, fragstart + fraglen); #endif + encode_datawriter_submsg(*pmsg, sm_marker, wr); + + /* It is possible that the encoding removed the submessage. + * If there is no content, free the message. */ + if (nn_xmsg_size(*pmsg) == 0) { + nn_xmsg_free (*pmsg); + *pmsg = NULL; + } + return ret; } @@ -639,7 +700,7 @@ static void create_HeartbeatFrag (struct writer *wr, seqno_t seq, unsigned fragn struct nn_xmsg_marker sm_marker; HeartbeatFrag_t *hbf; ASSERT_MUTEX_HELD (&wr->e.lock); - if ((*pmsg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid.prefix, sizeof (HeartbeatFrag_t), NN_XMSG_KIND_CONTROL)) == NULL) + if ((*pmsg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid, wr->c.pp, sizeof (HeartbeatFrag_t), NN_XMSG_KIND_CONTROL)) == NULL) return; /* ignore out-of-memory: HeartbeatFrag is only advisory anyway */ #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS nn_xmsg_setencoderid (*pmsg, wr->partition_id); @@ -668,6 +729,15 @@ static void create_HeartbeatFrag (struct writer *wr, seqno_t seq, unsigned fragn hbf->count = ++wr->hbfragcount; nn_xmsg_submsg_setnext (*pmsg, sm_marker); + encode_datawriter_submsg(*pmsg, sm_marker, wr); + + /* It is possible that the encoding removed the submessage. + * If there is no content, free the message. */ + if (nn_xmsg_size(*pmsg) == 0) + { + nn_xmsg_free(*pmsg); + *pmsg = NULL; + } } dds_return_t write_hb_liveliness (struct ddsi_domaingv * const gv, struct ddsi_guid *wr_guid, struct nn_xpack *xp) @@ -690,7 +760,7 @@ dds_return_t write_hb_liveliness (struct ddsi_domaingv * const gv, struct ddsi_g else if (wr->xqos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_TOPIC && wr->lease != NULL) lease_renew (wr->lease, ddsrt_time_elapsed()); - if ((msg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid.prefix, sizeof (InfoTS_t) + sizeof (Heartbeat_t), NN_XMSG_KIND_CONTROL)) == NULL) + if ((msg = nn_xmsg_new (gv->xmsgpool, &wr->e.guid, wr->c.pp, sizeof (InfoTS_t) + sizeof (Heartbeat_t), NN_XMSG_KIND_CONTROL)) == NULL) return DDS_RETCODE_OUT_OF_RESOURCES; ddsrt_mutex_lock (&wr->e.lock); nn_xmsg_setdstN (msg, wr->as, wr->as_group); @@ -796,7 +866,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); @@ -896,8 +966,6 @@ static int insert_sample_in_whc (struct writer *wr, seqno_t seq, struct ddsi_pli { char ppbuf[1024]; int tmp; - const char *tname = wr->topic ? wr->topic->name : "(null)"; - const char *ttname = wr->topic ? wr->topic->type_name : "(null)"; ppbuf[0] = '\0'; tmp = sizeof (ppbuf) - 1; if (wr->e.gv->logconfig.c.mask & DDS_LC_CONTENT) @@ -905,7 +973,7 @@ static int insert_sample_in_whc (struct writer *wr, seqno_t seq, struct ddsi_pli ETRACE (wr, "write_sample "PGUIDFMT" #%"PRId64, PGUID (wr->e.guid), seq); if (plist != 0 && (plist->present & PP_COHERENT_SET)) ETRACE (wr, " C#%"PRId64"", fromSN (plist->coherent_set_seqno)); - ETRACE (wr, ": ST%"PRIu32" %s/%s:%s%s\n", serdata->statusinfo, tname, ttname, ppbuf, tmp < (int) sizeof (ppbuf) ? "" : " (trunc)"); + ETRACE (wr, ": ST%"PRIu32" %s/%s:%s%s\n", serdata->statusinfo, wr->topic->name, wr->topic->type_name, ppbuf, tmp < (int) sizeof (ppbuf) ? "" : " (trunc)"); } assert (wr->reliable || have_reliable_subs (wr) == 0); @@ -945,7 +1013,9 @@ static int insert_sample_in_whc (struct writer *wr, seqno_t seq, struct ddsi_pli } #ifndef NDEBUG - if (wr->e.guid.entityid.u == NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER && !is_local_orphan_endpoint (&wr->e)) + if (((wr->e.guid.entityid.u == NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER) || + (wr->e.guid.entityid.u == NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER)) && + !is_local_orphan_endpoint (&wr->e)) { struct whc_state whcst; whc_get_state(wr->whc, &whcst); @@ -1083,6 +1153,74 @@ static int maybe_grow_whc (struct writer *wr) return 0; } +int write_sample_p2p_wrlock_held(struct writer *wr, seqno_t seq, struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk, struct proxy_reader *prd) +{ + struct ddsi_domaingv * const gv = wr->e.gv; + int r = 0; + ddsrt_mtime_t tnow; + int rexmit = 1; + struct wr_prd_match *wprd = NULL; + seqno_t gseq; + struct nn_xmsg *gap = NULL; + + tnow = ddsrt_time_monotonic (); + serdata->twrite = tnow; + serdata->timestamp = ddsrt_time_wallclock (); + + + if (prd->filter) + { + if ((wprd = ddsrt_avl_lookup (&wr_readers_treedef, &wr->readers, &prd->e.guid)) != NULL) + { + if (wprd->seq == MAX_SEQ_NUMBER) + goto prd_is_deleting; + + rexmit = prd->filter(wr, prd, serdata); + /* determine if gap has to added */ + if (rexmit) + { + struct nn_gap_info gi; + + GVLOG (DDS_LC_DISCOVERY, "send filtered "PGUIDFMT" last_seq=%"PRIu64" seq=%"PRIu64"\n", PGUID (wr->e.guid), wprd->seq, seq); + + nn_gap_info_init(&gi); + for (gseq = wprd->seq + 1; gseq < seq; gseq++) + { + struct whc_borrowed_sample sample; + if (whc_borrow_sample (wr->whc, seq, &sample)) + { + if (prd->filter(wr, prd, sample.serdata) == 0) + { + nn_gap_info_update(wr->e.gv, &gi, gseq); + } + whc_return_sample (wr->whc, &sample, false); + } + } + gap = nn_gap_info_create_gap(wr, prd, &gi); + } + wprd->last_seq = seq; + } + } + + if ((r = insert_sample_in_whc (wr, seq, plist, serdata, tk)) >= 0) + { + enqueue_sample_wrlock_held (wr, seq, plist, serdata, prd, 1); + + if (gap) + qxev_msg (wr->evq, gap); + + if (wr->heartbeat_xevent) + writer_hbcontrol_note_asyncwrite(wr, tnow); + } + else if (gap) + { + nn_xmsg_free (gap); + } + +prd_is_deleting: + return r; +} + static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack *xp, struct writer *wr, struct ddsi_plist *plist, struct ddsi_serdata *serdata, struct ddsi_tkmap_instance *tk, int end_of_txn, int gc_allowed) { struct ddsi_domaingv const * const gv = wr->e.gv; @@ -1099,13 +1237,11 @@ static int write_sample_eot (struct thread_state1 * const ts1, struct nn_xpack * { char ppbuf[1024]; int tmp; - const char *tname = wr->topic ? wr->topic->name : "(null)"; - const char *ttname = wr->topic ? wr->topic->type_name : "(null)"; ppbuf[0] = '\0'; tmp = sizeof (ppbuf) - 1; GVWARNING ("dropping oversize (%"PRIu32" > %"PRIu32") sample from local writer "PGUIDFMT" %s/%s:%s%s\n", ddsi_serdata_size (serdata), gv->config.max_sample_size, - PGUID (wr->e.guid), tname, ttname, ppbuf, + PGUID (wr->e.guid), wr->topic->name, wr->topic->type_name, ppbuf, tmp < (int) sizeof (ppbuf) ? "" : " (trunc)"); r = DDS_RETCODE_BAD_PARAMETER; goto drop; diff --git a/src/core/ddsi/src/q_xevent.c b/src/core/ddsi/src/q_xevent.c index f5c9da8..443a9fc 100644 --- a/src/core/ddsi/src/q_xevent.c +++ b/src/core/ddsi/src/q_xevent.c @@ -39,6 +39,7 @@ #include "dds/ddsi/q_entity.h" #include "dds/ddsi/ddsi_serdata.h" #include "dds/ddsi/ddsi_serdata_default.h" +#include "dds/ddsi/ddsi_security_omg.h" #include "dds/ddsi/ddsi_tkmap.h" #include "dds/ddsi/ddsi_pmd.h" #include "dds__whc.h" @@ -102,7 +103,9 @@ enum xeventkind_nt { XEVK_MSG, XEVK_MSG_REXMIT, - XEVK_ENTITYID + XEVK_MSG_REXMIT_NOMERGE, + XEVK_ENTITYID, + XEVK_NT_CALLBACK }; struct untimed_listelem { @@ -124,11 +127,15 @@ struct xevent_nt struct nn_xmsg *msg; size_t queued_rexmit_bytes; ddsrt_avl_node_t msg_avlnode; - } msg_rexmit; + } msg_rexmit; /* and msg_rexmit_nomerge */ struct { /* xmsg is self-contained / relies on reference counts */ struct nn_xmsg *msg; } entityid; + struct { + void (*cb) (void *arg); + void *arg; + } callback; } u; }; @@ -172,7 +179,7 @@ static void update_rexmit_counts (struct xeventq *evq, struct xevent_nt *ev) #if 0 EVQTRACE ("ZZZ(%p,%"PRIuSIZE")", (void *) ev, ev->u.msg_rexmit.queued_rexmit_bytes); #endif - assert (ev->kind == XEVK_MSG_REXMIT); + assert (ev->kind == XEVK_MSG_REXMIT || ev->kind == XEVK_MSG_REXMIT_NOMERGE); assert (ev->u.msg_rexmit.queued_rexmit_bytes <= evq->queued_rexmit_bytes); assert (evq->queued_rexmit_msgs > 0); evq->queued_rexmit_bytes -= ev->u.msg_rexmit.queued_rexmit_bytes; @@ -184,7 +191,7 @@ static void trace_msg (struct xeventq *evq, const char *func, const struct nn_xm { if (dds_get_log_mask() & DDS_LC_TRACE) { - nn_guid_t wrguid; + ddsi_guid_t wrguid; seqno_t wrseq; nn_fragment_number_t wrfragid; nn_xmsg_guid_seq_fragid (m, &wrguid, &wrseq, &wrfragid); @@ -199,9 +206,20 @@ static void trace_msg (UNUSED_ARG (struct xeventq *evq), UNUSED_ARG (const char static struct xevent_nt *lookup_msg (struct xeventq *evq, struct nn_xmsg *msg) { - assert (nn_xmsg_kind (msg) == NN_XMSG_KIND_DATA_REXMIT); - trace_msg (evq, "lookup-msg", msg); - return ddsrt_avl_lookup (&msg_xevents_treedef, &evq->msg_xevents, msg); + switch (nn_xmsg_kind (msg)) + { + case NN_XMSG_KIND_CONTROL: + case NN_XMSG_KIND_DATA: + assert (0); + return NULL; + case NN_XMSG_KIND_DATA_REXMIT: + trace_msg (evq, "lookup-msg", msg); + return ddsrt_avl_lookup (&msg_xevents_treedef, &evq->msg_xevents, msg); + case NN_XMSG_KIND_DATA_REXMIT_NOMERGE: + return NULL; + } + assert (0); + return NULL; } static void remember_msg (struct xeventq *evq, struct xevent_nt *ev) @@ -601,7 +619,96 @@ static void handle_xevk_entityid (struct nn_xpack *xp, struct xevent_nt *ev) nn_xpack_addmsg (xp, ev->u.entityid.msg, 0); } -static void handle_xevk_heartbeat (struct nn_xpack *xp, struct xevent *ev, ddsrt_mtime_t tnow /* monotonic */) +#ifdef DDSI_INCLUDE_SECURITY +static int send_heartbeat_to_all_readers_check_and_sched (struct xevent *ev, struct writer *wr, const struct whc_state *whcst, ddsrt_mtime_t tnow, ddsrt_mtime_t *t_next) +{ + int send; + if (!writer_must_have_hb_scheduled (wr, whcst)) + { + wr->hbcontrol.tsched = DDSRT_MTIME_NEVER; + send = -1; + } + else if (!writer_hbcontrol_must_send (wr, whcst, tnow)) + { + wr->hbcontrol.tsched = ddsrt_mtime_add_duration (tnow, writer_hbcontrol_intv (wr, whcst, tnow)); + send = -1; + } + else + { + const int hbansreq = writer_hbcontrol_ack_required (wr, whcst, tnow); + wr->hbcontrol.tsched = ddsrt_mtime_add_duration (tnow, writer_hbcontrol_intv (wr, whcst, tnow)); + send = hbansreq; + } + + resched_xevent_if_earlier (ev, wr->hbcontrol.tsched); + *t_next = wr->hbcontrol.tsched; + return send; +} + +static void send_heartbeat_to_all_readers (struct nn_xpack *xp, struct xevent *ev, struct writer *wr, ddsrt_mtime_t tnow) +{ + struct whc_state whcst; + ddsrt_mtime_t t_next; + unsigned count = 0; + + ddsrt_mutex_lock (&wr->e.lock); + + whc_get_state(wr->whc, &whcst); + const int hbansreq = send_heartbeat_to_all_readers_check_and_sched (ev, wr, &whcst, tnow, &t_next); + if (hbansreq >= 0) + { + struct wr_prd_match *m; + struct ddsi_guid last_guid = { .prefix = {.u = {0,0,0}}, .entityid = {0} }; + + while ((m = ddsrt_avl_lookup_succ (&wr_readers_treedef, &wr->readers, &last_guid)) != NULL) + { + last_guid = m->prd_guid; + if (m->seq < m->last_seq) + { + struct proxy_reader *prd; + + prd = entidx_lookup_proxy_reader_guid(wr->e.gv->entity_index, &m->prd_guid); + if (prd) + { + ETRACE (wr, " heartbeat(wr "PGUIDFMT" rd "PGUIDFMT" %s) send, resched in %g s (min-ack %"PRId64", avail-seq %"PRId64")\n", + PGUID (wr->e.guid), + PGUID (m->prd_guid), + hbansreq ? "" : " final", + (double)(t_next.v - tnow.v) / 1e9, + m->seq, + m->last_seq); + + struct nn_xmsg *msg = writer_hbcontrol_p2p(wr, &whcst, hbansreq, prd); + if (msg != NULL) + { + ddsrt_mutex_unlock (&wr->e.lock); + nn_xpack_addmsg (xp, msg, 0); + ddsrt_mutex_lock (&wr->e.lock); + } + count++; + } + } + } + } + + if (count == 0) + { + ETRACE (wr, "heartbeat(wr "PGUIDFMT") suppressed, resched in %g s (min-ack %"PRId64"%s, avail-seq %"PRId64", xmit %"PRId64")\n", + PGUID (wr->e.guid), + (t_next.v == DDS_NEVER) ? INFINITY : (double)(t_next.v - tnow.v) / 1e9, + ddsrt_avl_is_empty (&wr->readers) ? (int64_t) -1 : ((struct wr_prd_match *) ddsrt_avl_root (&wr_readers_treedef, &wr->readers))->min_seq, + ddsrt_avl_is_empty (&wr->readers) || ((struct wr_prd_match *) ddsrt_avl_root (&wr_readers_treedef, &wr->readers))->all_have_replied_to_hb ? "" : "!", + whcst.max_seq, + writer_read_seq_xmit(wr)); + } + + ddsrt_mutex_unlock (&wr->e.lock); +} + + +#endif + +static void handle_xevk_heartbeat (struct nn_xpack *xp, struct xevent *ev, ddsrt_mtime_t tnow) { struct ddsi_domaingv const * const gv = ev->evq->gv; struct nn_xmsg *msg; @@ -616,6 +723,14 @@ static void handle_xevk_heartbeat (struct nn_xpack *xp, struct xevent *ev, ddsrt return; } +#ifdef DDSI_INCLUDE_SECURITY + if (wr->e.guid.entityid.u == NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER) + { + send_heartbeat_to_all_readers(xp, ev, wr, tnow); + return; + } +#endif + ddsrt_mutex_lock (&wr->e.lock); assert (wr->reliable); whc_get_state(wr->whc, &whcst); @@ -723,7 +838,7 @@ static void add_AckNack (struct nn_xmsg *msg, struct proxy_writer *pwr, struct p AckNack_t *an; struct nn_xmsg_marker sm_marker; uint32_t i, numbits; - seqno_t base; + seqno_t base, last_seq; DDSRT_STATIC_ASSERT ((NN_FRAGMENT_NUMBER_SET_MAX_BITS % 32) == 0); struct { @@ -738,7 +853,7 @@ static void add_AckNack (struct nn_xmsg *msg, struct proxy_writer *pwr, struct p /* if in sync, look at proxy writer status, else look at proxy-writer--reader match status */ - if (rwn->in_sync != PRMSS_OUT_OF_SYNC) + if (rwn->in_sync != PRMSS_OUT_OF_SYNC && !rwn->filtered) { reorder = pwr->reorder; if (!pwr->e.gv->config.late_ack_mode) @@ -756,6 +871,11 @@ static void add_AckNack (struct nn_xmsg *msg, struct proxy_writer *pwr, struct p bitmap_base = nn_reorder_next_seq (reorder); } + if (rwn->filtered) + last_seq = rwn->last_seq; + else + last_seq = pwr->last_seq; + an = nn_xmsg_append (msg, &sm_marker, ACKNACK_SIZE_MAX); nn_xmsg_submsg_init (msg, sm_marker, SMID_ACKNACK); an->readerId = nn_hton_entityid (rwn->rd_guid.entityid); @@ -763,7 +883,7 @@ static void add_AckNack (struct nn_xmsg *msg, struct proxy_writer *pwr, struct p /* Make bitmap; note that we've made sure to have room for the maximum bitmap size. */ - numbits = nn_reorder_nackmap (reorder, bitmap_base, pwr->last_seq, &an->readerSNState, an->bits, max_numbits, notail); + numbits = nn_reorder_nackmap (reorder, bitmap_base, last_seq, &an->readerSNState, an->bits, max_numbits, notail); base = fromSN (an->readerSNState.bitmap_base); /* Scan through bitmap, cutting it off at the first missing sample @@ -776,7 +896,7 @@ static void add_AckNack (struct nn_xmsg *msg, struct proxy_writer *pwr, struct p nackfrag_seq = base + i; if (!nn_bitset_isset (numbits, an->bits, i)) continue; - if (nackfrag_seq == pwr->last_seq) + if (nackfrag_seq == last_seq) fragnum = pwr->last_fragnum; else fragnum = UINT32_MAX; @@ -800,7 +920,7 @@ static void add_AckNack (struct nn_xmsg *msg, struct proxy_writer *pwr, struct p *nack_seq = (numbits > 0) ? base + numbits : 0; if (!pwr->have_seen_heartbeat) { /* We must have seen a heartbeat for us to consider setting FINAL */ - } else if (*nack_seq && base + numbits <= pwr->last_seq) { + } else if (*nack_seq && base + numbits <= last_seq) { /* If it's a NACK and it doesn't cover samples all the way up to the highest known sequence number, there's some reason to expect we may to do another round. For which we need a Heartbeat. @@ -828,6 +948,9 @@ static void add_AckNack (struct nn_xmsg *msg, struct proxy_writer *pwr, struct p base, an->readerSNState.numbits); for (uint32_t ui = 0; ui != an->readerSNState.numbits; ui++) ETRACE (pwr, "%c", nn_bitset_isset (numbits, an->bits, ui) ? '1' : '0'); + + /* Encode the sub-message when needed. */ + encode_datareader_submsg(msg, sm_marker, pwr, &rwn->rd_guid); } if (nackfrag_numbits > 0) @@ -858,12 +981,15 @@ static void add_AckNack (struct nn_xmsg *msg, struct proxy_writer *pwr, struct p for (uint32_t ui = 0; ui != nf->fragmentNumberState.numbits; ui++) ETRACE (pwr, "%c", nn_bitset_isset (nf->fragmentNumberState.numbits, nf->bits, ui) ? '1' : '0'); } + + /* Encode the sub-message when needed. */ + encode_datareader_submsg(msg, sm_marker, pwr, &rwn->rd_guid); } ETRACE (pwr, "\n"); } -static void handle_xevk_acknack (UNUSED_ARG (struct nn_xpack *xp), struct xevent *ev, ddsrt_mtime_t tnow) +static void handle_xevk_acknack (struct nn_xpack *xp, struct xevent *ev, ddsrt_mtime_t tnow) { /* FIXME: ought to keep track of which NACKs are being generated in response to a Heartbeat. There is no point in having multiple @@ -894,10 +1020,20 @@ static void handle_xevk_acknack (UNUSED_ARG (struct nn_xpack *xp), struct xevent if (addrset_any_uc (pwr->c.as, &loc) || addrset_any_mc (pwr->c.as, &loc)) { + struct participant *pp = NULL; seqno_t nack_seq; - if ((msg = nn_xmsg_new (gv->xmsgpool, &ev->u.acknack.rd_guid.prefix, ACKNACK_SIZE_MAX, NN_XMSG_KIND_CONTROL)) == NULL) + + 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; - nn_xmsg_setdst1 (msg, &ev->u.acknack.pwr_guid.prefix, &loc); + nn_xmsg_setdst1 (gv, msg, &ev->u.acknack.pwr_guid.prefix, &loc); if (gv->config.meas_hb_to_ack_latency && rwn->hb_timestamp.v) { /* If HB->ACK latency measurement is enabled, and we have a @@ -909,7 +1045,13 @@ static void handle_xevk_acknack (UNUSED_ARG (struct nn_xpack *xp), struct xevent rwn->hb_timestamp.v = 0; } add_AckNack (msg, pwr, rwn, &nack_seq); - if (nack_seq) + if (nn_xmsg_size(msg) == 0) + { + /* No AckNack added. */ + nn_xmsg_free(msg); + msg = NULL; + } + else if (nack_seq) { rwn->t_last_nack = tnow; rwn->seq_last_nack = nack_seq; @@ -971,15 +1113,9 @@ static bool resend_spdp_sample_by_guid_key (struct writer *wr, const ddsi_guid_t ddsi_plist_init_empty (&ps); ps.present |= PP_PARTICIPANT_GUID; ps.participant_guid = *guid; - struct nn_xmsg *mpayload = nn_xmsg_new (gv->xmsgpool, &guid->prefix, 0, NN_XMSG_KIND_DATA); - ddsi_plist_addtomsg (mpayload, &ps, ~(uint64_t)0, ~(uint64_t)0); - nn_xmsg_addpar_sentinel (mpayload); + struct ddsi_serdata *sd = ddsi_serdata_from_sample (gv->spdp_topic, SDK_KEY, &ps); ddsi_plist_fini (&ps); - struct ddsi_plist_sample plist_sample; - nn_xmsg_payload_to_plistsample (&plist_sample, PID_PARTICIPANT_GUID, mpayload); - struct ddsi_serdata *sd = ddsi_serdata_from_sample (gv->plist_topic, SDK_KEY, &plist_sample); struct whc_borrowed_sample sample; - nn_xmsg_free (mpayload); ddsrt_mutex_lock (&wr->e.lock); sample_found = whc_borrow_sample_key (wr->whc, sd, &sample); @@ -1208,11 +1344,15 @@ static void handle_individual_xevent_nt (struct xevent_nt *xev, struct nn_xpack handle_xevk_msg (xp, xev); break; case XEVK_MSG_REXMIT: + case XEVK_MSG_REXMIT_NOMERGE: handle_xevk_msg_rexmit (xp, xev); break; 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); } @@ -1369,7 +1509,19 @@ void qxev_msg (struct xeventq *evq, struct nn_xmsg *msg) ddsrt_mutex_unlock (&evq->lock); } -void qxev_prd_entityid (struct proxy_reader *prd, ddsi_guid_prefix_t *id) +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; struct nn_xmsg *msg; @@ -1379,10 +1531,10 @@ void qxev_prd_entityid (struct proxy_reader *prd, ddsi_guid_prefix_t *id) if (! gv->xevents->tev_conn->m_connless) { - msg = nn_xmsg_new (gv->xmsgpool, id, sizeof (EntityId_t), NN_XMSG_KIND_CONTROL); + msg = nn_xmsg_new (gv->xmsgpool, guid, NULL, sizeof (EntityId_t), NN_XMSG_KIND_CONTROL); if (nn_xmsg_setdstPRD (msg, prd) == 0) { - GVTRACE (" qxev_prd_entityid (%"PRIx32":%"PRIx32":%"PRIx32")\n", PGUIDPREFIX (*id)); + GVTRACE (" qxev_prd_entityid (%"PRIx32":%"PRIx32":%"PRIx32")\n", PGUIDPREFIX (guid->prefix)); nn_xmsg_add_entityid (msg); ddsrt_mutex_lock (&gv->xevents->lock); ev = qxev_common_nt (gv->xevents, XEVK_ENTITYID); @@ -1397,7 +1549,7 @@ void qxev_prd_entityid (struct proxy_reader *prd, ddsi_guid_prefix_t *id) } } -void qxev_pwr_entityid (struct proxy_writer *pwr, ddsi_guid_prefix_t *id) +void qxev_pwr_entityid (struct proxy_writer *pwr, const ddsi_guid_t *guid) { struct ddsi_domaingv * const gv = pwr->e.gv; struct nn_xmsg *msg; @@ -1407,10 +1559,10 @@ void qxev_pwr_entityid (struct proxy_writer *pwr, ddsi_guid_prefix_t *id) if (! pwr->evq->tev_conn->m_connless) { - msg = nn_xmsg_new (gv->xmsgpool, id, sizeof (EntityId_t), NN_XMSG_KIND_CONTROL); + msg = nn_xmsg_new (gv->xmsgpool, guid, NULL, sizeof (EntityId_t), NN_XMSG_KIND_CONTROL); if (nn_xmsg_setdstPWR (msg, pwr) == 0) { - GVTRACE (" qxev_pwr_entityid (%"PRIx32":%"PRIx32":%"PRIx32")\n", PGUIDPREFIX (*id)); + GVTRACE (" qxev_pwr_entityid (%"PRIx32":%"PRIx32":%"PRIx32")\n", PGUIDPREFIX (guid->prefix)); nn_xmsg_add_entityid (msg); ddsrt_mutex_lock (&pwr->evq->lock); ev = qxev_common_nt (pwr->evq, XEVK_ENTITYID); @@ -1432,7 +1584,7 @@ int qxev_msg_rexmit_wrlock_held (struct xeventq *evq, struct nn_xmsg *msg, int f struct xevent_nt *ev; assert (evq); - assert (nn_xmsg_kind (msg) == NN_XMSG_KIND_DATA_REXMIT); + assert (nn_xmsg_kind (msg) == NN_XMSG_KIND_DATA_REXMIT || nn_xmsg_kind (msg) == NN_XMSG_KIND_DATA_REXMIT_NOMERGE); ddsrt_mutex_lock (&evq->lock); if ((ev = lookup_msg (evq, msg)) != NULL && nn_xmsg_merge_rexmit_destinations_wrlock_held (gv, ev->u.msg_rexmit.msg, msg)) { @@ -1456,7 +1608,9 @@ int qxev_msg_rexmit_wrlock_held (struct xeventq *evq, struct nn_xmsg *msg, int f } else { - ev = qxev_common_nt (evq, XEVK_MSG_REXMIT); + const enum xeventkind_nt kind = + (nn_xmsg_kind (msg) == NN_XMSG_KIND_DATA_REXMIT) ? XEVK_MSG_REXMIT : XEVK_MSG_REXMIT_NOMERGE; + ev = qxev_common_nt (evq, kind); ev->u.msg_rexmit.msg = msg; ev->u.msg_rexmit.queued_rexmit_bytes = msg_size; evq->queued_rexmit_bytes += msg_size; diff --git a/src/core/ddsi/src/q_xmsg.c b/src/core/ddsi/src/q_xmsg.c index 7bc9993..70c70e5 100644 --- a/src/core/ddsi/src/q_xmsg.c +++ b/src/core/ddsi/src/q_xmsg.c @@ -41,6 +41,7 @@ #include "dds/ddsi/ddsi_entity_index.h" #include "dds/ddsi/q_freelist.h" #include "dds/ddsi/ddsi_serdata_default.h" +#include "dds/ddsi/ddsi_security_omg.h" #define NN_XMSG_MAX_ALIGN 8 #define NN_XMSG_CHUNK_SIZE 128 @@ -72,6 +73,11 @@ struct nn_xmsg { int have_params; struct ddsi_serdata *refd_payload; ddsrt_iovec_t refd_payload_iov; +#ifdef DDSI_INCLUDE_SECURITY + /* Used as pointer to contain encoded payload to which iov can alias. */ + unsigned char *refd_payload_encoded; + nn_msg_sec_info_t sec_info; +#endif int64_t maxdelay; #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS uint32_t encoderid; @@ -136,7 +142,7 @@ struct nn_xmsg_chain { struct nn_bw_limiter { uint32_t bandwidth; /*gv.config in bytes/s (0 = UNLIMITED)*/ int64_t balance; - nn_mtime_t last_update; + ddsrt_mtime_t last_update; }; #endif @@ -223,6 +229,9 @@ struct nn_xpack #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS uint32_t encoderId; #endif /* DDSI_INCLUDE_NETWORK_PARTITIONS */ +#ifdef DDSI_INCLUDE_SECURITY + nn_msg_sec_info_t sec_info; +#endif }; static size_t align4u (size_t x) @@ -283,6 +292,12 @@ static void nn_xmsg_reinit (struct nn_xmsg *m, enum nn_xmsg_kind kind) m->dstmode = NN_XMSG_DST_UNSET; m->kind = kind; m->maxdelay = 0; +#ifdef DDSI_INCLUDE_SECURITY + m->refd_payload_encoded = NULL; + m->sec_info.use_rtps_encoding = 0; + m->sec_info.src_pp_handle = 0; + m->sec_info.dst_pp_handle = 0; +#endif #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS m->encoderid = 0; #endif @@ -322,14 +337,29 @@ static struct nn_xmsg *nn_xmsg_allocnew (struct nn_xmsgpool *pool, size_t expect return m; } -struct nn_xmsg *nn_xmsg_new (struct nn_xmsgpool *pool, const ddsi_guid_prefix_t *src_guid_prefix, size_t expected_size, enum nn_xmsg_kind kind) +struct nn_xmsg *nn_xmsg_new (struct nn_xmsgpool *pool, const ddsi_guid_t *src_guid, struct participant *pp, size_t expected_size, enum nn_xmsg_kind kind) { struct nn_xmsg *m; if ((m = nn_freelist_pop (&pool->freelist)) != NULL) nn_xmsg_reinit (m, kind); else if ((m = nn_xmsg_allocnew (pool, expected_size, kind)) == NULL) return NULL; - m->data->src.guid_prefix = nn_hton_guid_prefix (*src_guid_prefix); + m->data->src.guid_prefix = nn_hton_guid_prefix (src_guid->prefix); + +#ifdef DDSI_INCLUDE_SECURITY + m->sec_info.use_rtps_encoding = 0; + if (pp && q_omg_participant_is_secure(pp)) + { + if (q_omg_security_is_local_rtps_protected(pp, src_guid->entityid)) + { + m->sec_info.use_rtps_encoding = 1; + m->sec_info.src_pp_handle = q_omg_security_get_local_participant_handle(pp); + } + } +#else + DDSRT_UNUSED_ARG(pp); +#endif + return m; } @@ -344,6 +374,9 @@ void nn_xmsg_free (struct nn_xmsg *m) struct nn_xmsgpool *pool = m->pool; if (m->refd_payload) ddsi_serdata_to_ser_unref (m->refd_payload, &m->refd_payload_iov); +#ifdef DDSI_INCLUDE_SECURITY + ddsrt_free(m->refd_payload_encoded); +#endif if (m->dstmode == NN_XMSG_DST_ALL) { unref_addrset (m->dstaddr.all.as); @@ -384,11 +417,19 @@ static int submsg_is_compatible (const struct nn_xmsg *msg, SubmessageKind_t smk case SMID_DATA: case SMID_DATA_FRAG: /* but data is strictly verboten */ return 0; + case SMID_SEC_BODY: + case SMID_SEC_PREFIX: + case SMID_SEC_POSTFIX: + case SMID_SRTPS_PREFIX: + case SMID_SRTPS_POSTFIX: + /* and the security sm are basically data. */ + return 0; } assert (0); break; case NN_XMSG_KIND_DATA: case NN_XMSG_KIND_DATA_REXMIT: + case NN_XMSG_KIND_DATA_REXMIT_NOMERGE: switch (smkind) { case SMID_PAD: @@ -405,6 +446,13 @@ static int submsg_is_compatible (const struct nn_xmsg *msg, SubmessageKind_t smk won't work for initial transmits, but those currently don't allow a readerId */ return msg->kindspecific.data.readerId_off == 0; + case SMID_SEC_BODY: + case SMID_SEC_PREFIX: + case SMID_SEC_POSTFIX: + case SMID_SRTPS_PREFIX: + case SMID_SRTPS_POSTFIX: + /* Just do the same as 'normal' data sm. */ + return msg->kindspecific.data.readerId_off == 0; case SMID_ACKNACK: case SMID_HEARTBEAT: case SMID_GAP: @@ -492,6 +540,97 @@ void nn_xmsg_submsg_setnext (struct nn_xmsg *msg, struct nn_xmsg_marker marker) ((unsigned)(msg->data->payload + msg->sz + plsize - (char *) hdr) - RTPS_SUBMESSAGE_HEADER_SIZE); } +#ifdef DDSI_INCLUDE_SECURITY + +size_t nn_xmsg_submsg_size (struct nn_xmsg *msg, struct nn_xmsg_marker marker) +{ + SubmessageHeader_t *hdr = (SubmessageHeader_t*)nn_xmsg_submsg_from_marker(msg, marker); + return align4u(hdr->octetsToNextHeader + sizeof(SubmessageHeader_t)); +} + +void nn_xmsg_submsg_remove(struct nn_xmsg *msg, struct nn_xmsg_marker sm_marker) +{ + /* Just reset the message size to the start of the current sub-message. */ + msg->sz = sm_marker.offset; + + /* Deleting the submessage means the readerId offset in a DATA_REXMIT message is no + longer valid. Converting the message kind to a _NOMERGE one ensures no subsequent + operation will assume its validity. */ + if (msg->kind == NN_XMSG_KIND_DATA_REXMIT) + msg->kind = NN_XMSG_KIND_DATA_REXMIT_NOMERGE; +} + +void nn_xmsg_submsg_replace(struct nn_xmsg *msg, struct nn_xmsg_marker sm_marker, unsigned char *new_submsg, size_t new_len) +{ + /* Size of current sub-message. */ + size_t old_len = msg->sz - sm_marker.offset; + + /* Adjust the message size to the new sub-message. */ + if (old_len < new_len) + { + nn_xmsg_append(msg, NULL, new_len - old_len); + } + else if (old_len > new_len) + { + nn_xmsg_shrink(msg, sm_marker, new_len); + } + + /* Just a sanity check: assert(msg_end == submsg_end) */ + assert((msg->data->payload + msg->sz) == (msg->data->payload + sm_marker.offset + new_len)); + + /* Replace the sub-message. */ + memcpy(msg->data->payload + sm_marker.offset, new_submsg, new_len); + + /* The replacement submessage may have undergone any transformation and so the readerId + offset in a DATA_REXMIT message is potentially no longer valid. Converting the + message kind to a _NOMERGE one ensures no subsequent operation will assume its + validity. This is used by the security implementation when encrypting and/or signing + messages and apart from the offset possibly no longer being valid (for which one + might conceivably be able to correct), there is also the issue that it may now be + meaningless junk or that rewriting it would make the receiver reject it as having + been tampered with. */ + if (msg->kind == NN_XMSG_KIND_DATA_REXMIT) + msg->kind = NN_XMSG_KIND_DATA_REXMIT_NOMERGE; +} + +void nn_xmsg_submsg_append_refd_payload(struct nn_xmsg *msg, struct nn_xmsg_marker sm_marker) +{ + DDSRT_UNUSED_ARG(sm_marker); + /* + * Normally, the refd payload pointer is moved around until it is added to + * the iov of the socket. This reduces the amount of allocations and copies. + * + * However, in a few cases (like security), the sub-message should be one + * complete blob. + * Appending the payload will just do that. + */ + if (msg->refd_payload) + { + void *dst; + + /* Get payload information. */ + char *payload_ptr = msg->refd_payload_iov.iov_base; + size_t payload_len = msg->refd_payload_iov.iov_len; + + /* Make space for the payload (dst points to the start of the appended space). */ + dst = nn_xmsg_append(msg, NULL, payload_len); + + /* Copy the payload into the submessage. */ + memcpy(dst, payload_ptr, payload_len); + + /* No need to remember the payload now. */ + ddsi_serdata_unref(msg->refd_payload); + msg->refd_payload = NULL; + if (msg->refd_payload_encoded) + { + ddsrt_free(msg->refd_payload_encoded); + msg->refd_payload_encoded = NULL; + } + } +} + +#endif /* DDSI_INCLUDE_SECURITY */ + void *nn_xmsg_submsg_from_marker (struct nn_xmsg *msg, struct nn_xmsg_marker marker) { return msg->data->payload + marker.offset; @@ -558,22 +697,66 @@ void nn_xmsg_add_entityid (struct nn_xmsg * m) nn_xmsg_submsg_setnext (m, sm); } -void nn_xmsg_serdata (struct nn_xmsg *m, struct ddsi_serdata *serdata, size_t off, size_t len) +void nn_xmsg_serdata (struct nn_xmsg *m, struct ddsi_serdata *serdata, size_t off, size_t len, struct writer *wr) { if (serdata->kind != SDK_EMPTY) { size_t len4 = align4u (len); assert (m->refd_payload == NULL); m->refd_payload = ddsi_serdata_to_ser_ref (serdata, off, len4, &m->refd_payload_iov); + +#ifdef DDSI_INCLUDE_SECURITY + assert (m->refd_payload_encoded == NULL); + /* When encoding is necessary, m->refd_payload_encoded will be allocated + * and m->refd_payload_iov contents will change to point to that buffer. + * If no encoding is necessary, nothing changes. */ + if (!encode_payload(wr, &(m->refd_payload_iov), &(m->refd_payload_encoded))) + { + DDS_CWARNING (&wr->e.gv->logconfig, "nn_xmsg_serdata: failed to encrypt data for "PGUIDFMT"", PGUID (wr->e.guid)); + ddsi_serdata_to_ser_unref (m->refd_payload, &m->refd_payload_iov); + assert (m->refd_payload_encoded == NULL); + m->refd_payload_iov.iov_base = NULL; + m->refd_payload_iov.iov_len = 0; + m->refd_payload = NULL; + } +#else + DDSRT_UNUSED_ARG(wr); +#endif } } -void nn_xmsg_setdst1 (struct nn_xmsg *m, const ddsi_guid_prefix_t *gp, const nn_locator_t *loc) +void nn_xmsg_setdst1 (struct ddsi_domaingv *gv, struct nn_xmsg *m, const ddsi_guid_prefix_t *gp, const nn_locator_t *loc) { assert (m->dstmode == NN_XMSG_DST_UNSET); m->dstmode = NN_XMSG_DST_ONE; m->dstaddr.one.loc = *loc; m->data->dst.guid_prefix = nn_hton_guid_prefix (*gp); +#ifdef DDSI_INCLUDE_SECURITY + if (m->sec_info.use_rtps_encoding && !m->sec_info.dst_pp_handle) + { + struct proxy_participant *proxypp; + ddsi_guid_t guid; + + guid.prefix = *gp; + guid.entityid.u = NN_ENTITYID_PARTICIPANT; + + proxypp = entidx_lookup_proxy_participant_guid(gv->entity_index, &guid); + if (proxypp) + m->sec_info.dst_pp_handle = q_omg_security_get_remote_participant_handle(proxypp); + } +#else + DDSRT_UNUSED_ARG(gv); +#endif +} + +bool nn_xmsg_getdst1prefix (struct nn_xmsg *m, ddsi_guid_prefix_t *gp) +{ + if (m->dstmode == NN_XMSG_DST_ONE) + { + *gp = nn_hton_guid_prefix(m->data->dst.guid_prefix); + return true; + } + return false; } dds_return_t nn_xmsg_setdstPRD (struct nn_xmsg *m, const struct proxy_reader *prd) @@ -581,7 +764,7 @@ dds_return_t nn_xmsg_setdstPRD (struct nn_xmsg *m, const struct proxy_reader *pr nn_locator_t loc; if (addrset_any_uc (prd->c.as, &loc) || addrset_any_mc (prd->c.as, &loc)) { - nn_xmsg_setdst1 (m, &prd->e.guid.prefix, &loc); + nn_xmsg_setdst1 (prd->e.gv, m, &prd->e.guid.prefix, &loc); return 0; } else @@ -596,7 +779,7 @@ dds_return_t nn_xmsg_setdstPWR (struct nn_xmsg *m, const struct proxy_writer *pw nn_locator_t loc; if (addrset_any_uc (pwr->c.as, &loc) || addrset_any_mc (pwr->c.as, &loc)) { - nn_xmsg_setdst1 (m, &pwr->e.guid.prefix, &loc); + nn_xmsg_setdst1 (pwr->e.gv, m, &pwr->e.guid.prefix, &loc); return 0; } DDS_CWARNING (&pwr->e.gv->logconfig, "nn_xmsg_setdstPRD: no address for "PGUIDFMT, PGUID (pwr->e.guid)); @@ -753,31 +936,39 @@ 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_keyhash (struct nn_xmsg *m, const struct ddsi_serdata *serdata) +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) { if (serdata->kind != SDK_EMPTY) { - const struct ddsi_serdata_default *serdata_def = (const struct ddsi_serdata_default *)serdata; char *p = nn_xmsg_addpar (m, PID_KEYHASH, 16); - memcpy (p, serdata_def->keyhash.m_hash, 16); + ddsi_serdata_get_keyhash(serdata, (struct ddsi_keyhash*)p, force_md5); } } @@ -808,6 +999,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) @@ -888,7 +1084,7 @@ static void nn_xmsg_chain_add (struct nn_xmsg_chain *chain, struct nn_xmsg *m) static void nn_bw_limit_sleep_if_needed (struct ddsi_domaingv const * const gv, struct nn_bw_limiter *this, ssize_t size) { if ( this->bandwidth > 0 ) { - nn_mtime_t tnow = now_mt(); + ddsrt_mtime_t tnow = ddsrt_time_monotonic(); int64_t actual_interval; int64_t target_interval; @@ -931,7 +1127,7 @@ static void nn_bw_limit_init (struct nn_bw_limiter *limiter, uint32_t bandwidth_ limiter->bandwidth = bandwidth_limit; limiter->balance = 0; if (bandwidth_limit) - limiter->last_update = now_mt (); + limiter->last_update = ddsrt_time_monotonic(); else limiter->last_update.v = 0; } @@ -951,6 +1147,9 @@ static void nn_xpack_reinit (struct nn_xpack *xp) xp->msg_len.length = 0; xp->included_msgs.latest = NULL; xp->maxdelay = DDS_INFINITY; +#ifdef DDSI_INCLUDE_SECURITY + xp->sec_info.use_rtps_encoding = 0; +#endif #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS xp->encoderId = 0; #endif @@ -1010,6 +1209,35 @@ void nn_xpack_free (struct nn_xpack *xp) ddsrt_free (xp); } +static ssize_t nn_xpack_send_rtps(struct nn_xpack * xp, const nn_locator_t *loc) +{ + ssize_t ret = -1; + +#ifdef DDSI_INCLUDE_SECURITY + /* Only encode when needed. */ + if (xp->sec_info.use_rtps_encoding) + { + ret = secure_conn_write( + xp->gv, + xp->conn, + loc, + xp->niov, + xp->iov, + xp->call_flags, + &(xp->msg_len), + (xp->dstmode == NN_XMSG_DST_ONE), + &(xp->sec_info), + ddsi_conn_write); + } + else +#endif /* DDSI_INCLUDE_SECURITY */ + { + ret = ddsi_conn_write (xp->conn, loc, xp->niov, xp->iov, xp->call_flags); + } + + return ret; +} + static ssize_t nn_xpack_send1 (const nn_locator_t *loc, void * varg) { struct nn_xpack *xp = varg; @@ -1036,14 +1264,17 @@ static ssize_t nn_xpack_send1 (const nn_locator_t *loc, void * varg) if (!gv->mute) { - nbytes = ddsi_conn_write (xp->conn, loc, xp->niov, xp->iov, xp->call_flags); + nbytes = nn_xpack_send_rtps(xp, loc); + #ifndef NDEBUG { size_t i, len; for (i = 0, len = 0; i < xp->niov; i++) { len += xp->iov[i].iov_len; } - assert (nbytes == -1 || (size_t) nbytes == len); + /* Possible number of bytes written can be larger + * due to security. */ + assert (nbytes == -1 || (size_t) nbytes >= len); } #endif } @@ -1337,12 +1568,13 @@ static int nn_xpack_mayaddmsg (const struct nn_xpack *xp, const struct nn_xmsg * return 0; #endif - return addressing_info_eq_onesidederr (xp, m); -} +#ifdef DDSI_INCLUDE_SECURITY + /* Don't mix up encoded and plain rtps messages */ + if (xp->sec_info.use_rtps_encoding != m->sec_info.use_rtps_encoding) + return 0; +#endif -static 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]; + return addressing_info_eq_onesidederr (xp, m); } int nn_xpack_addmsg (struct nn_xpack *xp, struct nn_xmsg *m, const uint32_t flags) @@ -1400,6 +1632,7 @@ int nn_xpack_addmsg (struct nn_xpack *xp, struct nn_xmsg *m, const uint32_t flag break; case NN_XMSG_KIND_DATA: case NN_XMSG_KIND_DATA_REXMIT: + case NN_XMSG_KIND_DATA_REXMIT_NOMERGE: GVTRACE ("%s("PGUIDFMT":#%"PRId64"/%u)", (m->kind == NN_XMSG_KIND_DATA) ? "data" : "rexmit", PGUID (m->kindspecific.data.wrguid), @@ -1430,6 +1663,9 @@ int nn_xpack_addmsg (struct nn_xpack *xp, struct nn_xmsg *m, const uint32_t flag niov++; } +#ifdef DDSI_INCLUDE_SECURITY + xp->sec_info = m->sec_info; +#endif #ifdef DDSI_INCLUDE_NETWORK_PARTITIONS xp->encoderId = m->encoderid; #endif diff --git a/src/core/ddsi/tests/CMakeLists.txt b/src/core/ddsi/tests/CMakeLists.txt index 7aa0300..a071abe 100644 --- a/src/core/ddsi/tests/CMakeLists.txt +++ b/src/core/ddsi/tests/CMakeLists.txt @@ -13,7 +13,12 @@ include(CUnit) set(ddsi_test_sources "plist_generic.c" - "plist.c") + "plist.c" + "mem_ser.h") + +if(ENABLE_SECURITY) + set(ddsi_test_sources ${ddsi_test_sources} "security_msg.c") +endif() add_cunit_executable(cunit_ddsi ${ddsi_test_sources}) target_include_directories( diff --git a/src/core/ddsi/tests/mem_ser.h b/src/core/ddsi/tests/mem_ser.h new file mode 100644 index 0000000..d616a90 --- /dev/null +++ b/src/core/ddsi/tests/mem_ser.h @@ -0,0 +1,55 @@ +/* + * Copyright(c) 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 DDSI_TEST_MEM_SER_H +#define DDSI_TEST_MEM_SER_H + +#include "dds/ddsrt/endian.h" + +#if DDSRT_ENDIAN == DDSRT_BIG_ENDIAN +#define SER32(v) \ + (unsigned char)( (uint32_t)(v) >> 24 ), \ + (unsigned char)(((uint32_t)(v) >> 16) & 0xff), \ + (unsigned char)(((uint32_t)(v) >> 8) & 0xff), \ + (unsigned char)( (uint32_t)(v) & 0xff) +#define SER32BE(v) SER32(v) +#define SER64(v) \ + (unsigned char)( (uint32_t)(v) >> 56), \ + (unsigned char)(((uint32_t)(v) >> 48) & 0xff), \ + (unsigned char)(((uint32_t)(v) >> 40) & 0xff), \ + (unsigned char)(((uint32_t)(v) >> 32) & 0xff), \ + (unsigned char)(((uint32_t)(v) >> 24) & 0xff), \ + (unsigned char)(((uint32_t)(v) >> 16) & 0xff), \ + (unsigned char)(((uint32_t)(v) >> 8) & 0xff), \ + (unsigned char)( (uint32_t)(v) & 0xff) +#else +#define SER32(v) \ + (unsigned char)( (uint32_t)(v) & 0xff), \ + (unsigned char)(((uint32_t)(v) >> 8) & 0xff), \ + (unsigned char)(((uint32_t)(v) >> 16) & 0xff), \ + (unsigned char)( (uint32_t)(v) >> 24 ) +#define SER32BE(v) \ + (unsigned char)( (uint32_t)(v) >> 24 ), \ + (unsigned char)(((uint32_t)(v) >> 16) & 0xff), \ + (unsigned char)(((uint32_t)(v) >> 8) & 0xff), \ + (unsigned char)( (uint32_t)(v) & 0xff) +#define SER64(v) \ + (unsigned char)( (uint64_t)(v) & 0xff), \ + (unsigned char)(((uint64_t)(v) >> 8) & 0xff), \ + (unsigned char)(((uint64_t)(v) >> 16) & 0xff), \ + (unsigned char)(((uint64_t)(v) >> 24) & 0xff), \ + (unsigned char)(((uint64_t)(v) >> 32) & 0xff), \ + (unsigned char)(((uint64_t)(v) >> 40) & 0xff), \ + (unsigned char)(((uint64_t)(v) >> 48) & 0xff), \ + (unsigned char)( (uint64_t)(v) >> 56) +#endif + +#endif /* DDSI_TEST_MEM_SER_H */ diff --git a/src/core/ddsi/tests/plist.c b/src/core/ddsi/tests/plist.c index a26d932..8227831 100644 --- a/src/core/ddsi/tests/plist.c +++ b/src/core/ddsi/tests/plist.c @@ -21,7 +21,7 @@ CU_Test (ddsi_plist, unalias_copy_merge) { /* one int, one string and one string sequence covers most cases */ ddsi_plist_t p0, p0memcpy; - char *p0strs[3]; + char *p0strs[7]; ddsi_plist_init_empty (&p0); p0.present = PP_ENTITY_NAME; p0.aliased = PP_ENTITY_NAME; @@ -33,18 +33,43 @@ CU_Test (ddsi_plist, unalias_copy_merge) p0strs[0] = p0.qos.partition.strs[0] = "aap"; p0strs[1] = p0.qos.partition.strs[1] = "noot"; p0strs[2] = p0.qos.partition.strs[2] = "mies"; +#ifdef DDSI_INCLUDE_SECURITY + p0.present |= PP_IDENTITY_TOKEN; + p0.aliased |= PP_IDENTITY_TOKEN; + p0.identity_token.class_id = "class_id"; + p0.identity_token.properties.n = 2; + p0.identity_token.properties.props = ddsrt_malloc (p0.identity_token.properties.n * sizeof (*p0.identity_token.properties.props)); + p0.identity_token.properties.props[0].propagate = false; + p0strs[3] = p0.identity_token.properties.props[0].name = "name0"; + p0strs[4] = p0.identity_token.properties.props[0].value = "value0"; + p0.identity_token.properties.props[1].propagate = true; + p0strs[5] = p0.identity_token.properties.props[1].name = "name1"; + p0strs[6] = p0.identity_token.properties.props[1].value = "value1"; + p0.identity_token.binary_properties.n = 0; + p0.identity_token.binary_properties.props = NULL; +#endif memcpy (&p0memcpy, &p0, sizeof (p0)); /* manually alias one, so we can free it*/ ddsi_plist_t p0alias; memcpy (&p0alias, &p0, sizeof (p0)); p0alias.qos.partition.strs = ddsrt_memdup (p0alias.qos.partition.strs, p0.qos.partition.n * sizeof (*p0.qos.partition.strs)); +#ifdef DDSI_INCLUDE_SECURITY + p0alias.identity_token.properties.props = ddsrt_memdup (p0alias.identity_token.properties.props, + p0.identity_token.properties.n * sizeof (*p0.identity_token.properties.props)); +#endif ddsi_plist_fini (&p0alias); CU_ASSERT (memcmp (&p0, &p0memcpy, sizeof (p0)) == 0); CU_ASSERT_STRING_EQUAL (p0.entity_name, "nemo"); CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[0], p0strs[0]); CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[1], p0strs[1]); CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[2], p0strs[2]); +#ifdef DDSI_INCLUDE_SECURITY + CU_ASSERT_STRING_EQUAL (p0.identity_token.properties.props[0].name, p0strs[3]); + CU_ASSERT_STRING_EQUAL (p0.identity_token.properties.props[0].value, p0strs[4]); + CU_ASSERT_STRING_EQUAL (p0.identity_token.properties.props[1].name, p0strs[5]); + CU_ASSERT_STRING_EQUAL (p0.identity_token.properties.props[1].value, p0strs[6]); +#endif /* copy an aliased one; the original must be unchanged, the copy unaliased */ ddsi_plist_t p1; @@ -65,6 +90,24 @@ CU_Test (ddsi_plist, unalias_copy_merge) CU_ASSERT_STRING_EQUAL (p1.qos.partition.strs[0], p0.qos.partition.strs[0]); CU_ASSERT_STRING_EQUAL (p1.qos.partition.strs[1], p0.qos.partition.strs[1]); CU_ASSERT_STRING_EQUAL (p1.qos.partition.strs[2], p0.qos.partition.strs[2]); +#ifdef DDSI_INCLUDE_SECURITY + CU_ASSERT (p1.identity_token.class_id != p0.identity_token.class_id); + CU_ASSERT_STRING_EQUAL (p1.identity_token.class_id, p0.identity_token.class_id); + CU_ASSERT (p1.identity_token.properties.n == p0.identity_token.properties.n); + CU_ASSERT (p1.identity_token.properties.props != p0.identity_token.properties.props); + CU_ASSERT (p1.identity_token.properties.props[0].name != p0.identity_token.properties.props[0].name); + CU_ASSERT (p1.identity_token.properties.props[0].value != p0.identity_token.properties.props[0].value); + CU_ASSERT (p1.identity_token.properties.props[0].propagate == p0.identity_token.properties.props[0].propagate); + CU_ASSERT (p1.identity_token.properties.props[1].name != p0.identity_token.properties.props[1].name); + CU_ASSERT (p1.identity_token.properties.props[1].value != p0.identity_token.properties.props[1].value); + CU_ASSERT (p1.identity_token.properties.props[1].propagate == p0.identity_token.properties.props[1].propagate); + CU_ASSERT_STRING_EQUAL (p1.identity_token.properties.props[0].name, p0.identity_token.properties.props[0].name); + CU_ASSERT_STRING_EQUAL (p1.identity_token.properties.props[0].value, p0.identity_token.properties.props[0].value); + CU_ASSERT_STRING_EQUAL (p1.identity_token.properties.props[1].name, p0.identity_token.properties.props[1].name); + CU_ASSERT_STRING_EQUAL (p1.identity_token.properties.props[1].value, p0.identity_token.properties.props[1].value); + CU_ASSERT (p1.identity_token.binary_properties.n == 0); + CU_ASSERT (p1.identity_token.binary_properties.props == NULL); +#endif /* merge-in missing ones from an aliased copy: original must remain unchanged; existing ones should stay without touching "aliased" only new ones are @@ -91,6 +134,24 @@ CU_Test (ddsi_plist, unalias_copy_merge) CU_ASSERT_STRING_EQUAL (p2.qos.partition.strs[0], p0.qos.partition.strs[0]); CU_ASSERT_STRING_EQUAL (p2.qos.partition.strs[1], p0.qos.partition.strs[1]); CU_ASSERT_STRING_EQUAL (p2.qos.partition.strs[2], p0.qos.partition.strs[2]); +#ifdef DDSI_INCLUDE_SECURITY + CU_ASSERT (p2.identity_token.class_id != p0.identity_token.class_id); + CU_ASSERT_STRING_EQUAL (p2.identity_token.class_id, p0.identity_token.class_id); + CU_ASSERT (p2.identity_token.properties.n == p0.identity_token.properties.n); + CU_ASSERT (p2.identity_token.properties.props != p0.identity_token.properties.props); + CU_ASSERT (p2.identity_token.properties.props[0].name != p0.identity_token.properties.props[0].name); + CU_ASSERT (p2.identity_token.properties.props[0].value != p0.identity_token.properties.props[0].value); + CU_ASSERT (p2.identity_token.properties.props[0].propagate == p0.identity_token.properties.props[0].propagate); + CU_ASSERT (p2.identity_token.properties.props[1].name != p0.identity_token.properties.props[1].name); + CU_ASSERT (p2.identity_token.properties.props[1].value != p0.identity_token.properties.props[1].value); + CU_ASSERT (p2.identity_token.properties.props[1].propagate == p0.identity_token.properties.props[1].propagate); + CU_ASSERT_STRING_EQUAL (p2.identity_token.properties.props[0].name, p0.identity_token.properties.props[0].name); + CU_ASSERT_STRING_EQUAL (p2.identity_token.properties.props[0].value, p0.identity_token.properties.props[0].value); + CU_ASSERT_STRING_EQUAL (p2.identity_token.properties.props[1].name, p0.identity_token.properties.props[1].name); + CU_ASSERT_STRING_EQUAL (p2.identity_token.properties.props[1].value, p0.identity_token.properties.props[1].value); + CU_ASSERT (p2.identity_token.binary_properties.n == 0); + CU_ASSERT (p2.identity_token.binary_properties.props == NULL); +#endif /* unalias of p0, partition.strs mustn't change, because it, unlike its elements, wasn't aliased */ ddsi_plist_unalias (&p0); @@ -108,6 +169,17 @@ CU_Test (ddsi_plist, unalias_copy_merge) CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[0], p0strs[0]); CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[1], p0strs[1]); CU_ASSERT_STRING_EQUAL (p0.qos.partition.strs[2], p0strs[2]); +#ifdef DDSI_INCLUDE_SECURITY + CU_ASSERT (p0.identity_token.properties.props[0].name != p0strs[3]); + CU_ASSERT (p0.identity_token.properties.props[0].value != p0strs[4]); + CU_ASSERT (p0.identity_token.properties.props[1].name != p0strs[5]); + CU_ASSERT (p0.identity_token.properties.props[1].value != p0strs[6]); + CU_ASSERT_STRING_EQUAL (p0.identity_token.properties.props[0].name, p0strs[3]); + CU_ASSERT_STRING_EQUAL (p0.identity_token.properties.props[0].value, p0strs[4]); + CU_ASSERT_STRING_EQUAL (p0.identity_token.properties.props[1].name, p0strs[5]); + CU_ASSERT_STRING_EQUAL (p0.identity_token.properties.props[1].value, p0strs[6]); +#endif + memcpy (&p0memcpy, &p0, sizeof (p0)); /* copy an aliased one; the original must be unchanged, the copy unaliased */ @@ -129,6 +201,24 @@ CU_Test (ddsi_plist, unalias_copy_merge) CU_ASSERT_STRING_EQUAL (p3.qos.partition.strs[0], p0.qos.partition.strs[0]); CU_ASSERT_STRING_EQUAL (p3.qos.partition.strs[1], p0.qos.partition.strs[1]); CU_ASSERT_STRING_EQUAL (p3.qos.partition.strs[2], p0.qos.partition.strs[2]); +#ifdef DDSI_INCLUDE_SECURITY + CU_ASSERT (p3.identity_token.class_id != p0.identity_token.class_id); + CU_ASSERT_STRING_EQUAL (p3.identity_token.class_id, p0.identity_token.class_id); + CU_ASSERT (p3.identity_token.properties.n == p0.identity_token.properties.n); + CU_ASSERT (p3.identity_token.properties.props != p0.identity_token.properties.props); + CU_ASSERT (p3.identity_token.properties.props[0].name != p0.identity_token.properties.props[0].name); + CU_ASSERT (p3.identity_token.properties.props[0].value != p0.identity_token.properties.props[0].value); + CU_ASSERT (p3.identity_token.properties.props[0].propagate == p0.identity_token.properties.props[0].propagate); + CU_ASSERT (p3.identity_token.properties.props[1].name != p0.identity_token.properties.props[1].name); + CU_ASSERT (p3.identity_token.properties.props[1].value != p0.identity_token.properties.props[1].value); + CU_ASSERT (p3.identity_token.properties.props[1].propagate == p0.identity_token.properties.props[1].propagate); + CU_ASSERT_STRING_EQUAL (p3.identity_token.properties.props[0].name, p0.identity_token.properties.props[0].name); + CU_ASSERT_STRING_EQUAL (p3.identity_token.properties.props[0].value, p0.identity_token.properties.props[0].value); + CU_ASSERT_STRING_EQUAL (p3.identity_token.properties.props[1].name, p0.identity_token.properties.props[1].name); + CU_ASSERT_STRING_EQUAL (p3.identity_token.properties.props[1].value, p0.identity_token.properties.props[1].value); + CU_ASSERT (p3.identity_token.binary_properties.n == 0); + CU_ASSERT (p3.identity_token.binary_properties.props == NULL); +#endif /* merge-in missing ones from an aliased copy: original must remain unchanged; existing ones should stay without touching "aliased" only new ones are @@ -155,6 +245,24 @@ CU_Test (ddsi_plist, unalias_copy_merge) CU_ASSERT_STRING_EQUAL (p4.qos.partition.strs[0], p0.qos.partition.strs[0]); CU_ASSERT_STRING_EQUAL (p4.qos.partition.strs[1], p0.qos.partition.strs[1]); CU_ASSERT_STRING_EQUAL (p4.qos.partition.strs[2], p0.qos.partition.strs[2]); +#ifdef DDSI_INCLUDE_SECURITY + CU_ASSERT (p4.identity_token.class_id != p0.identity_token.class_id); + CU_ASSERT_STRING_EQUAL (p4.identity_token.class_id, p0.identity_token.class_id); + CU_ASSERT (p4.identity_token.properties.n == p0.identity_token.properties.n); + CU_ASSERT (p4.identity_token.properties.props != p0.identity_token.properties.props); + CU_ASSERT (p4.identity_token.properties.props[0].name != p0.identity_token.properties.props[0].name); + CU_ASSERT (p4.identity_token.properties.props[0].value != p0.identity_token.properties.props[0].value); + CU_ASSERT (p4.identity_token.properties.props[0].propagate == p0.identity_token.properties.props[0].propagate); + CU_ASSERT (p4.identity_token.properties.props[1].name != p0.identity_token.properties.props[1].name); + CU_ASSERT (p4.identity_token.properties.props[1].value != p0.identity_token.properties.props[1].value); + CU_ASSERT (p4.identity_token.properties.props[1].propagate == p0.identity_token.properties.props[1].propagate); + CU_ASSERT_STRING_EQUAL (p4.identity_token.properties.props[0].name, p0.identity_token.properties.props[0].name); + CU_ASSERT_STRING_EQUAL (p4.identity_token.properties.props[0].value, p0.identity_token.properties.props[0].value); + CU_ASSERT_STRING_EQUAL (p4.identity_token.properties.props[1].name, p0.identity_token.properties.props[1].name); + CU_ASSERT_STRING_EQUAL (p4.identity_token.properties.props[1].value, p0.identity_token.properties.props[1].value); + CU_ASSERT (p4.identity_token.binary_properties.n == 0); + CU_ASSERT (p4.identity_token.binary_properties.props == NULL); +#endif ddsi_plist_fini (&p0); ddsi_plist_fini (&p1); diff --git a/src/core/ddsi/tests/plist_generic.c b/src/core/ddsi/tests/plist_generic.c index 7c97b74..689f2f9 100644 --- a/src/core/ddsi/tests/plist_generic.c +++ b/src/core/ddsi/tests/plist_generic.c @@ -15,6 +15,7 @@ #include "dds/ddsrt/endian.h" #include "dds/ddsi/ddsi_xqos.h" #include "dds/ddsi/ddsi_plist_generic.h" +#include "mem_ser.h" struct desc { const enum pserop desc[20]; @@ -33,28 +34,9 @@ struct desc_invalid { const unsigned char *ser; }; -#if DDSRT_ENDIAN == DDSRT_BIG_ENDIAN -#define SER32(v) \ - (unsigned char)((uint32_t)(v) >> 24), \ - (unsigned char)(((uint32_t)(v) >> 16) & 0xff), \ - (unsigned char)(((uint32_t)(v) >> 8) & 0xff), \ - (unsigned char)((uint32_t)(v) & 0xff) -#define SER32BE(v) SER32(v) -#else -#define SER32(v) \ - (unsigned char)((uint32_t)(v) & 0xff), \ - (unsigned char)(((uint32_t)(v) >> 8) & 0xff), \ - (unsigned char)(((uint32_t)(v) >> 16) & 0xff), \ - (unsigned char)((uint32_t)(v) >> 24) -#define SER32BE(v) \ - (unsigned char)((uint32_t)(v) >> 24), \ - (unsigned char)(((uint32_t)(v) >> 16) & 0xff), \ - (unsigned char)(((uint32_t)(v) >> 8) & 0xff), \ - (unsigned char)((uint32_t)(v) & 0xff) -#endif - typedef unsigned char raw[]; typedef uint32_t raw32[]; +typedef uint64_t raw64[]; typedef ddsi_octetseq_t oseq; struct desc descs[] = { @@ -75,6 +57,7 @@ struct desc descs[] = { { {Xux3,XSTOP}, (raw32){4,5,6}, 12, (raw){SER32(4), SER32(5), SER32(6)} }, { {Xux4,XSTOP}, (raw32){7,8,9,10}, 16, (raw){SER32(7), SER32(8), SER32(9), SER32(10)} }, { {Xux5,XSTOP}, (raw32){7,8,9,10,11}, 20, (raw){SER32(7), SER32(8), SER32(9), SER32(10), SER32(11)} }, + { {Xl,XSTOP}, (raw64){123456789}, 8, (raw){SER64(123456789)} }, { {XD,XSTOP}, (uint64_t[]){314159265358979324}, /* note: fractional part depends on rounding rule used for converting nanoseconds to NTP time Cyclone currently rounds up, so we have to do that too */ @@ -94,6 +77,46 @@ struct desc descs[] = { 7, (raw){SER32(3), 1,2,3} }, { {XQ,XS,XSTOP,XSTOP}, &(ddsi_stringseq_t){2, (char*[]){"tree","flower"}}, 27, (raw){SER32(2), SER32(5),'t','r','e','e',0, 0,0,0, SER32(7), 'f','l','o','w','e','r',0} }, + { {Xo,Xl,Xo,Xu,Xo,XSTOP}, + &(struct{unsigned char a;int64_t b;unsigned char c;uint32_t d;unsigned char e;}){ 1, 2, 3, 4, 5 }, + 25, (raw){1,0,0,0,0,0,0,0,SER64(2),3,0,0,0,SER32(4),5} }, + { {Xo,XQ,Xo,Xu,Xo,XSTOP,Xo,XSTOP}, + &(struct{uint8_t b; oseq seq; uint8_t c;}) + {1, {2, (unsigned char *)(struct{uint8_t a; uint32_t b; uint8_t c;}[]) + { {0x10, 0x11, 0x12}, + {0x21, 0x22, 0x23} }, + }, 0x42 }, + 26, + (raw){1, /* pad */0,0,0, SER32(2), + 0x10, /* pad */0,0,0, SER32(0x11), 0x12, + 0x21, /* pad */0,0, SER32(0x22), 0x23, + 0x42} + }, + { {Xo,XQ,Xo,Xl,Xo,XSTOP,Xo,XSTOP}, + &(struct{uint8_t b; oseq seq; uint8_t c;}) + {1, {2, (unsigned char *)(struct{uint8_t a; int64_t b; uint8_t c;}[]) + { {0x10, 0x11, 0x12}, + {0x21, 0x22, 0x23} }, + }, 0x42 }, + 42, + (raw){1, /* pad */0,0,0, SER32(2), + 0x10, /* pad */0,0,0,0,0,0,0, SER64(0x11), 0x12, + 0x21, /* pad */0,0,0,0,0,0, SER64(0x22), 0x23, + 0x42} + }, + { {Xo,XQ,Xo,Xo,XQ,Xo,XSTOP,XSTOP,Xo,XSTOP}, + &(struct{uint8_t b; oseq seq; uint8_t c;}) + {1, {2, (unsigned char *)(struct{uint8_t a; uint8_t b; oseq seq;}[]) + { {0x10, 0x11, { 3, (unsigned char *)(struct{uint8_t a;}[]){ {'a'}, {'b'}, {'c'}}}}, + {0x21, 0x22, { 2, (unsigned char *)(struct{uint8_t a;}[]){ {'o'}, {'p'}}}} + }, + }, 0x42 }, + 31, + (raw){1, /* pad */0,0,0, SER32(2), + 0x10, 0x11, /* pad */0,0, SER32(3), 'a','b','c', + 0x21, 0x22, /* pad */0,0,0, SER32(2), 'o','p', + 0x42} + }, { {Xb,XQ,XbPROP,XS,Xo,XSTOP,XSTOP}, &(struct{char b; oseq seq;}){1, {5, (unsigned char *)(struct{char b;char *s;uint8_t o;}[]){ {0,"apple",1}, {1,"orange",2}, {0,"cherry",3}, {1,"fig",4}, {1,"prune",5}}}}, @@ -240,7 +263,8 @@ struct desc_invalid descs_invalid[] = { SER32(7), 'o','r','a','n','g','e',0, 2, SER32(4), 'f','i','g',0, 4, 0,0,0, SER32(7), 'p','r','u','n','e',0, 5 // string not terminated - } } + } }, + { {XQ,XQ,Xu,XSTOP,XSTOP}, 16, (raw){SER32(2),SER32(1),SER32(31415),SER32(3)} } // nested sequence failure }; CU_Test (ddsi_plist_generic, invalid_input) diff --git a/src/core/ddsi/tests/security_msg.c b/src/core/ddsi/tests/security_msg.c new file mode 100644 index 0000000..c052a89 --- /dev/null +++ b/src/core/ddsi/tests/security_msg.c @@ -0,0 +1,330 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#include "CUnit/Theory.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsi/ddsi_security_msg.h" +#include "mem_ser.h" +#include + +static nn_participant_generic_message_t test_msg_in = +{ + .message_identity = { {{.u={1,2,3}},{4}}, 5 }, + .related_message_identity = { {{.u={5,4,3}},{2}}, 1 }, + .destination_participant_guid = { {.u={2,3,4}},{5} }, + .destination_endpoint_guid = { {.u={3,4,5}},{6} }, + .source_endpoint_guid = { {.u={4,5,6}},{7} }, + .message_class_id = "testing message", + .message_data = { + .n = 4, + .tags = (nn_dataholder_t[]) { + { + .class_id = "holder0", + .properties = { + .n = 3, + .props = (dds_property_t[]) { + { + .propagate = false, + .name = "holder0::prop0name", + .value = "holder0::prop0value", + }, + { + .propagate = true, + .name = "holder0::prop1name", + .value = "holder0::prop1value", + }, + { + .propagate = false, + .name = "holder0::prop2name", + .value = "holder0::prop2value", + }, + } + }, + .binary_properties = { + .n = 1, + .props = (dds_binaryproperty_t[]) { + { + .propagate = false, + .name = "holder0::bprop0name", + .value = { 2, (unsigned char[]){ 1, 2 } }, + }, + } + }, + }, + { + .class_id = "holder1", + .properties = { + .n = 1, + .props = (dds_property_t[]) { + { + .propagate = true, + .name = "holder1::prop0name", + .value = "holder1::prop0value", + }, + } + }, + .binary_properties = { + .n = 1, + .props = (dds_binaryproperty_t[]) { + { + .propagate = true, + .name = "holder1::bprop0name", + .value = { 3, (unsigned char[]){ 1, 2, 3 } }, + }, + } + }, + }, + { + .class_id = "holder2", + .properties = { + .n = 1, + .props = (dds_property_t[]) { + { + .propagate = false, + .name = "holder2::prop0name", + .value = "holder2::prop0value", + }, + } + }, + .binary_properties = { + .n = 3, + .props = (dds_binaryproperty_t[]) { + { + .propagate = true, + .name = "holder2::bprop0name", + .value = { 3, (unsigned char[]){ 1, 2, 3 } }, + }, + { + .propagate = false, + .name = "holder2::bprop1name", + .value = { 4, (unsigned char[]){ 1, 2, 3, 4 } }, + }, + { + .propagate = true, + .name = "holder2::bprop2name", + .value = { 5, (unsigned char[]){ 1, 2, 3, 4, 5 } }, + }, + } + }, + }, + { + .class_id = "holder3", + .properties = { + .n = 1, + .props = (dds_property_t[]) { + { + .propagate = false, + .name = "holder3::prop0name", + .value = "holder3::prop0value", + }, + } + }, + .binary_properties = { + .n = 1, + .props = (dds_binaryproperty_t[]) { + { + .propagate = false, + .name = "holder3::bprop0name", + .value = { 3, (unsigned char[]){ 1, 2, 3 } }, + }, + } + }, + }, + }, + }, +}; + +/* Same as test_msg_in, excluding the non-propagated properties. */ +static nn_participant_generic_message_t test_msg_out = +{ + .message_identity = { {{.u={1,2,3}},{4}}, 5 }, + .related_message_identity = { {{.u={5,4,3}},{2}}, 1 }, + .destination_participant_guid = { {.u={2,3,4}},{5} }, + .destination_endpoint_guid = { {.u={3,4,5}},{6} }, + .source_endpoint_guid = { {.u={4,5,6}},{7} }, + .message_class_id = "testing message", + .message_data = { + .n = 4, + .tags = (nn_dataholder_t[]) { + { + .class_id = "holder0", + .properties = { + .n = 1, + .props = (dds_property_t[]) { + { + .propagate = true, + .name = "holder0::prop1name", + .value = "holder0::prop1value", + }, + } + }, + .binary_properties = { + .n = 0, + .props = NULL + }, + }, + { + .class_id = "holder1", + .properties = { + .n = 1, + .props = (dds_property_t[]) { + { + .propagate = true, + .name = "holder1::prop0name", + .value = "holder1::prop0value", + }, + } + }, + .binary_properties = { + .n = 1, + .props = (dds_binaryproperty_t[]) { + { + .propagate = true, + .name = "holder1::bprop0name", + .value = { 3, (unsigned char[]){ 1, 2, 3 } }, + }, + } + }, + }, + { + .class_id = "holder2", + .properties = { + .n = 0, + .props = NULL, + }, + .binary_properties = { + .n = 2, + .props = (dds_binaryproperty_t[]) { + { + .propagate = true, + .name = "holder2::bprop0name", + .value = { 3, (unsigned char[]){ 1, 2, 3 } }, + }, + { + .propagate = true, + .name = "holder2::bprop2name", + .value = { 5, (unsigned char[]){ 1, 2, 3, 4, 5 } }, + }, + } + }, + }, + { + .class_id = "holder3", + .properties = { + .n = 0, + .props = NULL, + }, + .binary_properties = { + .n = 0, + .props = NULL, + }, + }, + }, + }, +}; + +/* The cdr of test_msg_out. */ +static unsigned char test_msg_ser[] = { + SER32BE(1), SER32BE(2), SER32BE(3), SER32BE(4), SER64(5), + SER32BE(5), SER32BE(4), SER32BE(3), SER32BE(2), SER64(1), + SER32BE(2), SER32BE(3), SER32BE(4), SER32BE(5), + SER32BE(3), SER32BE(4), SER32BE(5), SER32BE(6), + SER32BE(4), SER32BE(5), SER32BE(6), SER32BE(7), + SER32(16), 't','e','s','t','i','n','g',' ','m','e','s','s','a','g','e',0, + SER32(4), + /* dataholder 0 */ + SER32(8), 'h','o','l','d','e','r','0',0, + SER32(1), + SER32(19), 'h','o','l','d','e','r','0',':',':','p','r','o','p','1','n','a','m','e',0,/* pad */0, + SER32(20), 'h','o','l','d','e','r','0',':',':','p','r','o','p','1','v','a','l','u','e',0, + SER32(0), + /* dataholder 1 */ + SER32(8), 'h','o','l','d','e','r','1',0, + SER32(1), + SER32(19), 'h','o','l','d','e','r','1',':',':','p','r','o','p','0','n','a','m','e',0,/* pad */0, + SER32(20), 'h','o','l','d','e','r','1',':',':','p','r','o','p','0','v','a','l','u','e',0, + SER32(1), + SER32(20), 'h','o','l','d','e','r','1',':',':','b','p','r','o','p','0','n','a','m','e',0, + SER32(3), 1,2,3, /* pad */0, + /* dataholder 2 */ + SER32(8), 'h','o','l','d','e','r','2',0, + SER32(0), + SER32(2), + SER32(20), 'h','o','l','d','e','r','2',':',':','b','p','r','o','p','0','n','a','m','e',0, + SER32(3), 1,2,3, /* pad */0, + SER32(20), 'h','o','l','d','e','r','2',':',':','b','p','r','o','p','2','n','a','m','e',0, + SER32(5), 1,2,3,4,5, /* pad */0,0,0, + /* dataholder 2 */ + SER32(8), 'h','o','l','d','e','r','3',0, + SER32(0), + SER32(0) +}; + +CU_Test (ddsi_security_msg, serializer) +{ + nn_participant_generic_message_t msg_in; + nn_participant_generic_message_t msg_ser; + unsigned char *data = NULL; + dds_return_t ret; + size_t len; + bool equal; + + /* Create the message (normally with various arguments). */ + nn_participant_generic_message_init( + &msg_in, + &test_msg_in.message_identity.source_guid, + test_msg_in.message_identity.sequence_number, + &test_msg_in.destination_participant_guid, + &test_msg_in.destination_endpoint_guid, + &test_msg_in.source_endpoint_guid, + test_msg_in.message_class_id, + &test_msg_in.message_data, + &test_msg_in.related_message_identity); + + /* Check creation result. */ + equal = plist_equal_generic(&msg_in, &test_msg_in, pserop_participant_generic_message); + CU_ASSERT_FATAL(equal == true); + + /* Serialize the message. */ + ret = nn_participant_generic_message_serialize(&msg_in, &data, &len); + CU_ASSERT_FATAL (ret == DDS_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL_FATAL(data); + CU_ASSERT(len > 0); + + /* Check serialization result. */ + size_t cmpsize = (len < sizeof(test_msg_ser)) ? len : sizeof(test_msg_ser); + assert(data != NULL); /* for Clang static analyzer */ + if (memcmp (data, test_msg_ser, cmpsize) != 0) + { + printf ("memcmp(%d)\n", (int)cmpsize); + for (size_t k = 0; k < cmpsize; k++) + printf (" %3zu %02x %02x (%c) %s\n", k, data[k], test_msg_ser[k], + ((test_msg_ser[k] >= '0') && (test_msg_ser[k] <= 'z')) ? test_msg_ser[k] : ' ', + (data[k] == test_msg_ser[k]) ? "" : "<--"); + CU_ASSERT (!(bool)"memcmp"); + } + CU_ASSERT_FATAL (len == sizeof(test_msg_ser)); + + /* Deserialize the message. */ + ret = nn_participant_generic_message_deseralize(&msg_ser, data, len, false); + CU_ASSERT_FATAL (ret == DDS_RETCODE_OK); + + /* Check deserialization result. */ + equal = plist_equal_generic(&msg_ser, &test_msg_out, pserop_participant_generic_message); + CU_ASSERT_FATAL(equal == true); + + /* Cleanup. */ + nn_participant_generic_message_deinit(&msg_in); + nn_participant_generic_message_deinit(&msg_ser); + ddsrt_free(data); +} diff --git a/src/core/xtests/rhc_torture/rhc_torture.c b/src/core/xtests/rhc_torture/rhc_torture.c index fe9dc53..b08fa4f 100644 --- a/src/core/xtests/rhc_torture/rhc_torture.c +++ b/src/core/xtests/rhc_torture/rhc_torture.c @@ -894,6 +894,7 @@ int main (int argc, char **argv) uint32_t states_seen[2 * 2 * 3][2] = {{ 0 }}; unsigned seed = 0; bool print = false; + int xchecks = 1; int first = 0, count = 10000; ddsrt_mutex_init (&wait_gc_cycle_lock); @@ -909,10 +910,21 @@ int main (int argc, char **argv) count = atoi (argv[3]); if (argc > 4) print = (atoi (argv[4]) != 0); + if (argc > 5) + xchecks = atoi (argv[4]); - printf ("prng seed %u first %d count %d print %d\n", seed, first, count, print); + printf ("prng seed %u first %d count %d print %d xchecks %d\n", seed, first, count, print, xchecks); ddsrt_prng_init_simple (&prng, seed); + if (xchecks != 0) + { + struct ddsi_domaingv *gv = get_gv (pp); + if (xchecks > 0) + gv->config.enabled_xchecks = ~0u; + else + gv->config.enabled_xchecks = 0u; + } + memset (rres_mseq, 0, sizeof (rres_mseq)); for (size_t i = 0; i < sizeof (rres_iseq) / sizeof(rres_iseq[0]); i++) rres_ptrs[i] = &rres_mseq[i]; @@ -935,6 +947,7 @@ int main (int argc, char **argv) printf ("************* 0 *************\n"); struct dds_rhc *rhc = mkrhc (gv, NULL, DDS_HISTORY_KEEP_LAST, 1, DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP); struct proxy_writer *wr0 = mkwr (gv, 1); + struct proxy_writer *wr1 = mkwr (gv, 1); uint64_t iid0, iid1, iid_t; iid0 = store (tkmap, rhc, wr0, mksample (0, 0), print, false); iid1 = store (tkmap, rhc, wr0, mksample (1, NN_STATUSINFO_DISPOSE), print, false); @@ -944,17 +957,38 @@ int main (int argc, char **argv) { 0, 0, 0, 0, 0, 0, 0, 0 } }; rdall (rhc, c0, print, states_seen); - iid_t = store (tkmap, rhc, wr0, mkkeysample (0, NN_STATUSINFO_UNREGISTER), print, false); + /* write instance 0 with 2nd writer to have 2 live writers */ + iid_t = store (tkmap, rhc, wr1, mksample (0, 0), print, false); assert (iid_t == iid0); - (void)iid0; - (void)iid_t; const struct check c1[] = { - { "ROU", iid0, wr0->e.iid, 0,0, 1, 0,1 }, - { "NOU", iid0, 0, 0,0, 0, 0,0 }, + { "NOA", iid0, wr1->e.iid, 0,0, 1, 0,3 }, { "ROD", iid1, wr0->e.iid, 0,0, 1, 1,2 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }; rdall (rhc, c1, print, states_seen); + /* unregister instance 0 with wr0 - autodispose, but 2nd writer keeps it alive, no visible change */ + iid_t = store (tkmap, rhc, wr0, mkkeysample (0, NN_STATUSINFO_UNREGISTER), print, false); + assert (iid_t == iid0); + const struct check c2[] = { + { "ROA", iid0, wr1->e.iid, 0,0, 1, 0,3 }, + { "ROD", iid1, wr0->e.iid, 0,0, 1, 1,2 }, + { 0, 0, 0, 0, 0, 0, 0, 0 } + }; + rdall (rhc, c2, print, states_seen); + /* unregistering instance 0 again should be a no-op because wr0 no longer has it registered */ + iid_t = store (tkmap, rhc, wr0, mkkeysample (0, NN_STATUSINFO_UNREGISTER), print, false); + assert (iid_t == iid0); + rdall (rhc, c2, print, states_seen); + /* unregistering instance 0 with wr1 - autodispose, no live writers -> dispose */ + iid_t = store (tkmap, rhc, wr1, mkkeysample (0, NN_STATUSINFO_UNREGISTER), print, false); + assert (iid_t == iid0); + const struct check c3[] = { + { "ROD", iid0, wr1->e.iid, 0,0, 1, 0,3 }, + { "NOD", iid0, 0, 0,0, 0, 0,0 }, + { "ROD", iid1, wr0->e.iid, 0,0, 1, 1,2 }, + { 0, 0, 0, 0, 0, 0, 0, 0 } + }; + rdall (rhc, c3, print, states_seen); thread_state_awake_domain_ok (lookup_thread_state ()); struct ddsi_writer_info wr0_info; wr0_info.auto_dispose = wr0->c.xqos->writer_data_lifecycle.autodispose_unregistered_instances; @@ -966,16 +1000,18 @@ int main (int argc, char **argv) #endif dds_rhc_unregister_wr (rhc, &wr0_info); thread_state_asleep (lookup_thread_state ()); - const struct check c2[] = { - { "ROU", iid0, wr0->e.iid, 0,0, 1, 0,1 }, - { "ROU", iid0, 0, 0,0, 0, 0,0 }, + const struct check c4[] = { + { "ROD", iid0, wr1->e.iid, 0,0, 1, 0,3 }, + { "ROD", iid0, 0, 0,0, 0, 0,0 }, { "ROD", iid1, wr0->e.iid, 0,0, 1, 1,2 }, - { "NOD", iid1, 0, 0,0, 0, 1,0 }, + // { "NOD", iid1, 0, 0,0, 0, 1,0 }, doesn't exist because it is already disposed { 0, 0, 0, 0, 0, 0, 0, 0 } }; - tkall (rhc, c2, print, states_seen); + tkall (rhc, c4, print, states_seen); frhc (rhc); fwr (wr0); + fwr (wr1); + (void)iid_t; } if (1 >= first) diff --git a/src/ddsrt/CMakeLists.txt b/src/ddsrt/CMakeLists.txt index 658e1ee..5c7f24d 100644 --- a/src/ddsrt/CMakeLists.txt +++ b/src/ddsrt/CMakeLists.txt @@ -118,6 +118,7 @@ list(APPEND headers "${include_path}/dds/ddsrt/mh3.h" "${include_path}/dds/ddsrt/io.h" "${include_path}/dds/ddsrt/process.h" + "${include_path}/dds/ddsrt/dynlib.h" "${include_path}/dds/ddsrt/strtod.h" "${include_path}/dds/ddsrt/strtol.h" "${include_path}/dds/ddsrt/types.h" @@ -134,7 +135,8 @@ list(APPEND sources "${source_path}/strtol.c" "${source_path}/mh3.c" "${source_path}/avl.c" - "${source_path}/expand_envvars.c" + "${source_path}/environ.c" + "${source_path}/expand_vars.c" "${source_path}/fibheap.c" "${source_path}/hopscotch.c" "${source_path}/thread_pool.c" @@ -152,7 +154,7 @@ list(APPEND sources # network stack. In order to mix-and-match various compilers, architectures, # operating systems, etc input from the build system is required. foreach(feature atomics cdtors environ heap ifaddrs random rusage - sockets string sync threads time md5 process netstat) + sockets string sync threads time md5 process netstat dynlib filesystem) if(EXISTS "${include_path}/dds/ddsrt/${feature}.h") list(APPEND headers "${include_path}/dds/ddsrt/${feature}.h") file(GLOB_RECURSE @@ -237,6 +239,7 @@ if(NOT WITH_FREERTOS) set(CMAKE_THREAD_PREFER_PTHREAD TRUE) find_package(Threads REQUIRED) target_link_libraries(ddsrt INTERFACE Threads::Threads) + target_link_libraries(ddsrt INTERFACE ${CMAKE_DL_LIBS}) endif() if(WIN32) diff --git a/src/ddsrt/include/dds/ddsrt/dynlib.h b/src/ddsrt/include/dds/ddsrt/dynlib.h new file mode 100644 index 0000000..554438b --- /dev/null +++ b/src/ddsrt/include/dds/ddsrt/dynlib.h @@ -0,0 +1,143 @@ + +/* + * 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 DDSRT_LIBRARY_H +#define DDSRT_LIBRARY_H + +#include "dds/export.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/retcode.h" +#include "dds/ddsrt/attributes.h" + +#if defined (__cplusplus) +extern "C" { +#endif + + +//typedef void *ddsrt_dynlib_t; +typedef struct ddsrt_dynlib *ddsrt_dynlib_t; + + +/** + * @brief Load a dynamic shared library. + * + * The function ddsrt_dlopen() loads the dynamic shared object (shared library) + * file, identified by 'name', sets the handle parameter for the loaded library and + * returns the result with dds return code. + * + * If the 'translate' boolean is true, this function will first try to open the + * library with a translated 'name'. Translated in this context means that if + * "mylibrary" is provided, it will be translated into libmylibrary.so, + * libmylibrary.dylib or mylibrary.dll depending on the platform. + * This translation only happens when the given name does not contain + * a directory. + * If the function isn't able to load the library with the translated name, it + * will still try the given name. + * + * @param[in] name Library file name. + * @param[in] translate Automatic name translation on/off. + * @param[out] handle Library handle that will be assigned after successfull operation. It is assigned to NULL if loading fails. + * + * @returns A dds_return_t indicating success or failure. + * + * @retval DDS_RETCODE_OK + * Library handle was successfully loaded. + * @retval DDS_RETCODE_BAD_PARAM + * There is an invalid input in the parameter list + * @retval DDS_RETCODE_ERROR + * Loading failed. + * Use ddsrt_dlerror() to diagnose the failure. + */ +DDS_EXPORT dds_return_t +ddsrt_dlopen( + const char *name, + bool translate, + ddsrt_dynlib_t *handle) ddsrt_nonnull_all; + +/** + * @brief Close the library. + * + * The function ddsrt_dlclose() informs the system that the + * library, identified by 'handle', is no longer needed. + * will get the memory address of a symbol, + * identified by 'symbol', from a loaded library 'handle'. + * + * @param[in] handle Library handle. + * + * @returns A dds_return_t indicating success or failure. + * + * @retval DDS_RETCODE_OK + * Library handle was successfully closed. + * @retval DDS_RETCODE_ERROR + * Library closing failed. + * Use ddsrt_dlerror() to diagnose the failure. + */ +DDS_EXPORT dds_return_t +ddsrt_dlclose( + ddsrt_dynlib_t handle); + +/** + * @brief Get the memory address of a symbol. + * + * The function ddsrt_dlsym() will get the memory address of a symbol, + * identified by 'symbol', from a loaded library 'handle'. + * + * @param[in] handle Library handle. + * @param[in] symbol Symbol name. + * @param[out] address The memory address of the loaded symbol (void*). + * + * @returns A dds_return_t indicating success or failure. + * + * @retval DDS_RETCODE_OK + * Symbol was found in the loaded library. + * Address parameter is ready to use. + * @retval DDS_RETCODE_ERROR + * Symbol was not found. + * Use ddsrt_dlerror() to diagnose the failure. + */ +DDS_EXPORT dds_return_t +ddsrt_dlsym( + ddsrt_dynlib_t handle, + const char *symbol, + void **address); + +/** + * @brief Get the most recent library related error. + * + * The function ddsrt_dlerror() will return the most recent error of the operating system + * in human readable form. + * + * If no error was found, it's either due to the fact that there + * actually was no error since init or last ddsrt_dlerror() call, + * or due to an unknown unrelated error. + * + * As error reporting function can be used for different purposes, dssrt_dlerror + * function should be called immediately after calling ddsrt_dlopen or ddsrt_dlsym + * function. + * + * @returns A dds_return_t indicating success or failure. + * + * @retval DDS_RETCODE_OK + * Most recent library related error returned. + * @retval DDS_RETCODE_NOT_FOUND + * No library related error found. + */ +DDS_EXPORT dds_return_t +ddsrt_dlerror( + char *buf, + size_t buflen); + +#if defined (__cplusplus) +} +#endif + +#endif /* DDSRT_LIBRARY_H */ diff --git a/src/ddsrt/include/dds/ddsrt/environ.h b/src/ddsrt/include/dds/ddsrt/environ.h index d5d895e..dd65f01 100644 --- a/src/ddsrt/include/dds/ddsrt/environ.h +++ b/src/ddsrt/include/dds/ddsrt/environ.h @@ -14,6 +14,7 @@ #include "dds/export.h" #include "dds/ddsrt/attributes.h" +#include "dds/ddsrt/expand_vars.h" #include "dds/ddsrt/retcode.h" #if defined(__cplusplus) @@ -42,7 +43,7 @@ extern "C" { DDS_EXPORT dds_return_t ddsrt_getenv( const char *name, - char **value) + const char **value) ddsrt_nonnull_all; /** diff --git a/src/ddsrt/include/dds/ddsrt/expand_vars.h b/src/ddsrt/include/dds/ddsrt/expand_vars.h new file mode 100644 index 0000000..78b2326 --- /dev/null +++ b/src/ddsrt/include/dds/ddsrt/expand_vars.h @@ -0,0 +1,78 @@ +/* + * 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 DDSRT_EXPAND_VARS_H +#define DDSRT_EXPAND_VARS_H + +#include "dds/export.h" +#include "dds/ddsrt/attributes.h" +#include "dds/ddsrt/retcode.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef const char * (*expand_lookup_fn)(const char *name, void *data); + +/** + * @brief Expand variables within string. + * + * Expands ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms, but not $X. + * + * The result string should be freed with ddsrt_free(). + * + * @param[in] string String to expand. + * @param[in] lookup Lookup function to retrieve replacement value + * @param[in] data Data passed to lookup function + * + * @returns Allocated char*. + * + * @retval NULL + * Expansion failed. + * @retval Pointer + * Copy of the string argument with the variables expanded. + */ +DDS_EXPORT char* +ddsrt_expand_vars( + const char *string, + expand_lookup_fn lookup, + void * data); + +/** + * @brief Expand variables within string. + * + * Expands $X, ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms, $ and \ + * can be escaped with \. + * + * The result string should be freed with ddsrt_free(). + * + * @param[in] string String to expand. + * @param[in] lookup Lookup function to retrieve replacement value + * @param[in] data Data passed to lookup function + * + * @returns Allocated char*. + * + * @retval NULL + * Expansion failed. + * @retval Pointer + * Copy of the string argument with the variables expanded. + */ +DDS_EXPORT char* +ddsrt_expand_vars_sh( + const char *string, + expand_lookup_fn lookup, + void * data); + +#if defined(__cplusplus) +} +#endif + +#endif /* DDSRT_EXPAND_VARS_H */ diff --git a/src/ddsrt/include/dds/ddsrt/filesystem.h b/src/ddsrt/include/dds/ddsrt/filesystem.h new file mode 100644 index 0000000..60ade53 --- /dev/null +++ b/src/ddsrt/include/dds/ddsrt/filesystem.h @@ -0,0 +1,123 @@ +/* + * 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 FILESYSTEM_H +#define FILESYSTEM_H + +#include + +#include "dds/export.h" +#include "dds/ddsrt/retcode.h" +#include "dds/ddsrt/time.h" + +#if _WIN32 +#include "dds/ddsrt/filesystem/windows.h" +#else +#include "dds/ddsrt/filesystem/posix.h" +#endif + +#if defined (__cplusplus) +extern "C" { +#endif + +struct ddsrt_stat { + ddsrt_mode_t stat_mode; + size_t stat_size; + dds_time_t stat_mtime; +}; + + +struct ddsrt_dirent { + char d_name[DDSRT_PATH_MAX + 1]; +}; + +/** \brief opendir wrapper + * + * Open the directory conform opendir + * + * Precondition: + * none + * + * Possible results: + * - return DDS_RETCODE_OK if directory 'name' is opened + * - DDS_RETCODE_ERROR if 'name' could not + * be found or is not a directory. + */ +DDS_EXPORT dds_return_t ddsrt_opendir(const char *name, ddsrt_dir_handle_t *dir); + +/** \brief closedir wrapper + * + * Close the directory conform closdir + * + * Precondition: + * none + * + * Possible results: + * - return DDS_RETCODE_OK if directory identified by the handle + * is succesfully closed + * - return DDS_RETCODE_ERROR if the handle is invalid. + */ +DDS_EXPORT dds_return_t ddsrt_closedir(ddsrt_dir_handle_t d); + +/** \brief readdir wrapper + * + * Read the directory conform readdir. + * + * Precondition: + * none + * + * Possible results: + * - return DDS_RETCODE_OK if next directory is found + * - return DDS_RETCODE_ERROR if no more directories are found. + */ +DDS_EXPORT dds_return_t ddsrt_readdir(ddsrt_dir_handle_t d, struct ddsrt_dirent *direntp); + +/** \brief stat wrapper + * + * Gets directory status conform stat. + * + * Precondition: + * none + * + * Possible results: + * - return DDS_RETCODE_OK if stat is successful + * - return DDS_RETCODE_ERROR if stat fails. + */ +DDS_EXPORT dds_return_t ddsrt_stat(const char *path, struct ddsrt_stat *buf); + +/** \brief Transforms the given filepath into a platform specific filepath. + * + * This translation function will replace any platform file seperator into + * the fileseperator of the current platform. Doulbe quotes are removed + * as well. + * + * Precondition: + * none + * + * Possible results: + * - returns normalized filepath conform current platform + * - return NULL if out of memory. + */ +DDS_EXPORT char* ddsrt_file_normalize(const char *filepath); + +/** \brief Get file seperator + * + * Possible Results: + * - "" + */ +DDS_EXPORT const char* ddsrt_file_sep(void); + +#if defined (__cplusplus) +} +#endif + +#endif // FILESYSTEM_H diff --git a/src/ddsrt/include/dds/ddsrt/filesystem/posix.h b/src/ddsrt/include/dds/ddsrt/filesystem/posix.h new file mode 100644 index 0000000..7d8e7c2 --- /dev/null +++ b/src/ddsrt/include/dds/ddsrt/filesystem/posix.h @@ -0,0 +1,34 @@ +/* + * 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 DDSRT_FILESYSTEM_POSIX_H +#define DDSRT_FILESYSTEM_POSIX_H + +#include +#include +#include +#include + +typedef DIR *ddsrt_dir_handle_t; +typedef mode_t ddsrt_mode_t; + +#define DDSRT_PATH_MAX PATH_MAX +#define DDSRT_FILESEPCHAR '/' + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* DDSRT_FILESYSTEM_POSIX_H */ diff --git a/src/ddsrt/include/dds/ddsrt/filesystem/windows.h b/src/ddsrt/include/dds/ddsrt/filesystem/windows.h new file mode 100644 index 0000000..abde1d6 --- /dev/null +++ b/src/ddsrt/include/dds/ddsrt/filesystem/windows.h @@ -0,0 +1,34 @@ +/* + * 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 DDSRT_FILESYSTEM_WINDOWS_H +#define DDSRT_FILESYSTEM_WINDOWS_H + +#include +#include + +#include "dds/ddsrt/types.h" + +typedef HANDLE ddsrt_dir_handle_t; +typedef unsigned short ddsrt_mode_t; + +#define DDSRT_PATH_MAX MAX_PATH +#define DDSRT_FILESEPCHAR '\\' + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* DDSRT_FILESYSTEM_WINDOWS_H */ diff --git a/src/ddsrt/include/dds/ddsrt/string.h b/src/ddsrt/include/dds/ddsrt/string.h index 7fca58c..5c8d600 100644 --- a/src/ddsrt/include/dds/ddsrt/string.h +++ b/src/ddsrt/include/dds/ddsrt/string.h @@ -176,6 +176,25 @@ ddsrt_strerror_r( char *buf, size_t buflen); +/** + * @brief Replace substring of null terminated string + * + * @param[in] str pointer to string + * @param[in] srch non-empty string to replace + * @param[in] subst string to substitute character "srch" with + * @param[in] max maximum number of times to replace search, or 0 for unlimited + * + * @returns Pointer to newly allocated string with max occurrences of srch replaced, or + * NULL on allocation failure or if srch is an empty string. + */ +DDS_EXPORT char * +ddsrt_str_replace( + const char *str, + const char *srch, + const char *subst, + size_t max) +ddsrt_nonnull_all; + #if defined (__cplusplus) } #endif diff --git a/src/ddsrt/include/dds/ddsrt/strtol.h b/src/ddsrt/include/dds/ddsrt/strtol.h index c4cb059..07860c2 100644 --- a/src/ddsrt/include/dds/ddsrt/strtol.h +++ b/src/ddsrt/include/dds/ddsrt/strtol.h @@ -21,6 +21,19 @@ extern "C" { #endif +/** + * @brief Convert a character to an integer value + * + * Translates the numeric value of the provided character. For characters in range + * '0' to '9' the returned integer value is 0-9. For the range 'a' to 'z' and 'A' + * to 'Z', the numeric return value is 10-36. + * + * @param[in] chr The character + * + * @returns The integer value for the character, or -1 in case @chr cannot be translated to a numeric value + */ +DDS_EXPORT int32_t ddsrt_todigit(const int chr); + /** * @brief Convert a string to a long long integer. * diff --git a/src/ddsrt/include/dds/ddsrt/threads.h b/src/ddsrt/include/dds/ddsrt/threads.h index e258218..c4d3d81 100644 --- a/src/ddsrt/include/dds/ddsrt/threads.h +++ b/src/ddsrt/include/dds/ddsrt/threads.h @@ -140,11 +140,20 @@ ddsrt_nonnull((1,2,3,4)); /** * @brief Retrieve integer representation of the given thread id. * - * @returns The integer representation of the given thread. + * @returns The integer representation of the current thread. */ DDS_EXPORT ddsrt_tid_t ddsrt_gettid(void); +/** + * @brief Retrieve integer representation of the given thread id. + * + * @returns The integer representation of the given thread. + */ +DDS_EXPORT ddsrt_tid_t +ddsrt_gettid_for_thread( ddsrt_thread_t thread); + + /** * @brief Return thread ID of the calling thread. * diff --git a/src/ddsrt/include/dds/ddsrt/time.h b/src/ddsrt/include/dds/ddsrt/time.h index 5df8358..9069134 100644 --- a/src/ddsrt/include/dds/ddsrt/time.h +++ b/src/ddsrt/include/dds/ddsrt/time.h @@ -60,6 +60,9 @@ typedef int64_t dds_duration_t; /** @name Infinite timeout for relative time */ #define DDS_INFINITY ((dds_duration_t) INT64_MAX) +/** @name Invalid time value for assigning to time output when something goes wrong */ +#define DDS_TIME_INVALID ((dds_time_t) INT64_MIN) + /** @name Invalid duration value */ #define DDS_DURATION_INVALID ((dds_duration_t) INT64_MIN) diff --git a/src/ddsrt/include/dds/ddsrt/xmlparser.h b/src/ddsrt/include/dds/ddsrt/xmlparser.h index 93bd92d..732bb2a 100644 --- a/src/ddsrt/include/dds/ddsrt/xmlparser.h +++ b/src/ddsrt/include/dds/ddsrt/xmlparser.h @@ -12,6 +12,7 @@ #ifndef DDSRT_XMLPARSER_H #define DDSRT_XMLPARSER_H +#include #include #include "dds/export.h" diff --git a/src/ddsrt/src/dynlib/posix/dynlib.c b/src/ddsrt/src/dynlib/posix/dynlib.c new file mode 100644 index 0000000..1a61267 --- /dev/null +++ b/src/ddsrt/src/dynlib/posix/dynlib.c @@ -0,0 +1,96 @@ +/* + * 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 + */ +#include +#include +#include +#include +#include +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/io.h" + +dds_return_t ddsrt_dlopen(const char *name, bool translate, + ddsrt_dynlib_t *handle) { + dds_return_t retcode = DDS_RETCODE_OK; + + assert( handle ); + *handle = NULL; + + if ((translate) && (strrchr(name, '/') == NULL )) { + /* Add lib and suffix to the name and try to open. */ +#if __APPLE__ + static const char suffix[] = ".dylib"; +#else + static const char suffix[] = ".so"; +#endif + char* libName; + ddsrt_asprintf( &libName, "lib%s%s", name, suffix); + *handle = dlopen(libName, RTLD_GLOBAL | RTLD_NOW); + ddsrt_free(libName); + } + + if (*handle == NULL ) { + /* name contains a path, + * (auto)translate is disabled or + * dlopen on translated name failed. */ + *handle = dlopen(name, RTLD_GLOBAL | RTLD_NOW); + } + + + if (*handle != NULL) { + retcode = DDS_RETCODE_OK; + } else { + retcode = DDS_RETCODE_ERROR; + } + + return retcode; +} + +dds_return_t ddsrt_dlclose(ddsrt_dynlib_t handle) { + + assert ( handle ); + return (dlclose(handle) == 0) ? DDS_RETCODE_OK : DDS_RETCODE_ERROR; + +} + +dds_return_t ddsrt_dlsym(ddsrt_dynlib_t handle, const char *symbol, + void **address) { + dds_return_t retcode = DDS_RETCODE_OK; + + assert( handle ); + assert( address ); + assert( symbol ); + + *address = dlsym(handle, symbol); + if (*address == NULL) { + retcode = DDS_RETCODE_ERROR; + } + + return retcode; +} + +dds_return_t ddsrt_dlerror(char *buf, size_t buflen) { + + const char *err; + dds_return_t retcode = DDS_RETCODE_OK; + + assert (buf ); + + err = dlerror(); + if (err == NULL) { + retcode = DDS_RETCODE_NOT_FOUND; + } else { + snprintf(buf, buflen, "%s", err); + } + + return retcode; +} + diff --git a/src/ddsrt/src/dynlib/windows/dynlib.c b/src/ddsrt/src/dynlib/windows/dynlib.c new file mode 100644 index 0000000..7b48240 --- /dev/null +++ b/src/ddsrt/src/dynlib/windows/dynlib.c @@ -0,0 +1,96 @@ +/* + * 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 + */ +#include +#include +#include +#include +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/string.h" + +dds_return_t ddsrt_dlopen(const char *name, bool translate, + ddsrt_dynlib_t *handle) { + dds_return_t retcode = DDS_RETCODE_OK; + + assert( handle ); + *handle = NULL; + + if ((translate) && (strrchr(name, '/') == NULL ) + && (strrchr(name, '\\') == NULL )) { + /* Add suffix to the name and try to open. */ + static const char suffix[] = ".dll"; + size_t len = strlen(name) + sizeof(suffix); + char* libName = ddsrt_malloc(len); + sprintf_s(libName, len, "%s%s", name, suffix); + *handle = (ddsrt_dynlib_t)LoadLibrary(libName); + ddsrt_free(libName); + } + + if (*handle == NULL) { + /* Name contains a path, + * (auto)translate is disabled or + * LoadLibrary on translated name failed. */ + *handle = (ddsrt_dynlib_t)LoadLibrary(name); + } + + if (*handle != NULL) { + retcode = DDS_RETCODE_OK; + } else { + retcode = DDS_RETCODE_ERROR; + } + + return retcode; +} + +dds_return_t ddsrt_dlclose(ddsrt_dynlib_t handle) { + + assert ( handle ); + return (FreeLibrary((HMODULE)handle) == 0) ? DDS_RETCODE_ERROR : DDS_RETCODE_OK; +} + +dds_return_t ddsrt_dlsym(ddsrt_dynlib_t handle, const char *symbol, + void **address) { + dds_return_t retcode = DDS_RETCODE_OK; + + assert( handle ); + assert( address ); + assert( symbol ); + + *address = GetProcAddress((HMODULE)handle, symbol); + if ( *address == NULL ) { + retcode = DDS_RETCODE_ERROR; + } + + return retcode; +} + +dds_return_t ddsrt_dlerror(char *buf, size_t buflen) { + + /* Hopefully (and likely), the last error is + * related to a Library action attempt. */ + DWORD err; + assert ( buf ); + + dds_return_t retcode = DDS_RETCODE_OK; + + err = GetLastError(); + if ( err == 0 ) { + retcode = DDS_RETCODE_NOT_FOUND; + } else { + ddsrt_strerror_r(err, buf, buflen); + SetLastError(0); + } + + return retcode; + +} + diff --git a/src/ddsrt/src/environ.c b/src/ddsrt/src/environ.c new file mode 100644 index 0000000..501d92b --- /dev/null +++ b/src/ddsrt/src/environ.c @@ -0,0 +1,59 @@ +/* + * 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 + */ +#include +#include +#include +#include +#include + +#include "dds/ddsrt/expand_vars.h" +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/log.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/process.h" + +struct expand_env_data +{ + uint32_t domid; + char idstr[20]; +}; + +static const char * expand_lookup_env(const char *name, void * data) +{ + const char *env = NULL; + struct expand_env_data * env_data = data; + + if (ddsrt_getenv (name, &env) == DDS_RETCODE_OK) { + /* ok */ + } else if (strcmp (name, "$") == 0 || strcmp (name, "CYCLONEDDS_PID") == 0) { + (void) snprintf (env_data->idstr, sizeof (env_data->idstr), "%"PRIdPID, ddsrt_getpid ()); + env = env_data->idstr; + } else if (strcmp (name, "CYCLONEDDS_DOMAIN_ID") == 0 && env_data->domid != UINT32_MAX) { + (void) snprintf (env_data->idstr, sizeof (env_data->idstr), "%"PRIu32, env_data->domid); + env = env_data->idstr; + } + return env; +} + +char *ddsrt_expand_envvars_sh (const char *src0, uint32_t domid) +{ + struct expand_env_data env = { .domid = domid, .idstr = "" }; + return ddsrt_expand_vars_sh(src0, &expand_lookup_env, &env); +} + +char *ddsrt_expand_envvars (const char *src0, uint32_t domid) +{ + struct expand_env_data env = { .domid = domid, .idstr = "" }; + return ddsrt_expand_vars(src0, &expand_lookup_env, &env); +} + diff --git a/src/ddsrt/src/environ/posix/environ.c b/src/ddsrt/src/environ/posix/environ.c index 1f8b84f..c2e61a9 100644 --- a/src/ddsrt/src/environ/posix/environ.c +++ b/src/ddsrt/src/environ/posix/environ.c @@ -24,7 +24,7 @@ isenvvar(const char *name) } dds_return_t -ddsrt_getenv(const char *name, char **value) +ddsrt_getenv(const char *name, const char **value) { char *env; diff --git a/src/ddsrt/src/environ/solaris2.6/environ.c b/src/ddsrt/src/environ/solaris2.6/environ.c index 83f0d8f..07d113a 100644 --- a/src/ddsrt/src/environ/solaris2.6/environ.c +++ b/src/ddsrt/src/environ/solaris2.6/environ.c @@ -27,7 +27,7 @@ isenvvar(const char *name) } dds_return_t -ddsrt_getenv(const char *name, char **value) +ddsrt_getenv(const char *name, const char **value) { char *env; diff --git a/src/ddsrt/src/environ/windows/environ.c b/src/ddsrt/src/environ/windows/environ.c index a5b2f90..7589545 100644 --- a/src/ddsrt/src/environ/windows/environ.c +++ b/src/ddsrt/src/environ/windows/environ.c @@ -26,7 +26,7 @@ isenvvar(const char *name) DDSRT_WARNING_MSVC_OFF(4996) dds_return_t -ddsrt_getenv(const char *name, char **value) +ddsrt_getenv(const char *name, const char **value) { char *env; diff --git a/src/ddsrt/src/expand_envvars.c b/src/ddsrt/src/expand_vars.c similarity index 72% rename from src/ddsrt/src/expand_envvars.c rename to src/ddsrt/src/expand_vars.c index faa166a..e0396bd 100644 --- a/src/ddsrt/src/expand_envvars.c +++ b/src/ddsrt/src/expand_vars.c @@ -15,13 +15,13 @@ #include #include -#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/expand_vars.h" #include "dds/ddsrt/heap.h" #include "dds/ddsrt/log.h" #include "dds/ddsrt/string.h" #include "dds/ddsrt/process.h" -typedef char * (*expand_fn)(const char *src0, uint32_t domid); +typedef char * (*expand_fn)(const char *src0, expand_lookup_fn lookup, void * data); static void expand_append (char **dst, size_t *sz, size_t *pos, char c) { @@ -33,46 +33,33 @@ static void expand_append (char **dst, size_t *sz, size_t *pos, char c) (*pos)++; } -static char *expand_env (const char *name, char op, const char *alt, expand_fn expand, uint32_t domid) +static char *expand_var (const char *name, char op, const char *alt, expand_fn expand, expand_lookup_fn lookup, void * data) { - char idstr[20]; - char *env = NULL; - dds_return_t ret; - - if ((ret = ddsrt_getenv (name, &env)) == DDS_RETCODE_OK) { - /* ok */ - } else if (strcmp (name, "$") == 0 || strcmp (name, "CYCLONEDDS_PID") == 0) { - (void) snprintf (idstr, sizeof (idstr), "%"PRIdPID, ddsrt_getpid ()); - env = idstr; - } else if (strcmp (name, "CYCLONEDDS_DOMAIN_ID") == 0 && domid != UINT32_MAX) { - (void) snprintf (idstr, sizeof (idstr), "%"PRIu32, domid); - env = idstr; - } - + const char *val = lookup (name, data); switch (op) { case 0: - return ddsrt_strdup (env ? env : ""); + return ddsrt_strdup (val ? val : ""); case '-': - return env && *env ? ddsrt_strdup (env) : expand (alt, domid); + return val && *val ? ddsrt_strdup (val) : expand (alt, lookup, data); case '?': - if (env && *env) { - return ddsrt_strdup (env); + if (val && *val) { + return ddsrt_strdup (val); } else { - char *altx = expand (alt, domid); - DDS_ILOG (DDS_LC_ERROR, domid, "%s: %s\n", name, altx); + char *altx = expand (alt, lookup, data); + DDS_LOG (DDS_LC_ERROR, "%s: %s\n", name, altx); ddsrt_free (altx); return NULL; } case '+': - return env && *env ? expand (alt, domid) : ddsrt_strdup (""); + return val && *val ? expand (alt, lookup, data) : ddsrt_strdup (""); default: abort (); return NULL; } } -static char *expand_envbrace (const char **src, expand_fn expand, uint32_t domid) +static char *expand_varbrace (const char **src, expand_fn expand, expand_lookup_fn lookup, void * data) { const char *start = *src + 1; char *name, *x; @@ -89,7 +76,7 @@ static char *expand_envbrace (const char **src, expand_fn expand, uint32_t domid name[*src - start] = 0; if (**src == '}') { (*src)++; - x = expand_env (name, 0, NULL, expand, domid); + x = expand_var (name, 0, NULL, expand, lookup, data); ddsrt_free (name); return x; } else { @@ -133,7 +120,7 @@ static char *expand_envbrace (const char **src, expand_fn expand, uint32_t domid memcpy (alt, altstart, (size_t) (*src - altstart)); alt[*src - altstart] = 0; (*src)++; - x = expand_env (name, op, alt, expand, domid); + x = expand_var (name, op, alt, expand, lookup, data); ddsrt_free (alt); ddsrt_free (name); return x; @@ -143,7 +130,7 @@ err: return NULL; } -static char *expand_envsimple (const char **src, expand_fn expand, uint32_t domid) +static char *expand_varsimple (const char **src, expand_fn expand, expand_lookup_fn lookup, void * data) { const char *start = *src; char *name, *x; @@ -154,22 +141,22 @@ static char *expand_envsimple (const char **src, expand_fn expand, uint32_t domi name = ddsrt_malloc ((size_t) (*src - start) + 1); memcpy (name, start, (size_t) (*src - start)); name[*src - start] = 0; - x = expand_env (name, 0, NULL, expand, domid); + x = expand_var (name, 0, NULL, expand, lookup, data); ddsrt_free (name); return x; } -static char *expand_envchar (const char **src, expand_fn expand, uint32_t domid) +static char *expand_varchar (const char **src, expand_fn expand, expand_lookup_fn lookup, void * data) { char name[2]; assert (**src); name[0] = **src; name[1] = 0; (*src)++; - return expand_env (name, 0, NULL, expand, domid); + return expand_var (name, 0, NULL, expand, lookup, data); } -char *ddsrt_expand_envvars_sh (const char *src0, uint32_t domid) +char *ddsrt_expand_vars_sh (const char *src0, expand_lookup_fn lookup, void * data) { /* Expands $X, ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms; $ and \ can be escaped with \ */ const char *src = src0; @@ -192,11 +179,11 @@ char *ddsrt_expand_envvars_sh (const char *src0, uint32_t domid) ddsrt_free(dst); return NULL; } else if (*src == '{') { - x = expand_envbrace (&src, &ddsrt_expand_envvars_sh, domid); + x = expand_varbrace (&src, &ddsrt_expand_vars_sh, lookup, data); } else if (isalnum ((unsigned char) *src) || *src == '_') { - x = expand_envsimple (&src, &ddsrt_expand_envvars_sh, domid); + x = expand_varsimple (&src, &ddsrt_expand_vars_sh, lookup, data); } else { - x = expand_envchar (&src, &ddsrt_expand_envvars_sh, domid); + x = expand_varchar (&src, &ddsrt_expand_vars_sh, lookup, data); } if (x == NULL) { ddsrt_free(dst); @@ -215,7 +202,7 @@ char *ddsrt_expand_envvars_sh (const char *src0, uint32_t domid) return dst; } -char *ddsrt_expand_envvars (const char *src0, uint32_t domid) +char *ddsrt_expand_vars (const char *src0, expand_lookup_fn lookup, void * data) { /* Expands ${X}, ${X:-Y}, ${X:+Y}, ${X:?Y} forms, but not $X */ const char *src = src0; @@ -225,7 +212,7 @@ char *ddsrt_expand_envvars (const char *src0, uint32_t domid) if (*src == '$' && *(src + 1) == '{') { char *x, *xp; src++; - x = expand_envbrace (&src, &ddsrt_expand_envvars, domid); + x = expand_varbrace (&src, &ddsrt_expand_vars, lookup, data); if (x == NULL) { ddsrt_free(dst); return NULL; @@ -242,3 +229,4 @@ char *ddsrt_expand_envvars (const char *src0, uint32_t domid) expand_append (&dst, &sz, &pos, 0); return dst; } + diff --git a/src/ddsrt/src/filesystem/posix/filesystem.c b/src/ddsrt/src/filesystem/posix/filesystem.c new file mode 100644 index 0000000..1db647c --- /dev/null +++ b/src/ddsrt/src/filesystem/posix/filesystem.c @@ -0,0 +1,115 @@ +/* + * 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 + */ + +#include + +#include "dds/ddsrt/filesystem.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/heap.h" + +dds_return_t ddsrt_opendir(const char *name, ddsrt_dir_handle_t *dir) +{ + dds_return_t result = DDS_RETCODE_ERROR; + DIR *d; + if (dir) { + d = opendir(name); + if (d) { + *dir = d; + result = DDS_RETCODE_OK; + } + } + return result; +} + +dds_return_t ddsrt_readdir(ddsrt_dir_handle_t d, struct ddsrt_dirent *direntp) +{ + dds_return_t result; + struct dirent *d_entry; + + result = DDS_RETCODE_ERROR; + if (d && direntp) { + d_entry = readdir(d); + if (d_entry) { + ddsrt_strlcpy(direntp->d_name, d_entry->d_name, sizeof(direntp->d_name)); + result = DDS_RETCODE_OK; + } + } + + return result; +} + +dds_return_t ddsrt_closedir(ddsrt_dir_handle_t d) +{ + dds_return_t result; + + result = DDS_RETCODE_ERROR; + if (d) { + if (closedir(d) == 0) { + result = DDS_RETCODE_OK; + } + } + + return result; +} + +dds_return_t ddsrt_stat(const char *path, struct ddsrt_stat *buf) +{ + dds_return_t result; + struct stat _buf; + int r; + + r = stat(path, &_buf); + if (r == 0) { + buf->stat_mode = _buf.st_mode; + buf->stat_size = (size_t) _buf.st_size; + buf->stat_mtime = DDS_SECS(_buf.st_mtime); + result = DDS_RETCODE_OK; + } else { + result = DDS_RETCODE_ERROR; + } + + return result; +} + +char * ddsrt_file_normalize(const char *filepath) +{ + char *norm; + const char *fpPtr; + char *normPtr; + + norm = NULL; + if (filepath != NULL) { + norm = ddsrt_malloc (strlen (filepath) + 1); + /* replace any / or \ by DDSRT_FILESEPCHAR */ + fpPtr = (char *) filepath; + normPtr = norm; + while (*fpPtr != '\0') { + *normPtr = *fpPtr; + if (*fpPtr == '/' || *fpPtr == '\\') { + *normPtr = DDSRT_FILESEPCHAR; + normPtr++; + } else { + if (*fpPtr != '\"') { + normPtr++; + } + } + fpPtr++; + } + *normPtr = '\0'; + } + return norm; +} + +const char *ddsrt_file_sep(void) +{ + return "/"; +} diff --git a/src/ddsrt/src/filesystem/windows/filesystem.c b/src/ddsrt/src/filesystem/windows/filesystem.c new file mode 100644 index 0000000..068d76e --- /dev/null +++ b/src/ddsrt/src/filesystem/windows/filesystem.c @@ -0,0 +1,122 @@ +/* + * 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 + */ + +#include + +#include "dds/ddsrt/filesystem.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/io.h" + +dds_return_t ddsrt_opendir(const char *name, ddsrt_dir_handle_t *dir) +{ + dds_return_t result; + + TCHAR szDir[DDSRT_PATH_MAX + 1]; + WIN32_FIND_DATA FileData; + HANDLE hList; + + result = DDS_RETCODE_ERROR; + if (dir) { + snprintf(szDir, DDSRT_PATH_MAX, "%s\\*", name); + hList = FindFirstFile(szDir, &FileData); + + if (hList != INVALID_HANDLE_VALUE) { + *dir = hList; + result = DDS_RETCODE_OK; + } + } + + return result; +} + +dds_return_t ddsrt_readdir(ddsrt_dir_handle_t d, struct ddsrt_dirent *direntp) +{ + dds_return_t result; + WIN32_FIND_DATA FileData; + BOOL r; + + if (direntp) { + r = FindNextFile(d, &FileData); + if (r) { + ddsrt_strlcpy(direntp->d_name, FileData.cFileName, sizeof(direntp->d_name)); + result = DDS_RETCODE_OK; + } else { + result = DDS_RETCODE_ERROR; + } + } else { + result = DDS_RETCODE_ERROR; + } + + return result; +} + +dds_return_t ddsrt_closedir(ddsrt_dir_handle_t d) +{ + FindClose(d); + + return DDS_RETCODE_OK; +} + +dds_return_t ddsrt_stat(const char *path, struct ddsrt_stat *buf) +{ + dds_return_t result; + struct _stat _buf; + int r; + + r = _stat(path, &_buf); + if (r == 0) { + buf->stat_mode = _buf.st_mode; + buf->stat_size = _buf.st_size; + buf->stat_mtime = DDS_SECS(_buf.st_mtime);; + result = DDS_RETCODE_OK; + } else { + result = DDS_RETCODE_ERROR; + } + + return result; +} + +char * ddsrt_file_normalize(const char *filepath) +{ + char *norm; + const char *fpPtr; + char *normPtr; + + norm = NULL; + if ((filepath != NULL) && (*filepath != '\0')) { + norm = ddsrt_malloc(strlen(filepath) + 1); + /* replace any / or \ by DDSRT_FILESEPCHAR */ + fpPtr = (char *) filepath; + normPtr = norm; + while (*fpPtr != '\0') { + *normPtr = *fpPtr; + if ((*fpPtr == '/') || (*fpPtr == '\\')) { + *normPtr = DDSRT_FILESEPCHAR; + normPtr++; + } else { + if (*fpPtr != '\"') { + normPtr++; + } + } + fpPtr++; + } + *normPtr = '\0'; + } + + return norm; +} + +const char *ddsrt_file_sep(void) +{ + return "\\"; +} diff --git a/src/ddsrt/src/log.c b/src/ddsrt/src/log.c index f426b90..bf20966 100644 --- a/src/ddsrt/src/log.c +++ b/src/ddsrt/src/log.c @@ -215,10 +215,6 @@ static void vlog1 (const struct ddsrt_log_cfg_impl *cfg, uint32_t cat, uint32_t used with the global one. */ assert (domid == cfg->c.domid || cfg == &logconfig); - if (*fmt == 0) { - return; - } - lb = &log_buffer; /* Thread-local buffer is always initialized with all zeroes. The pos @@ -227,6 +223,20 @@ static void vlog1 (const struct ddsrt_log_cfg_impl *cfg, uint32_t cat, uint32_t lb->pos = BUF_OFFSET; lb->buf[lb->pos] = 0; } + + /* drop any prefix of new lines if there is current no data in the buffer: + there are some tricky problems in tracing some details depending on + enabled categories (like which subset of discovery related data gets + traced), and it sometimes helps to be able to trace just a newline + knowing it won't have any effect if nothing is buffered */ + if (lb->pos == BUF_OFFSET) { + while (*fmt == '\n') + fmt++; + } + if (*fmt == 0) { + return; + } + nrem = sizeof (lb->buf) - lb->pos; if (nrem > 0) { n = vsnprintf (lb->buf + lb->pos, nrem, fmt, ap); diff --git a/src/ddsrt/src/string.c b/src/ddsrt/src/string.c index d048e5f..e625535 100644 --- a/src/ddsrt/src/string.c +++ b/src/ddsrt/src/string.c @@ -15,7 +15,9 @@ #include #include "dds/ddsrt/heap.h" +#include "dds/ddsrt/misc.h" #include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" int ddsrt_strcasecmp( @@ -162,3 +164,41 @@ ddsrt_strdup( return ddsrt_memdup(str, strlen(str) + 1); } + +char * +ddsrt_str_replace( + const char *str, + const char *srch, + const char *subst, + size_t max) +{ + const size_t lsrch = strlen(srch); + if (lsrch == 0) /* empty search string is treated as failure */ + return NULL; + + const size_t lsubst = strlen(subst); + const size_t lstr = strlen(str); + const char *cur = str; + char *res; + size_t cnt; + + if (max == 0) + max = SIZE_MAX; + for (cnt = 0; (cur = strstr(cur, srch)) != NULL && cnt < max; cnt++) + cur += lsrch; + if ((res = ddsrt_malloc(lstr + cnt * (lsubst - lsrch) + 1)) == NULL) + return NULL; + char *tmp = res; + cur = str; + while (cnt--) + { + const char *found = strstr(cur, srch); + const size_t skip = (size_t)(found - cur); + memcpy(tmp, cur, skip); + memcpy(tmp + skip, subst, lsubst); + tmp += skip + lsubst; + cur += skip + lsrch; + } + memcpy(tmp, cur, lstr - (size_t) (cur - str) + 1); + return res; +} diff --git a/src/ddsrt/src/strtol.c b/src/ddsrt/src/strtol.c index 5269d96..f8d4223 100644 --- a/src/ddsrt/src/strtol.c +++ b/src/ddsrt/src/strtol.c @@ -16,7 +16,7 @@ #include "dds/ddsrt/strtol.h" -static int ddsrt_todigit(const int chr) +int32_t ddsrt_todigit(const int chr) { if (chr >= '0' && chr <= '9') { return chr - '0'; diff --git a/src/ddsrt/src/sync/posix/sync.c b/src/ddsrt/src/sync/posix/sync.c index a7f92e8..7dcd203 100644 --- a/src/ddsrt/src/sync/posix/sync.c +++ b/src/ddsrt/src/sync/posix/sync.c @@ -159,22 +159,18 @@ ddsrt_cond_broadcast (ddsrt_cond_t *cond) void ddsrt_rwlock_init (ddsrt_rwlock_t *rwlock) { - int err = 0; - assert(rwlock != NULL); /* process-shared attribute is set to PTHREAD_PROCESS_PRIVATE by default */ - if ((err = pthread_rwlock_init(&rwlock->rwlock, NULL)) != 0) + if (pthread_rwlock_init(&rwlock->rwlock, NULL) != 0) abort(); } void ddsrt_rwlock_destroy (ddsrt_rwlock_t *rwlock) { - int err; - assert(rwlock != NULL); - if ((err = pthread_rwlock_destroy (&rwlock->rwlock)) != 0) + if (pthread_rwlock_destroy (&rwlock->rwlock) != 0) abort(); } diff --git a/src/ddsrt/src/threads/freertos/threads.c b/src/ddsrt/src/threads/freertos/threads.c index be4e177..be636c5 100644 --- a/src/ddsrt/src/threads/freertos/threads.c +++ b/src/ddsrt/src/threads/freertos/threads.c @@ -83,6 +83,13 @@ ddsrt_gettid(void) return status.xTaskNumber; } +DDS_EXPORT ddsrt_tid_t +ddsrt_gettid_for_thread( ddsrt_thread_t thread) +{ + return (ddsrt_tid_t)thread.task; +} + + ddsrt_thread_t ddsrt_thread_self(void) { diff --git a/src/ddsrt/src/threads/posix/threads.c b/src/ddsrt/src/threads/posix/threads.c index 14d09fd..3244202 100644 --- a/src/ddsrt/src/threads/posix/threads.c +++ b/src/ddsrt/src/threads/posix/threads.c @@ -348,6 +348,14 @@ ddsrt_gettid(void) return tid; } +ddsrt_tid_t +ddsrt_gettid_for_thread( ddsrt_thread_t thread) +{ + return (ddsrt_tid_t) thread.v; + +} + + ddsrt_thread_t ddsrt_thread_self(void) { diff --git a/src/ddsrt/src/threads/windows/threads.c b/src/ddsrt/src/threads/windows/threads.c index 2bc8052..a028e6c 100644 --- a/src/ddsrt/src/threads/windows/threads.c +++ b/src/ddsrt/src/threads/windows/threads.c @@ -173,6 +173,14 @@ ddsrt_gettid(void) return GetCurrentThreadId(); } + +ddsrt_tid_t +ddsrt_gettid_for_thread( ddsrt_thread_t thread) +{ + return (ddsrt_tid_t) thread.tid; + +} + ddsrt_thread_t ddsrt_thread_self( void) diff --git a/src/ddsrt/src/xmlparser.c b/src/ddsrt/src/xmlparser.c index 873aa0d..8820b71 100644 --- a/src/ddsrt/src/xmlparser.c +++ b/src/ddsrt/src/xmlparser.c @@ -27,9 +27,12 @@ #define TOK_CLOSE_TAG -5 #define TOK_SHORTHAND_CLOSE_TAG -6 #define TOK_ERROR -7 +#define TOK_CDATA -8 #define NOMARKER (~(size_t)0) +static const char *cdata_magic = ""); return next_token (st, payload); + } else if (peek_chars (st, cdata_magic, 0)) { + tok = TOK_CDATA; } else if (peek_chars (st, ""); return next_token (st, payload); @@ -652,7 +657,6 @@ static int parse_element (struct ddsrt_xmlp_state *st, uintptr_t parentinfo) } } else { /* text */ - static const char *cdata_magic = "") + + +# Create a separate shared library that will be used to +# test dynamic library loading. +set(test_lib_name "dltestlib") +add_library(${test_lib_name} SHARED dllib.c) +# Force the lib to be at the same location, no matter what platform or build type. +set_target_properties( + ${test_lib_name} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR} + RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR} + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_CURRENT_BINARY_DIR} + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_CURRENT_BINARY_DIR} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR} + LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR} + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_CURRENT_BINARY_DIR} + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_CURRENT_BINARY_DIR} ) +# Use proper export for this test lib. +#generate_dummy_export_header(${test_lib_name} BASE_NAME dds LIB_TEST) +target_include_directories(${test_lib_name} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") +# Let the cunit application know the location and name of the library. +file(TO_NATIVE_PATH "${CMAKE_CURRENT_BINARY_DIR}" test_lib_native_dir) +file(TO_NATIVE_PATH "/" test_lib_sep) +string(REPLACE "\\" "\\\\" test_lib_dir ${test_lib_native_dir}) +string(REPLACE "\\" "\\\\" test_lib_sep ${test_lib_sep}) +configure_file("dl_test.h.in" "${CMAKE_CURRENT_BINARY_DIR}/include/dl_test.h" @ONLY) +# Let ctest set the proper library path when executing library tests. +unset(test_lib_tests) +process_cunit_source_file("dynlib.c" test_lib_header test_lib_suites test_lib_tests) +foreach(libtest ${test_lib_tests}) + string(REPLACE ":" ";" libtest ${libtest}) + list(GET libtest 0 suite) + list(GET libtest 1 test) + set(libtestname "CUnit_${suite}_${test}") + if("${CMAKE_HOST_SYSTEM}" MATCHES ".*Windows.*") + set_property(TEST ${libtestname} APPEND PROPERTY ENVIRONMENT "${test_lib_native_dir}") + else() + set_property(TEST ${libtestname} APPEND PROPERTY ENVIRONMENT "LD_LIBRARY_PATH=${test_lib_native_dir};$ENV{LD_LIBRARY_PATH}") + endif() +endforeach() + generate_dummy_export_header( cunit_ddsrt BASE_NAME dds EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/include/dds/export.h") +generate_export_header(${test_lib_name} BASE_NAME LIB_TEST) + if(HAVE_MULTI_PROCESS) # A separate application is required to test process management. add_executable(process_app process_app.c) diff --git a/src/ddsrt/tests/dl_test.h.in b/src/ddsrt/tests/dl_test.h.in new file mode 100644 index 0000000..69a05ab --- /dev/null +++ b/src/ddsrt/tests/dl_test.h.in @@ -0,0 +1,22 @@ +/* + * 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 DDSRT_TEST_DL_TEST_H +#define DDSRT_TEST_DL_TEST_H + +/* Get the library name information from cmake. */ +#define TEST_LIB_NAME "@test_lib_name@" +#define TEST_LIB_DIR "@test_lib_dir@" +#define TEST_LIB_SEP "@test_lib_sep@" +#define TEST_LIB_SUFFIX "@CMAKE_SHARED_LIBRARY_SUFFIX@" +#define TEST_LIB_PREFIX "@CMAKE_SHARED_LIBRARY_PREFIX@" + +#endif /* DDSRT_TEST_DL_TEST_H */ diff --git a/src/ddsrt/tests/dllib.c b/src/ddsrt/tests/dllib.c new file mode 100644 index 0000000..b63d34b --- /dev/null +++ b/src/ddsrt/tests/dllib.c @@ -0,0 +1,27 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "lib_test_export.h" + +static int g_val = -1; + +LIB_TEST_EXPORT void set_int(int val); +void set_int(int val) +{ + g_val = val; +} + +LIB_TEST_EXPORT int get_int(void); +int get_int(void) +{ + return g_val; +} + diff --git a/src/ddsrt/tests/dynlib.c b/src/ddsrt/tests/dynlib.c new file mode 100644 index 0000000..9b8d5df --- /dev/null +++ b/src/ddsrt/tests/dynlib.c @@ -0,0 +1,193 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include "CUnit/Test.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/environ.h" +#include "dl_test.h" + +#define TEST_LIB_FILE ""TEST_LIB_PREFIX""TEST_LIB_NAME""TEST_LIB_SUFFIX"" +#define TEST_LIB_ABSOLUTE ""TEST_LIB_DIR""TEST_LIB_SEP""TEST_LIB_FILE"" + +#define TEST_ABORT_IF_NULL(var, msg) \ +do { \ + if (var == NULL) { \ + char err[256]; \ + r = ddsrt_dlerror(err, sizeof(err)); \ + CU_ASSERT_EQUAL_FATAL(r, DDS_RETCODE_OK); \ + printf("\n%s", err); \ + CU_FAIL_FATAL(msg); \ + } \ +} while(0) + + +/* + * Load a library. + */ +CU_Test(ddsrt_library, dlopen_path) +{ + dds_return_t r; + ddsrt_dynlib_t l; + + printf("Absolute lib: %s\n", TEST_LIB_ABSOLUTE); + r = ddsrt_dlopen(TEST_LIB_ABSOLUTE, false, &l); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(l); + TEST_ABORT_IF_NULL(l, "ddsrt_dlopen() failed. Is the proper library path set?"); + + r = ddsrt_dlclose(l); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); +} + +CU_Test(ddsrt_library, dlopen_file) +{ + dds_return_t r; + ddsrt_dynlib_t l; + + r = ddsrt_dlopen(TEST_LIB_FILE, false, &l); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(l); + TEST_ABORT_IF_NULL(l, "ddsrt_dlopen() failed. Is the proper library path set?"); + + r = ddsrt_dlclose(l); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); +} + +CU_Test(ddsrt_library, dlopen_name) +{ + dds_return_t r; + ddsrt_dynlib_t l; + + r = ddsrt_dlopen(TEST_LIB_NAME, true, &l); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(l); + TEST_ABORT_IF_NULL(l, "ddsrt_dlopen() failed. Is the proper library path set?"); + + r = ddsrt_dlclose(l); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); +} + +CU_Test(ddsrt_library, dlopen_unknown) +{ + char buffer[256]; + dds_return_t r; + ddsrt_dynlib_t l; + + r = ddsrt_dlopen("UnknownLib", false, &l); + CU_ASSERT_NOT_EQUAL(r, DDS_RETCODE_OK); + CU_ASSERT_PTR_NULL_FATAL(l); + + r = ddsrt_dlerror(buffer, sizeof(buffer)); + CU_ASSERT_EQUAL_FATAL(r, DDS_RETCODE_OK); + printf("\n%s", buffer); +} + +CU_Test(ddsrt_library, dlsym) +{ + dds_return_t r; + ddsrt_dynlib_t l; + void* f; + + r = ddsrt_dlopen(TEST_LIB_NAME, true, &l); + CU_ASSERT_PTR_NOT_NULL(l); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); + TEST_ABORT_IF_NULL(l, "ddsrt_dlopen() failed. Is the proper library path set?"); + + r = ddsrt_dlsym(l, "get_int", &f); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(f); + TEST_ABORT_IF_NULL(f, "ddsrt_dlsym(l, \"get_int\") failed."); + + r = ddsrt_dlclose(l); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); +} + +CU_Test(ddsrt_library, dlsym_unknown) +{ + char buffer[256]; + dds_return_t r; + ddsrt_dynlib_t l; + void* f; + + r = ddsrt_dlopen(TEST_LIB_NAME, true, &l); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(l); + TEST_ABORT_IF_NULL(l,"ddsrt_dlopen() failed. Is the proper library path set?"); + + r = ddsrt_dlsym(l, "UnknownSym", &f); + CU_ASSERT_EQUAL(r, DDS_RETCODE_ERROR); + CU_ASSERT_PTR_NULL_FATAL(f); + + r = ddsrt_dlerror(buffer, sizeof(buffer)); + CU_ASSERT_EQUAL_FATAL(r, DDS_RETCODE_OK); + printf("\n%s", buffer); + + r = ddsrt_dlclose(l); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); +} + +typedef void (*func_set_int)(int val); +typedef int (*func_get_int)(void); +CU_Test(ddsrt_library, call) +{ + int get_int = 0; + int set_int = 1234; + func_get_int f_get; + func_set_int f_set; + dds_return_t r; + ddsrt_dynlib_t l; + + r = ddsrt_dlopen(TEST_LIB_NAME, true, &l); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(l); + TEST_ABORT_IF_NULL(l, "ddsrt_dlopen() failed. Is the proper library path set?"); + + r = ddsrt_dlsym(l, "get_int", (void **)&f_get); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(f_get); + TEST_ABORT_IF_NULL(f_get, "ddsrt_dlsym(l, \"get_int\") failed."); + + r = ddsrt_dlsym(l, "set_int", (void **)&f_set); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(f_set); + TEST_ABORT_IF_NULL(f_set, "ddsrt_dlsym(l, \"set_int\") failed."); + + assert(f_set != 0 && f_get != 0); /* for Clang static analyzer */ + f_set(set_int); + get_int = f_get(); + CU_ASSERT_EQUAL(set_int, get_int); + + r = ddsrt_dlclose(l); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); +} + +CU_Test(ddsrt_library, dlclose_error) +{ + dds_return_t r; + ddsrt_dynlib_t l; + + r = ddsrt_dlopen(TEST_LIB_NAME, true, &l); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); + CU_ASSERT_PTR_NOT_NULL(l); + TEST_ABORT_IF_NULL(l, "ddsrt_dlopen() failed. Is the proper library path set?"); + + r = ddsrt_dlclose(l); + CU_ASSERT_EQUAL(r, DDS_RETCODE_OK); + + r = ddsrt_dlclose( l ); /*already closed handle */ + CU_ASSERT_EQUAL(r, DDS_RETCODE_ERROR); + +} diff --git a/src/ddsrt/tests/environ.c b/src/ddsrt/tests/environ.c index 0a11334..564445b 100644 --- a/src/ddsrt/tests/environ.c +++ b/src/ddsrt/tests/environ.c @@ -26,7 +26,7 @@ CU_Theory((const char *name), ddsrt_environ, bad_name) dds_return_t rc; static const char value[] = "bar"; static char dummy[] = "foobar"; - char *ptr; + const char *ptr; rc = ddsrt_setenv(name, value); CU_ASSERT_EQUAL(rc, DDS_RETCODE_BAD_PARAMETER); @@ -71,7 +71,7 @@ CU_Test(ddsrt_environ, getenv) static const char name[] = "foo"; static const char value[] = "bar"; static char dummy[] = "foobar"; - char *ptr; + const char *ptr; /* Ensure "not found" is returned. */ rc = ddsrt_unsetenv(name); diff --git a/src/ddsrt/tests/process_app.c b/src/ddsrt/tests/process_app.c index 1613391..9251a72 100644 --- a/src/ddsrt/tests/process_app.c +++ b/src/ddsrt/tests/process_app.c @@ -57,7 +57,7 @@ static int test_pid(void) static int test_env(void) { int ret = TEST_EXIT_FAILURE; - char *envptr = NULL; + const char *envptr = NULL; if (ddsrt_getenv(TEST_ENV_VAR_NAME, &envptr) == DDS_RETCODE_OK) { printf(" Process: env %s=%s.\n", TEST_ENV_VAR_NAME, envptr); if (strcmp(envptr, TEST_ENV_VAR_VALUE) == 0) { diff --git a/src/ddsrt/tests/string.c b/src/ddsrt/tests/string.c index eae2cc7..2d809ea 100644 --- a/src/ddsrt/tests/string.c +++ b/src/ddsrt/tests/string.c @@ -10,8 +10,10 @@ * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause */ #include +#include #include "CUnit/Theory.h" +#include "dds/ddsrt/heap.h" #include "dds/ddsrt/string.h" typedef enum { eq, lt, gt } eq_t; @@ -67,3 +69,27 @@ CU_Theory((const char *s1, const char *s2, size_t n, eq_t e), ddsrt_strncasecmp, CU_ASSERT((e == eq && r == 0) || (e == lt && r < 0) || (e == gt && r > 0)); } +CU_TheoryDataPoints(ddsrt_str_replace, basic) = { + CU_DataPoints(const char *, "", "a", "aaa", "aaa", "aaa", "aaa", "a", "aa", "acaca", "aacaacaa", "aaa"), + CU_DataPoints(const char *, "a", "", "a", "a", "a", "aa", "aaa", "a", "a", "aa", "a"), + CU_DataPoints(const char *, "b", "b", "b", "bb", "bb", "b", "b", "b", "bb", "b", ""), + CU_DataPoints(size_t, 0, 0, 0, 1, 2, 0, 0, 10, 0, 2, 0), + CU_DataPoints(const char *, "", NULL, "bbb", "bbaa", "bbbba", "ba", "a", "bb", "bbcbbcbb", "bcbcaa", ""), +}; + +CU_Theory((const char *str, const char *srch, const char *subst, size_t max, const char * exp), ddsrt_str_replace, basic) +{ + char * r = ddsrt_str_replace(str, srch, subst, max); + if (exp != NULL) + { + CU_ASSERT_FATAL(r != NULL); + assert(r != NULL); /* for Clang static analyzer */ + CU_ASSERT(strcmp(r, exp) == 0); + ddsrt_free(r); + } + else + { + CU_ASSERT_FATAL(r == NULL); + } +} + diff --git a/src/features.h.in b/src/features.h.in new file mode 100644 index 0000000..636f19f --- /dev/null +++ b/src/features.h.in @@ -0,0 +1,24 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef _DDS_PUBLIC_FEATURES_H_ +#define _DDS_PUBLIC_FEATURES_H_ + +/* Whether or not support for DDS Security is included */ +#cmakedefine DDS_HAS_SECURITY @DDS_HAS_SECURITY@ + +/* Whether or not support for the lifespan QoS is included */ +#cmakedefine DDS_HAS_LIFESPAN @DDS_HAS_LIFESPAN@ + +/* Whether or not support for generating "deadline missed" events is included */ +#cmakedefine DDS_HAS_DEADLINE_MISSED @DDS_HAS_DEADLINE_MISSED@ + +#endif diff --git a/src/idlc/src/org/eclipse/cyclonedds/generator/BasicType.java b/src/idlc/src/org/eclipse/cyclonedds/generator/BasicType.java index 6ddb67b..8964e7f 100644 --- a/src/idlc/src/org/eclipse/cyclonedds/generator/BasicType.java +++ b/src/idlc/src/org/eclipse/cyclonedds/generator/BasicType.java @@ -20,15 +20,15 @@ public class BasicType extends AbstractType { BOOLEAN ("bool", "DDS_OP_TYPE_BOO", "DDS_OP_SUBTYPE_BOO", Alignment.BOOL, "Boolean"), OCTET ("uint8_t", "DDS_OP_TYPE_1BY", "DDS_OP_SUBTYPE_1BY", Alignment.ONE, "Octet"), - CHAR ("char", "DDS_OP_TYPE_1BY", "DDS_OP_SUBTYPE_1BY", Alignment.ONE, "Char"), - SHORT ("int16_t", "DDS_OP_TYPE_2BY", "DDS_OP_SUBTYPE_2BY", Alignment.TWO, "Short"), + CHAR ("char", "DDS_OP_TYPE_1BY | DDS_OP_FLAG_SGN", "DDS_OP_SUBTYPE_1BY | DDS_OP_FLAG_SGN", Alignment.ONE, "Char"), + SHORT ("int16_t", "DDS_OP_TYPE_2BY | DDS_OP_FLAG_SGN", "DDS_OP_SUBTYPE_2BY | DDS_OP_FLAG_SGN", Alignment.TWO, "Short"), USHORT ("uint16_t", "DDS_OP_TYPE_2BY", "DDS_OP_SUBTYPE_2BY", Alignment.TWO, "UShort"), - LONG ("int32_t", "DDS_OP_TYPE_4BY", "DDS_OP_SUBTYPE_4BY", Alignment.FOUR, "Long"), + LONG ("int32_t", "DDS_OP_TYPE_4BY | DDS_OP_FLAG_SGN", "DDS_OP_SUBTYPE_4BY | DDS_OP_FLAG_SGN", Alignment.FOUR, "Long"), ULONG ("uint32_t", "DDS_OP_TYPE_4BY", "DDS_OP_SUBTYPE_4BY", Alignment.FOUR, "ULong"), - LONGLONG ("int64_t", "DDS_OP_TYPE_8BY", "DDS_OP_SUBTYPE_8BY", Alignment.EIGHT, "LongLong"), + LONGLONG ("int64_t", "DDS_OP_TYPE_8BY | DDS_OP_FLAG_SGN", "DDS_OP_SUBTYPE_8BY | DDS_OP_FLAG_SGN", Alignment.EIGHT, "LongLong"), ULONGLONG ("uint64_t", "DDS_OP_TYPE_8BY", "DDS_OP_SUBTYPE_8BY", Alignment.EIGHT, "ULongLong"), - FLOAT ("float", "DDS_OP_TYPE_4BY", "DDS_OP_SUBTYPE_4BY", Alignment.FOUR, "Float"), - DOUBLE ("double", "DDS_OP_TYPE_8BY", "DDS_OP_SUBTYPE_8BY", Alignment.EIGHT, "Double"), + FLOAT ("float", "DDS_OP_TYPE_4BY | DDS_OP_FLAG_FP", "DDS_OP_SUBTYPE_4BY | DDS_OP_FLAG_FP", Alignment.FOUR, "Float"), + DOUBLE ("double", "DDS_OP_TYPE_8BY | DDS_OP_FLAG_FP", "DDS_OP_SUBTYPE_8BY | DDS_OP_FLAG_FP", Alignment.EIGHT, "Double"), STRING ("char *", "DDS_OP_TYPE_STR", "DDS_OP_SUBTYPE_STR", Alignment.PTR, "String"); public final String cType; diff --git a/src/security/CMakeLists.txt b/src/security/CMakeLists.txt new file mode 100644 index 0000000..1c8ec01 --- /dev/null +++ b/src/security/CMakeLists.txt @@ -0,0 +1,22 @@ +# +# 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 +# +cmake_minimum_required(VERSION 3.7) + +if(ENABLE_SECURITY) + add_subdirectory(api) + add_subdirectory(core) + + if(ENABLE_SSL) + add_subdirectory(openssl) + add_subdirectory(builtin_plugins) + endif() +endif() diff --git a/src/security/api/CMakeLists.txt b/src/security/api/CMakeLists.txt new file mode 100644 index 0000000..fe9e0b4 --- /dev/null +++ b/src/security/api/CMakeLists.txt @@ -0,0 +1,28 @@ +# +# Copyright(c) 2006 to 2019 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# + + +add_library(security_api INTERFACE) + +target_include_directories( + security_api INTERFACE + "$" + "$" + "$" +) + +install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/include/" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + COMPONENT dev) + + diff --git a/src/security/api/include/dds/security/dds_security_api.h b/src/security/api/include/dds/security/dds_security_api.h new file mode 100644 index 0000000..d242b02 --- /dev/null +++ b/src/security/api/include/dds/security/dds_security_api.h @@ -0,0 +1,34 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef DDS_SECURITY_API_H +#define DDS_SECURITY_API_H + +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds_security_api_access_control.h" +#include "dds_security_api_authentication.h" +#include "dds_security_api_cryptography.h" + + +#if defined (__cplusplus) +extern "C" { +#endif + +/* Integration functions for Security plugins */ +typedef int (*plugin_init)(const char *argument, void **context, struct ddsi_domaingv *gv); +typedef int (*plugin_finalize)(void *context); + +#if defined (__cplusplus) +} +#endif + +#endif /* DDS_SECURITY_API_H */ diff --git a/src/security/api/include/dds/security/dds_security_api_access_control.h b/src/security/api/include/dds/security/dds_security_api_access_control.h new file mode 100644 index 0000000..5bc7f26 --- /dev/null +++ b/src/security/api/include/dds/security/dds_security_api_access_control.h @@ -0,0 +1,294 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef DDS_SECURITY_ACCESS_CONTROL_API_H +#define DDS_SECURITY_ACCESS_CONTROL_API_H + +#include "dds_security_api_types.h" +#include "dds_security_api_authentication.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* AccessControl Component */ +struct dds_security_access_control; +typedef struct dds_security_access_control dds_security_access_control; + + +/* AccessControlListener Interface */ +struct dds_security_access_control_listener; +typedef struct dds_security_access_control_listener dds_security_access_control_listener; + +typedef DDS_Security_boolean (*DDS_Security_access_control_listener_on_revoke_permissions)( + const dds_security_access_control *plugin, + const DDS_Security_PermissionsHandle handle); + +struct dds_security_access_control_listener +{ + DDS_Security_access_control_listener_on_revoke_permissions on_revoke_permissions; +}; + +/* AccessControl Interface */ +typedef DDS_Security_PermissionsHandle (*DDS_Security_access_control_validate_local_permissions)( + dds_security_access_control *instance, + const dds_security_authentication *auth_plugin, + const DDS_Security_IdentityHandle identity, + const DDS_Security_DomainId domain_id, + const DDS_Security_Qos *participant_qos, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_PermissionsHandle (*DDS_Security_access_control_validate_remote_permissions)( + dds_security_access_control *instance, + const dds_security_authentication *auth_plugin, + const DDS_Security_IdentityHandle local_identity_handle, + const DDS_Security_IdentityHandle remote_identity_handle, + const DDS_Security_PermissionsToken *remote_permissions_token, + const DDS_Security_AuthenticatedPeerCredentialToken *remote_credential_token, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_check_create_participant)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_Qos *participant_qos, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_check_create_datawriter)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_char *topic_name, + const DDS_Security_Qos *writer_qos, + const DDS_Security_PartitionQosPolicy *partition, + const DDS_Security_DataTags *data_tag, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_check_create_datareader)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_char *topic_name, + const DDS_Security_Qos *reader_qos, + const DDS_Security_PartitionQosPolicy *partition, + const DDS_Security_DataTags *data_tag, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_check_create_topic)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_char *topic_name, + const DDS_Security_Qos *topic_qos, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_check_local_datawriter_register_instance)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_Entity *writer, + const DDS_Security_DynamicData *key, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_check_local_datawriter_dispose_instance)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_Entity *writer, + const DDS_Security_DynamicData key, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_check_remote_participant)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_ParticipantBuiltinTopicDataSecure *participant_data, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_check_remote_datawriter)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_PublicationBuiltinTopicDataSecure *publication_data, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_check_remote_datareader)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_SubscriptionBuiltinTopicDataSecure *subscription_data, + DDS_Security_boolean *relay_only, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_check_remote_topic)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_TopicBuiltinTopicData *topic_data, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_check_local_datawriter_match)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle writer_permissions_handle, + const DDS_Security_PermissionsHandle reader_permissions_handle, + const DDS_Security_PublicationBuiltinTopicDataSecure *publication_data, + const DDS_Security_SubscriptionBuiltinTopicDataSecure *subscription_data, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_check_local_datareader_match)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle reader_permissions_handle, + const DDS_Security_PermissionsHandle writer_permissions_handle, + const DDS_Security_SubscriptionBuiltinTopicDataSecure *subscription_data, + const DDS_Security_PublicationBuiltinTopicDataSecure *publication_data, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_check_remote_datawriter_register_instance)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_Entity *reader, + const DDS_Security_InstanceHandle publication_handle, + const DDS_Security_DynamicData key, + const DDS_Security_InstanceHandle instance_handle, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_check_remote_datawriter_dispose_instance)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_Entity *reader, + const DDS_Security_InstanceHandle publication_handle, + const DDS_Security_DynamicData key, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_get_permissions_token)( + dds_security_access_control *instance, + DDS_Security_PermissionsToken *permissions_token, + const DDS_Security_PermissionsHandle handle, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_get_permissions_credential_token)( + dds_security_access_control *instance, + DDS_Security_PermissionsCredentialToken *permissions_credential_token, + const DDS_Security_PermissionsHandle handle, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_set_listener)( + dds_security_access_control *instance, + const dds_security_access_control_listener *listener, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_return_permissions_token)( + dds_security_access_control *instance, + const DDS_Security_PermissionsToken *token, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_return_permissions_credential_token)( + dds_security_access_control *instance, + const DDS_Security_PermissionsCredentialToken *permissions_credential_token, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_get_participant_sec_attributes)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + DDS_Security_ParticipantSecurityAttributes *attributes, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_get_topic_sec_attributes)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_char *topic_name, + DDS_Security_TopicSecurityAttributes *attributes, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_get_datawriter_sec_attributes)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_char *topic_name, + const DDS_Security_PartitionQosPolicy *partition, + const DDS_Security_DataTagQosPolicy *data_tag, + DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_get_datareader_sec_attributes)( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_char *topic_name, + const DDS_Security_PartitionQosPolicy *partition, + const DDS_Security_DataTagQosPolicy *data_tag, + DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_return_participant_sec_attributes)( + dds_security_access_control *instance, + const DDS_Security_ParticipantSecurityAttributes *attributes, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_return_topic_sec_attributes)( + dds_security_access_control *instance, + const DDS_Security_TopicSecurityAttributes *attributes, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_return_datawriter_sec_attributes)( + dds_security_access_control *instance, + const DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_return_datareader_sec_attributes)( + dds_security_access_control *instance, + const DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_access_control_return_permissions_handle)( + dds_security_access_control *instance, + DDS_Security_PermissionsHandle permissions_handle, + DDS_Security_SecurityException *ex); + +struct dds_security_access_control +{ + struct ddsi_domaingv *gv; + + DDS_Security_access_control_validate_local_permissions validate_local_permissions; + DDS_Security_access_control_validate_remote_permissions validate_remote_permissions; + DDS_Security_access_control_check_create_participant check_create_participant; + DDS_Security_access_control_check_create_datawriter check_create_datawriter; + DDS_Security_access_control_check_create_datareader check_create_datareader; + DDS_Security_access_control_check_create_topic check_create_topic; + DDS_Security_access_control_check_local_datawriter_register_instance check_local_datawriter_register_instance; + DDS_Security_access_control_check_local_datawriter_dispose_instance check_local_datawriter_dispose_instance; + DDS_Security_access_control_check_remote_participant check_remote_participant; + DDS_Security_access_control_check_remote_datawriter check_remote_datawriter; + DDS_Security_access_control_check_remote_datareader check_remote_datareader; + DDS_Security_access_control_check_remote_topic check_remote_topic; + DDS_Security_access_control_check_local_datawriter_match check_local_datawriter_match; + DDS_Security_access_control_check_local_datareader_match check_local_datareader_match; + DDS_Security_access_control_check_remote_datawriter_register_instance check_remote_datawriter_register_instance; + DDS_Security_access_control_check_remote_datawriter_dispose_instance check_remote_datawriter_dispose_instance; + DDS_Security_access_control_get_permissions_token get_permissions_token; + DDS_Security_access_control_get_permissions_credential_token get_permissions_credential_token; + DDS_Security_access_control_set_listener set_listener; + DDS_Security_access_control_return_permissions_token return_permissions_token; + DDS_Security_access_control_return_permissions_credential_token return_permissions_credential_token; + DDS_Security_access_control_get_participant_sec_attributes get_participant_sec_attributes; + DDS_Security_access_control_get_topic_sec_attributes get_topic_sec_attributes; + DDS_Security_access_control_get_datawriter_sec_attributes get_datawriter_sec_attributes; + DDS_Security_access_control_get_datareader_sec_attributes get_datareader_sec_attributes; + DDS_Security_access_control_return_participant_sec_attributes return_participant_sec_attributes; + DDS_Security_access_control_return_topic_sec_attributes return_topic_sec_attributes; + DDS_Security_access_control_return_datawriter_sec_attributes return_datawriter_sec_attributes; + DDS_Security_access_control_return_datareader_sec_attributes return_datareader_sec_attributes; + DDS_Security_access_control_return_permissions_handle return_permissions_handle; +}; + +#if defined(__cplusplus) +} +#endif + +#endif /* DDS_SECURITY_ACCESS_CONTROL_API_H */ diff --git a/src/security/api/include/dds/security/dds_security_api_authentication.h b/src/security/api/include/dds/security/dds_security_api_authentication.h new file mode 100644 index 0000000..5909dac --- /dev/null +++ b/src/security/api/include/dds/security/dds_security_api_authentication.h @@ -0,0 +1,184 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef DDS_SECURITY_AUTHENTICATION_API_H +#define DDS_SECURITY_AUTHENTICATION_API_H + +#include "dds_security_api_types.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* Authentication Component */ +struct dds_security_authentication; +typedef struct dds_security_authentication dds_security_authentication; + +struct dds_security_authentication_listener; +typedef struct dds_security_authentication_listener dds_security_authentication_listener; + +/* AuthenticationListener interface */ +typedef DDS_Security_boolean (*DDS_Security_authentication_listener_on_revoke_identity)( + const dds_security_authentication *plugin, + const DDS_Security_IdentityHandle handle); + +typedef DDS_Security_boolean (*DDS_Security_authentication_listener_on_status_changed)( + dds_security_authentication_listener *context, + const dds_security_authentication *plugin, + const DDS_Security_IdentityHandle handle, + const DDS_Security_AuthStatusKind status_kind); + +struct dds_security_authentication_listener +{ + DDS_Security_authentication_listener_on_revoke_identity on_revoke_identity; + DDS_Security_authentication_listener_on_status_changed on_status_changed; +}; + +typedef DDS_Security_ValidationResult_t (*DDS_Security_authentication_validate_local_identity)( + dds_security_authentication *instance, + DDS_Security_IdentityHandle *local_identity_handle, + DDS_Security_GUID_t *adjusted_participant_guid, + const DDS_Security_DomainId domain_id, + const DDS_Security_Qos *participant_qos, + const DDS_Security_GUID_t *candidate_participant_guid, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_authentication_get_identity_token)( + dds_security_authentication *instance, + DDS_Security_IdentityToken *identity_token, + const DDS_Security_IdentityHandle handle, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_authentication_get_identity_status_token)( + dds_security_authentication *instance, + DDS_Security_IdentityStatusToken *identity_status_token, + const DDS_Security_IdentityHandle handle, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_authentication_set_permissions_credential_and_token)( + dds_security_authentication *instance, + const DDS_Security_IdentityHandle handle, + const DDS_Security_PermissionsCredentialToken *permissions_credential, + const DDS_Security_PermissionsToken *permissions_token, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_ValidationResult_t (*DDS_Security_authentication_validate_remote_identity)( + dds_security_authentication *instance, + DDS_Security_IdentityHandle *remote_identity_handle, + DDS_Security_AuthRequestMessageToken *local_auth_request_token, + const DDS_Security_AuthRequestMessageToken *remote_auth_request_token, + const DDS_Security_IdentityHandle local_identity_handle, + const DDS_Security_IdentityToken *remote_identity_token, + const DDS_Security_GUID_t *remote_participant_guid, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_ValidationResult_t (*DDS_Security_authentication_begin_handshake_request)( + dds_security_authentication *instance, + DDS_Security_HandshakeHandle *handshake_handle, + DDS_Security_HandshakeMessageToken *handshake_message, + const DDS_Security_IdentityHandle initiator_identity_handle, + const DDS_Security_IdentityHandle replier_identity_handle, + const DDS_Security_OctetSeq *serialized_local_participant_data, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_ValidationResult_t (*DDS_Security_authentication_begin_handshake_reply)( + dds_security_authentication *instance, + DDS_Security_HandshakeHandle *handshake_handle, + DDS_Security_HandshakeMessageToken *handshake_message_out, + const DDS_Security_HandshakeMessageToken *handshake_message_in, + const DDS_Security_IdentityHandle initiator_identity_handle, + const DDS_Security_IdentityHandle replier_identity_handle, + const DDS_Security_OctetSeq *serialized_local_participant_data, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_ValidationResult_t (*DDS_Security_authentication_process_handshake)( + dds_security_authentication *instance, + DDS_Security_HandshakeMessageToken *handshake_message_out, + const DDS_Security_HandshakeMessageToken *handshake_message_in, + const DDS_Security_HandshakeHandle handshake_handle, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_SharedSecretHandle (*DDS_Security_authentication_get_shared_secret)( + dds_security_authentication *instance, + const DDS_Security_HandshakeHandle handshake_handle, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_authentication_get_authenticated_peer_credential_token)( + dds_security_authentication *instance, + DDS_Security_AuthenticatedPeerCredentialToken *peer_credential_token, + const DDS_Security_HandshakeHandle handshake_handle, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_authentication_set_listener)( + dds_security_authentication *instance, + const dds_security_authentication_listener *listener, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_authentication_return_identity_token)( + dds_security_authentication *instance, + const DDS_Security_IdentityToken *token, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_authentication_return_identity_status_token)( + dds_security_authentication *instance, + const DDS_Security_IdentityStatusToken *token, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_authentication_return_authenticated_peer_credential_token)( + dds_security_authentication *instance, + const DDS_Security_AuthenticatedPeerCredentialToken *peer_credential_token, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_authentication_return_handshake_handle)( + dds_security_authentication *instance, + const DDS_Security_HandshakeHandle handshake_handle, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_authentication_return_identity_handle)( + dds_security_authentication *instance, + const DDS_Security_IdentityHandle identity_handle, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_authentication_return_sharedsecret_handle)( + dds_security_authentication *instance, + const DDS_Security_SharedSecretHandle sharedsecret_handle, + DDS_Security_SecurityException *ex); + +struct dds_security_authentication +{ + struct ddsi_domaingv *gv; + + DDS_Security_authentication_validate_local_identity validate_local_identity; + DDS_Security_authentication_get_identity_token get_identity_token; + DDS_Security_authentication_get_identity_status_token get_identity_status_token; + DDS_Security_authentication_set_permissions_credential_and_token set_permissions_credential_and_token; + DDS_Security_authentication_validate_remote_identity validate_remote_identity; + DDS_Security_authentication_begin_handshake_request begin_handshake_request; + DDS_Security_authentication_begin_handshake_reply begin_handshake_reply; + DDS_Security_authentication_process_handshake process_handshake; + DDS_Security_authentication_get_shared_secret get_shared_secret; + DDS_Security_authentication_get_authenticated_peer_credential_token get_authenticated_peer_credential_token; + DDS_Security_authentication_set_listener set_listener; + DDS_Security_authentication_return_identity_token return_identity_token; + DDS_Security_authentication_return_identity_status_token return_identity_status_token; + DDS_Security_authentication_return_authenticated_peer_credential_token return_authenticated_peer_credential_token; + DDS_Security_authentication_return_handshake_handle return_handshake_handle; + DDS_Security_authentication_return_identity_handle return_identity_handle; + DDS_Security_authentication_return_sharedsecret_handle return_sharedsecret_handle; +}; + +#if defined(__cplusplus) +} +#endif + +#endif /* DDS_SECURITY_AUTHENTICATION_API_H */ diff --git a/src/security/api/include/dds/security/dds_security_api_cryptography.h b/src/security/api/include/dds/security/dds_security_api_cryptography.h new file mode 100644 index 0000000..2f3144e --- /dev/null +++ b/src/security/api/include/dds/security/dds_security_api_cryptography.h @@ -0,0 +1,270 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef DDS_SECURITY_API_CRYPTOGRAPHY_H +#define DDS_SECURITY_API_CRYPTOGRAPHY_H + +#include "dds_security_api_types.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* Crypto Component */ +struct dds_security_crypto_key_factory; +typedef struct dds_security_crypto_key_factory dds_security_crypto_key_factory; + +struct dds_security_crypto_key_exchange; +typedef struct dds_security_crypto_key_exchange dds_security_crypto_key_exchange; + +struct dds_security_crypto_transform; +typedef struct dds_security_crypto_transform dds_security_crypto_transform; + +/* CryptoKeyFactory interface */ +typedef DDS_Security_ParticipantCryptoHandle (*DDS_Security_crypto_key_factory_register_local_participant)( + dds_security_crypto_key_factory *instance, + const DDS_Security_IdentityHandle participant_identity, + const DDS_Security_PermissionsHandle participant_permissions, + const DDS_Security_PropertySeq *participant_properties, + const DDS_Security_ParticipantSecurityAttributes *participant_security_attributes, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_ParticipantCryptoHandle (*DDS_Security_crypto_key_factory_register_matched_remote_participant)( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle local_participant_crypto_handle, + const DDS_Security_IdentityHandle remote_participant_identity, + const DDS_Security_PermissionsHandle remote_participant_permissions, + const DDS_Security_SharedSecretHandle shared_secret, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_DatawriterCryptoHandle (*DDS_Security_crypto_key_factory_register_local_datawriter)( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle participant_crypto, + const DDS_Security_PropertySeq *datawriter_properties, + const DDS_Security_EndpointSecurityAttributes *datawriter_security_attributes, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_DatareaderCryptoHandle (*DDS_Security_crypto_key_factory_register_matched_remote_datareader)( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatawriterCryptoHandle local_datawriter_crypto_handle, + const DDS_Security_ParticipantCryptoHandle remote_participant_crypto, + const DDS_Security_SharedSecretHandle shared_secret, + const DDS_Security_boolean relay_only, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_DatareaderCryptoHandle (*DDS_Security_crypto_key_factory_register_local_datareader)( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle participant_crypto_handle, + const DDS_Security_PropertySeq *datareader_properties, + const DDS_Security_EndpointSecurityAttributes *datareader_security_attributes, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_DatawriterCryptoHandle (*DDS_Security_crypto_key_factory_register_matched_remote_datawriter)( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatareaderCryptoHandle local_datareader_crypto_handle, + const DDS_Security_ParticipantCryptoHandle remote_participant_crypt, + const DDS_Security_SharedSecretHandle shared_secret, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_key_factory_unregister_participant)( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle participant_crypto_handle, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_key_factory_unregister_datawriter)( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatawriterCryptoHandle datawriter_crypto_handle, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_key_factory_unregister_datareader)( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatareaderCryptoHandle datareader_crypto_handle, + DDS_Security_SecurityException *ex); + +struct dds_security_crypto_key_factory +{ + DDS_Security_crypto_key_factory_register_local_participant register_local_participant; + DDS_Security_crypto_key_factory_register_matched_remote_participant register_matched_remote_participant; + DDS_Security_crypto_key_factory_register_local_datawriter register_local_datawriter; + DDS_Security_crypto_key_factory_register_matched_remote_datareader register_matched_remote_datareader; + DDS_Security_crypto_key_factory_register_local_datareader register_local_datareader; + DDS_Security_crypto_key_factory_register_matched_remote_datawriter register_matched_remote_datawriter; + DDS_Security_crypto_key_factory_unregister_participant unregister_participant; + DDS_Security_crypto_key_factory_unregister_datawriter unregister_datawriter; + DDS_Security_crypto_key_factory_unregister_datareader unregister_datareader; +}; + +/* CryptoKeyExchange Interface */ +typedef DDS_Security_boolean (*DDS_Security_crypto_key_exchange_create_local_participant_crypto_tokens)( + dds_security_crypto_key_exchange *instance, + DDS_Security_ParticipantCryptoTokenSeq *local_participant_crypto_tokens, + const DDS_Security_ParticipantCryptoHandle local_participant_crypto, + const DDS_Security_ParticipantCryptoHandle remote_participant_crypto, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_key_exchange_set_remote_participant_crypto_tokens)( + dds_security_crypto_key_exchange *instance, + const DDS_Security_ParticipantCryptoHandle local_participant_crypto, + const DDS_Security_ParticipantCryptoHandle remote_participant_crypto, + const DDS_Security_ParticipantCryptoTokenSeq *remote_participant_tokens, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_key_exchange_create_local_datawriter_crypto_tokens)( + dds_security_crypto_key_exchange *instance, + DDS_Security_DatawriterCryptoTokenSeq *local_datawriter_crypto_tokens, + const DDS_Security_DatawriterCryptoHandle local_datawriter_crypto, + const DDS_Security_DatareaderCryptoHandle remote_datareader_crypto, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_key_exchange_set_remote_datawriter_crypto_tokens)( + dds_security_crypto_key_exchange *instance, + const DDS_Security_DatareaderCryptoHandle local_datareader_crypto, + const DDS_Security_DatawriterCryptoHandle remote_datawriter_crypto, + const DDS_Security_DatawriterCryptoTokenSeq *remote_datawriter_tokens, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_key_exchange_create_local_datareader_crypto_tokens)( + dds_security_crypto_key_exchange *instance, + DDS_Security_DatareaderCryptoTokenSeq *local_datareader_cryto_tokens, + const DDS_Security_DatareaderCryptoHandle local_datareader_crypto, + const DDS_Security_DatawriterCryptoHandle remote_datawriter_crypto, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_key_exchange_set_remote_datareader_crypto_tokens)( + dds_security_crypto_key_exchange *instance, + const DDS_Security_DatawriterCryptoHandle local_datawriter_crypto, + const DDS_Security_DatareaderCryptoHandle remote_datareader_crypto, + const DDS_Security_DatareaderCryptoTokenSeq *remote_datareader_tokens, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_key_exchange_return_crypto_tokens)( + dds_security_crypto_key_exchange *instance, + DDS_Security_CryptoTokenSeq *crypto_tokens, + DDS_Security_SecurityException *ex); + +struct dds_security_crypto_key_exchange +{ + DDS_Security_crypto_key_exchange_create_local_participant_crypto_tokens create_local_participant_crypto_tokens; + DDS_Security_crypto_key_exchange_set_remote_participant_crypto_tokens set_remote_participant_crypto_tokens; + DDS_Security_crypto_key_exchange_create_local_datawriter_crypto_tokens create_local_datawriter_crypto_tokens; + DDS_Security_crypto_key_exchange_set_remote_datawriter_crypto_tokens set_remote_datawriter_crypto_tokens; + DDS_Security_crypto_key_exchange_create_local_datareader_crypto_tokens create_local_datareader_crypto_tokens; + DDS_Security_crypto_key_exchange_set_remote_datareader_crypto_tokens set_remote_datareader_crypto_tokens; + DDS_Security_crypto_key_exchange_return_crypto_tokens return_crypto_tokens; +}; + +/* CryptoTransform Interface */ +typedef DDS_Security_boolean (*DDS_Security_crypto_transform_encode_serialized_payload)( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_buffer, + DDS_Security_OctetSeq *extra_inline_qos, + const DDS_Security_OctetSeq *plain_buffer, + const DDS_Security_DatawriterCryptoHandle sending_datawriter_crypto, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_transform_encode_datawriter_submessage)( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_rtps_submessage, + const DDS_Security_OctetSeq *plain_rtps_submessage, + const DDS_Security_DatawriterCryptoHandle sending_datawriter_crypto, + const DDS_Security_DatareaderCryptoHandleSeq *receiving_datareader_crypto_list, + DDS_Security_long *receiving_datareader_crypto_list_index, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_transform_encode_datareader_submessage)( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_rtps_submessage, + const DDS_Security_OctetSeq *plain_rtps_submessage, + const DDS_Security_DatareaderCryptoHandle sending_datareader_crypto, + const DDS_Security_DatawriterCryptoHandleSeq *receiving_datawriter_crypto_list, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_transform_encode_rtps_message)( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_rtps_message, + const DDS_Security_OctetSeq *plain_rtps_message, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + const DDS_Security_ParticipantCryptoHandleSeq *receiving_participant_crypto_list, + DDS_Security_long *receiving_participant_crypto_list_index, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_transform_decode_rtps_message)( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_buffer, + const DDS_Security_OctetSeq *encoded_buffer, + const DDS_Security_ParticipantCryptoHandle receiving_participant_crypto, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_transform_preprocess_secure_submsg)( + dds_security_crypto_transform *instance, + DDS_Security_DatawriterCryptoHandle *datawriter_crypto, + DDS_Security_DatareaderCryptoHandle *datareader_crypto, + DDS_Security_SecureSubmessageCategory_t *secure_submessage_category, + const DDS_Security_OctetSeq *encoded_rtps_submessage, + const DDS_Security_ParticipantCryptoHandle receiving_participant_crypto, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_transform_decode_datawriter_submessage)( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_rtps_submessage, + const DDS_Security_OctetSeq *encoded_rtps_submessage, + const DDS_Security_DatareaderCryptoHandle receiving_datareader_crypto, + const DDS_Security_DatawriterCryptoHandle sending_datawriter_crypto, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_transform_decode_datareader_submessage)( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_rtps_message, + const DDS_Security_OctetSeq *encoded_rtps_message, + const DDS_Security_DatawriterCryptoHandle receiving_datawriter_crypto, + const DDS_Security_DatareaderCryptoHandle sending_datareader_crypto, + DDS_Security_SecurityException *ex); + +typedef DDS_Security_boolean (*DDS_Security_crypto_transform_decode_serialized_payload)( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_buffer, + const DDS_Security_OctetSeq *encoded_buffer, + const DDS_Security_OctetSeq *inline_qos, + const DDS_Security_DatareaderCryptoHandle receiving_datareader_crypto, + const DDS_Security_DatawriterCryptoHandle sending_datawriter_crypto, + DDS_Security_SecurityException *ex); + +struct dds_security_crypto_transform +{ + DDS_Security_crypto_transform_encode_serialized_payload encode_serialized_payload; + DDS_Security_crypto_transform_encode_datawriter_submessage encode_datawriter_submessage; + DDS_Security_crypto_transform_encode_datareader_submessage encode_datareader_submessage; + DDS_Security_crypto_transform_encode_rtps_message encode_rtps_message; + DDS_Security_crypto_transform_decode_rtps_message decode_rtps_message; + DDS_Security_crypto_transform_preprocess_secure_submsg preprocess_secure_submsg; + DDS_Security_crypto_transform_decode_datawriter_submessage decode_datawriter_submessage; + DDS_Security_crypto_transform_decode_datareader_submessage decode_datareader_submessage; + DDS_Security_crypto_transform_decode_serialized_payload decode_serialized_payload; +}; + +typedef struct dds_security_cryptography +{ + struct ddsi_domaingv *gv; + + dds_security_crypto_transform *crypto_transform; + dds_security_crypto_key_factory *crypto_key_factory; + dds_security_crypto_key_exchange *crypto_key_exchange; +} dds_security_cryptography; + +#if defined(__cplusplus) +} +#endif + +#endif /* DDS_SECURITY_API_CRYPTOGRAPHY_H */ diff --git a/src/security/api/include/dds/security/dds_security_api_defs.h b/src/security/api/include/dds/security/dds_security_api_defs.h new file mode 100644 index 0000000..fbc2539 --- /dev/null +++ b/src/security/api/include/dds/security/dds_security_api_defs.h @@ -0,0 +1,216 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef DDS_SECURITY_API_DEF_H +#define DDS_SECURITY_API_DEF_H + +#include "dds_security_api_err.h" + +#if defined (__cplusplus) +extern "C" { +#endif + + + +/************************************************************************** + * * + * Return values. * + * * + **************************************************************************/ +typedef enum { + DDS_SECURITY_VALIDATION_OK, + DDS_SECURITY_VALIDATION_FAILED, + DDS_SECURITY_VALIDATION_PENDING_RETRY, + DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST, + DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE, + DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE +} DDS_Security_ValidationResult_t; + +#define DDS_SECURITY_HANDLE_NIL (0) + +#define DDS_SECURITY_SUCCESS (0) +#define DDS_SECURITY_FAILED (-1) + + +/************************************************************************** + * * + * Attribute flags. * + * * + **************************************************************************/ +#define DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_PROTECTED (1u ) +#define DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_PROTECTED (1u << 1) +#define DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_PROTECTED (1u << 2) +#define DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID (1u << 31) + +#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED (1u ) +#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_ENCRYPTED (1u << 1) +#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_ENCRYPTED (1u << 2) +#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED (1u << 3) +#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_AUTHENTICATED (1u << 4) +#define DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_AUTHENTICATED (1u << 5) + +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_READ_PROTECTED (1u ) +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_WRITE_PROTECTED (1u << 1) +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_DISCOVERY_PROTECTED (1u << 2) +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_PROTECTED (1u << 3) +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_PROTECTED (1u << 4) +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_KEY_PROTECTED (1u << 5) +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_LIVELINESS_PROTECTED (1u << 6) +#define DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_VALID (1u << 31) + +#define DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED (1u ) +#define DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED (1u << 1) +#define DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED (1u << 2) + + + + +/************************************************************************** + * * + * Protection types. * + * * + **************************************************************************/ +typedef enum { + DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION, + DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION, + DDS_SECURITY_PROTECTION_KIND_ENCRYPT, + DDS_SECURITY_PROTECTION_KIND_SIGN, + DDS_SECURITY_PROTECTION_KIND_NONE +} DDS_Security_ProtectionKind; + +typedef enum { + DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT, + DDS_SECURITY_BASICPROTECTION_KIND_SIGN, + DDS_SECURITY_BASICPROTECTION_KIND_NONE +} DDS_Security_BasicProtectionKind; + + + + +/************************************************************************** + * * + * Submessage categories. * + * * + **************************************************************************/ +typedef enum { + DDS_SECURITY_INFO_SUBMESSAGE, + DDS_SECURITY_DATAWRITER_SUBMESSAGE, + DDS_SECURITY_DATAREADER_SUBMESSAGE +} DDS_Security_SecureSubmessageCategory_t; + + + + +/************************************************************************** + * * + * QoS Policies content. * + * * + **************************************************************************/ +typedef enum { + DDS_SECURITY_AUTOMATIC_LIVELINESS_QOS, + DDS_SECURITY_MANUAL_BY_PARTICIPANT_LIVELINESS_QOS, + DDS_SECURITY_MANUAL_BY_TOPIC_LIVELINESS_QOS +} DDS_Security_LivelinessQosPolicyKind; + +typedef enum { + DDS_SECURITY_BEST_EFFORT_RELIABILITY_QOS, + DDS_SECURITY_RELIABLE_RELIABILITY_QOS +} DDS_Security_ReliabilityQosPolicyKind; + +typedef enum { + DDS_SECURITY_BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS, + DDS_SECURITY_BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS +} DDS_Security_DestinationOrderQosPolicyKind; + +typedef enum { + DDS_SECURITY_INSTANCE_PRESENTATION_QOS, + DDS_SECURITY_TOPIC_PRESENTATION_QOS, + DDS_SECURITY_GROUP_PRESENTATION_QOS +} DDS_Security_PresentationQosPolicyAccessScopeKind; + +typedef enum { + DDS_SECURITY_KEEP_LAST_HISTORY_QOS, + DDS_SECURITY_KEEP_ALL_HISTORY_QOS +} DDS_Security_HistoryQosPolicyKind; + +typedef enum { + DDS_SECURITY_VOLATILE_DURABILITY_QOS, + DDS_SECURITY_TRANSIENT_LOCAL_DURABILITY_QOS, + DDS_SECURITY_TRANSIENT_DURABILITY_QOS, + DDS_SECURITY_PERSISTENT_DURABILITY_QOS +} DDS_Security_DurabilityQosPolicyKind; + +typedef enum { + DDS_SECURITY_SHARED_OWNERSHIP_QOS, + DDS_SECURITY_EXCLUSIVE_OWNERSHIP_QOS +} DDS_Security_OwnershipQosPolicyKind; + + + + +/************************************************************************** + * * + * Listener information. * + * * + **************************************************************************/ +typedef enum { + DDS_SECURITY_IDENTITY_STATUS +} DDS_Security_AuthStatusKind; + + + + +/************************************************************************** + * * + * Some byte array sizes. * + * * + **************************************************************************/ +#define DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE 32 + +#define DDS_SECURITY_MASTER_SALT_SIZE_128 16 +#define DDS_SECURITY_MASTER_SALT_SIZE_256 32 +#define DDS_SECURITY_MASTER_SENDER_KEY_SIZE_128 16 +#define DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256 32 +#define DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_128 16 +#define DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256 32 + +/************************************************************************** + * * + * Security Property Key Names * + * * + *************************************************************************/ +#define DDS_SEC_PROP_AUTH_LIBRARY_PATH "dds.sec.auth.library.path" +#define DDS_SEC_PROP_AUTH_LIBRARY_INIT "dds.sec.auth.library.init" +#define DDS_SEC_PROP_AUTH_LIBRARY_FINALIZE "dds.sec.auth.library.finalize" +#define DDS_SEC_PROP_CRYPTO_LIBRARY_PATH "dds.sec.crypto.library.path" +#define DDS_SEC_PROP_CRYPTO_LIBRARY_INIT "dds.sec.crypto.library.init" +#define DDS_SEC_PROP_CRYPTO_LIBRARY_FINALIZE "dds.sec.crypto.library.finalize" +#define DDS_SEC_PROP_ACCESS_LIBRARY_PATH "dds.sec.access.library.path" +#define DDS_SEC_PROP_ACCESS_LIBRARY_INIT "dds.sec.access.library.init" +#define DDS_SEC_PROP_ACCESS_LIBRARY_FINALIZE "dds.sec.access.library.finalize" + +#define DDS_SEC_PROP_AUTH_IDENTITY_CA "dds.sec.auth.identity_ca" +#define DDS_SEC_PROP_AUTH_PRIV_KEY "dds.sec.auth.private_key" +#define DDS_SEC_PROP_AUTH_IDENTITY_CERT "dds.sec.auth.identity_certificate" +#define DDS_SEC_PROP_AUTH_PASSWORD "dds.sec.auth.password" +#define DDS_SEC_PROP_ACCESS_PERMISSIONS_CA "dds.sec.access.permissions_ca" +#define DDS_SEC_PROP_ACCESS_GOVERNANCE "dds.sec.access.governance" +#define DDS_SEC_PROP_ACCESS_PERMISSIONS "dds.sec.access.permissions" +#define DDS_SEC_PROP_ACCESS_TRUSTED_CA_DIR "dds.sec.auth.trusted_ca_dir" + + +#if defined (__cplusplus) +} +#endif + + +#endif /* DDS_SECURITY_API_DEF_H */ diff --git a/src/security/api/include/dds/security/dds_security_api_err.h b/src/security/api/include/dds/security/dds_security_api_err.h new file mode 100644 index 0000000..b93cc62 --- /dev/null +++ b/src/security/api/include/dds/security/dds_security_api_err.h @@ -0,0 +1,123 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef DDS_SECURITY_API_ERR_H +#define DDS_SECURITY_API_ERR_H + + +#if defined (__cplusplus) +extern "C" { +#endif + + +#define DDS_SECURITY_ERR_OK_CODE 0 +#define DDS_SECURITY_ERR_OK_MESSAGE "OK" +#define DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_CODE 100 +#define DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_MESSAGE "Can not generate random data" +#define DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE 110 +#define DDS_SECURITY_ERR_IDENTITY_EMPTY_MESSAGE "Identity empty" +#define DDS_SECURITY_ERR_PARTICIPANT_CRYPTO_HANDLE_EMPTY_CODE 111 +#define DDS_SECURITY_ERR_PARTICIPANT_CRYPTO_HANDLE_EMPTY_MESSAGE "Participant Crypto Handle empty" +#define DDS_SECURITY_ERR_PERMISSION_HANDLE_EMPTY_CODE 112 +#define DDS_SECURITY_ERR_PERMISSION_HANDLE_EMPTY_MESSAGE "Permission Handle empty" +#define DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE 113 +#define DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE "Invalid Crypto Handle" +#define DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE 114 +#define DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE "Invalid argument" +#define DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE 115 +#define DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE "Invalid Crypto token" +#define DDS_SECURITY_ERR_INVALID_PARAMETER_CODE 116 +#define DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE "Invalid parameter" +#define DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE 117 +#define DDS_SECURITY_ERR_INVALID_FILE_PATH_MESSAGE "File could not be found, opened or is empty, path: %s" +#define DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_CODE 118 +#define DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_MESSAGE "Unknown or unexpected transformation kind" +#define DDS_SECURITY_ERR_INVALID_CRYPTO_SIGN_CODE 119 +#define DDS_SECURITY_ERR_INVALID_CRYPTO_SIGN_MESSAGE "Message cannot be authenticated, incorrect signature" +#define DDS_SECURITY_ERR_INVALID_TRUSTED_CA_DIR_CODE 120 +#define DDS_SECURITY_ERR_INVALID_TRUSTED_CA_DIR_MESSAGE "Can not open trusted CA directory" +#define DDS_SECURITY_ERR_CA_NOT_TRUSTED_CODE 121 +#define DDS_SECURITY_ERR_CA_NOT_TRUSTED_MESSAGE "Identity CA is not trusted" +#define DDS_SECURITY_ERR_CERT_STARTDATE_IN_FUTURE_CODE 122 +#define DDS_SECURITY_ERR_CERT_STARTDATE_IN_FUTURE_MESSAGE "Certificate start date is in the future" +#define DDS_SECURITY_ERR_CERT_EXPIRED_CODE 123 +#define DDS_SECURITY_ERR_CERT_EXPIRED_MESSAGE "Certificate expired" +#define DDS_SECURITY_ERR_INVALID_CRYPTO_RECEIVER_SIGN_CODE 124 +#define DDS_SECURITY_ERR_CERT_AUTH_ALGO_KIND_UNKNOWN_CODE 125 +#define DDS_SECURITY_ERR_CERT_AUTH_ALGO_KIND_UNKNOWN_MESSAGE "Certificate authentication algorithm unknown" +#define DDS_SECURITY_ERR_ALLOCATION_FAILED_CODE 126 +#define DDS_SECURITY_ERR_ALLOCATION_FAILED_MESSAGE "Failed to allocate internal structure" +#define DDS_SECURITY_ERR_INVALID_SMIME_DOCUMENT_CODE 127 +#define DDS_SECURITY_ERR_INVALID_SMIME_DOCUMENT_MESSAGE "Failed to parse PKCS7 SMIME document" +#define DDS_SECURITY_ERR_MISSING_PROPERTY_CODE 128 +#define DDS_SECURITY_ERR_MISSING_PROPERTY_MESSAGE "Property is missing: (%s)" +#define DDS_SECURITY_ERR_INVALID_PERMISSION_DOCUMENT_PROPERTY_CODE 129 +#define DDS_SECURITY_ERR_INVALID_PERMISSION_DOCUMENT_PROPERTY_MESSAGE "Permissions document is invalid" +#define DDS_SECURITY_ERR_INVALID_GOVERNANCE_DOCUMENT_PROPERTY_CODE 130 +#define DDS_SECURITY_ERR_INVALID_GOVERNANCE_DOCUMENT_PROPERTY_MESSAGE "Governance document is invalid" +#define DDS_SECURITY_ERR_OPERATION_NOT_PERMITTED_CODE 131 +#define DDS_SECURITY_ERR_OPERATION_NOT_PERMITTED_MESSAGE "Operation is not permitted in this state" +#define DDS_SECURITY_ERR_MISSING_REMOTE_PERMISSIONS_DOCUMENT_CODE 132 +#define DDS_SECURITY_ERR_MISSING_REMOTE_PERMISSIONS_DOCUMENT_MESSAGE "Remote permissions document is not available" +#define DDS_SECURITY_ERR_INVALID_CERTIFICATE_CODE 133 +#define DDS_SECURITY_ERR_INVALID_CERTICICATE_MESSAGE "Certificate is invalid" +#define DDS_SECURITY_ERR_CERTIFICATE_TYPE_NOT_SUPPORTED_CODE 134 +#define DDS_SECURITY_ERR_CERTIFICATE_TYPE_NOT_SUPPORTED_MESSAGE "Certificate type is not supported" +#define DDS_SECURITY_ERR_GOVERNANCE_PROPERTY_REQUIRED_CODE 135 +#define DDS_SECURITY_ERR_GOVERNANCE_PROPERTY_REQUIRED_MESSAGE "Governance property is required" +#define DDS_SECURITY_ERR_PERMISSIONS_CA_PROPERTY_REQUIRED_CODE 136 +#define DDS_SECURITY_ERR_PERMISSIONS_CA_PROPERTY_REQUIRED_MESSAGE "Permissions CA property is required" +#define DDS_SECURITY_ERR_CAN_NOT_PARSE_GOVERNANCE_CODE 137 +#define DDS_SECURITY_ERR_CAN_NOT_PARSE_GOVERNANCE_MESSAGE "Can not parse governance file" +#define DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_CODE 138 +#define DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_MESSAGE "Can not parse permissions file" +#define DDS_SECURITY_ERR_CAN_NOT_FIND_TOPIC_PERMISSIONS_CODE 139 +#define DDS_SECURITY_ERR_CAN_NOT_FIND_TOPIC_PERMISSIONS_MESSAGE "Could not find permissions for topic" +#define DDS_SECURITY_ERR_CAN_NOT_FIND_DOMAIN_IN_PERMISSIONS_CODE 140 +#define DDS_SECURITY_ERR_CAN_NOT_FIND_DOMAIN_IN_PERMISSIONS_MESSAGE "Could not find domain %d in permissions" +#define DDS_SECURITY_ERR_CAN_NOT_FIND_DOMAIN_IN_GOVERNANCE_CODE 141 +#define DDS_SECURITY_ERR_CAN_NOT_FIND_DOMAIN_IN_GOVERNANCE_MESSAGE "Could not find domain %d in governance" +#define DDS_SECURITY_ERR_CAN_NOT_FIND_TOPIC_IN_DOMAIN_CODE 142 +#define DDS_SECURITY_ERR_CAN_NOT_FIND_TOPIC_IN_DOMAIN_MESSAGE "Could not find %s topic attributes for domain(%d) in governance" +#define DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_CLASSNAME_CODE 143 +#define DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_CLASSNAME_MESSAGE "PluginClass in remote token is incompatible" +#define DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_MAJORVERSION_CODE 144 +#define DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_MAJORVERSION_MESSAGE "MajorVersion in remote token is incompatible" +#define DDS_SECURITY_ERR_ACCESS_DENIED_CODE 145 +#define DDS_SECURITY_ERR_ACCESS_DENIED_MESSAGE "Access denied by access control" +#define DDS_SECURITY_ERR_INVALID_SUBJECT_NAME_CODE 146 +#define DDS_SECURITY_ERR_INVALID_SUBJECT_NAME_MESSAGE "Subject name is invalid" +#define DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_CODE 147 +#define DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_MESSAGE "Permissions validity period expired for %s (expired: %s)" +#define DDS_SECURITY_ERR_VALIDITY_PERIOD_NOT_STARTED_CODE 148 +#define DDS_SECURITY_ERR_VALIDITY_PERIOD_NOT_STARTED_MESSAGE "Permissions validity period has not started yet for %s (start: %s)" +#define DDS_SECURITY_ERR_CAN_NOT_FIND_PERMISSIONS_GRANT_CODE 149 +#define DDS_SECURITY_ERR_CAN_NOT_FIND_PERMISSIONS_GRANT_MESSAGE "Could not find valid grant in permissions" +#define DDS_SECURITY_ERR_URI_TYPE_NOT_SUPPORTED_CODE 150 +#define DDS_SECURITY_ERR_URI_TYPE_NOT_SUPPORTED_MESSAGE "Unsupported URI type: %s" +#define DDS_SECURITY_ERR_INVALID_CRYPTO_DATA_NOT_ALIGNED_CODE 151 +#define DDS_SECURITY_ERR_INVALID_CRYPTO_DATA_NOT_ALIGNED_MESSAGE "The payload is not aligned at 4 bytes" +#define DDS_SECURITY_ERR_TRUSTED_CA_DIR_MAX_EXCEEDED_CODE 152 +#define DDS_SECURITY_ERR_TRUSTED_CA_DIR_MAX_EXCEEDED_MESSAGE "Cannot open trusted CA directory: maximum number of CA directories (%d) exceeded" + +#define DDS_SECURITY_ERR_UNDEFINED_CODE 200 +#define DDS_SECURITY_ERR_UNDEFINED_MESSAGE "Undefined Error Message" + + +#define DDS_SECURITY_ERR_CIPHER_ERROR 301 + +#if defined (__cplusplus) +} +#endif + +#endif /* DDS_SECURITY_API_ERR_H */ + diff --git a/src/security/api/include/dds/security/dds_security_api_types.h b/src/security/api/include/dds/security/dds_security_api_types.h new file mode 100644 index 0000000..2957251 --- /dev/null +++ b/src/security/api/include/dds/security/dds_security_api_types.h @@ -0,0 +1,487 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef DDS_SECURITY_API_TYPES_H +#define DDS_SECURITY_API_TYPES_H + +#include "dds_security_api_defs.h" +#include "stdint.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +/************************************************************************** + * * + * Primitive types. * + * * + **************************************************************************/ +typedef int16_t DDS_Security_short; +typedef int32_t DDS_Security_long; +typedef int64_t DDS_Security_long_long; +typedef uint16_t DDS_Security_unsigned_short; +typedef uint32_t DDS_Security_unsigned_long; +typedef uint64_t DDS_Security_unsigned_long_long; +typedef float DDS_Security_float; +typedef double DDS_Security_double; +typedef long double DDS_Security_long_double; +typedef char DDS_Security_char; +typedef unsigned char DDS_Security_octet; +typedef unsigned char DDS_Security_boolean; +typedef DDS_Security_char * DDS_Security_string; +typedef void * DDS_Security_Object; + +/* Sequences */ +typedef struct { + DDS_Security_unsigned_long _maximum; + DDS_Security_unsigned_long _length; + DDS_Security_octet *_buffer; +} DDS_Security_OctetSeq; + +typedef struct { + DDS_Security_unsigned_long _maximum; + DDS_Security_unsigned_long _length; + DDS_Security_string *_buffer; +} DDS_Security_StringSeq; + +typedef struct { + DDS_Security_unsigned_long _maximum; + DDS_Security_unsigned_long _length; + DDS_Security_long_long *_buffer; +} DDS_Security_LongLongSeq; + + + + +/************************************************************************** + * * + * Simple types. * + * * + **************************************************************************/ +typedef DDS_Security_long_long DDS_Security_IdentityHandle; +typedef DDS_Security_long_long DDS_Security_InstanceHandle; +typedef DDS_Security_long_long DDS_Security_HandshakeHandle; +typedef DDS_Security_long_long DDS_Security_SharedSecretHandle; +typedef DDS_Security_long_long DDS_Security_PermissionsHandle; +typedef DDS_Security_long_long DDS_Security_ParticipantCryptoHandle; +typedef DDS_Security_long_long DDS_Security_DatawriterCryptoHandle; +typedef DDS_Security_long_long DDS_Security_DatareaderCryptoHandle; + +typedef DDS_Security_long DDS_Security_DynamicData; + +typedef DDS_Security_long DDS_Security_DomainId; /* Valid values 0 <= id <= 230 */ + +typedef DDS_Security_long DDS_Security_Entity; + +typedef DDS_Security_unsigned_long DDS_Security_BuiltinTopicKey_t[3]; + +typedef DDS_Security_octet DDS_Security_GuidPrefix_t[12]; + +/* Sequences */ +typedef DDS_Security_LongLongSeq DDS_Security_ParticipantCryptoHandleSeq; +typedef DDS_Security_LongLongSeq DDS_Security_DatawriterCryptoHandleSeq; +typedef DDS_Security_LongLongSeq DDS_Security_DatareaderCryptoHandleSeq; + + + + +/************************************************************************** + * * + * Simple structures. * + * * + **************************************************************************/ +typedef struct { + DDS_Security_string message; + DDS_Security_long code; + DDS_Security_long minor_code; +} DDS_Security_SecurityException; + +typedef struct { + DDS_Security_octet entityKey[3]; + DDS_Security_octet entityKind; +} DDS_Security_EntityId_t; + +typedef struct { + DDS_Security_GuidPrefix_t prefix; + DDS_Security_EntityId_t entityId; +} DDS_Security_GUID_t; + +typedef struct { + DDS_Security_long sec; + DDS_Security_unsigned_long nanosec; +} DDS_Security_Duration_t; + + + + +/************************************************************************** + * * + * Properties. * + * * + **************************************************************************/ +typedef struct { + DDS_Security_string name; + DDS_Security_string value; + DDS_Security_boolean propagate; +} DDS_Security_Property_t; + +typedef struct { + DDS_Security_unsigned_long _maximum; + DDS_Security_unsigned_long _length; + DDS_Security_Property_t *_buffer; +} DDS_Security_PropertySeq; + +typedef struct { + DDS_Security_string name; + DDS_Security_OctetSeq value; + DDS_Security_boolean propagate; +} DDS_Security_BinaryProperty_t; + +typedef struct { + DDS_Security_unsigned_long _maximum; + DDS_Security_unsigned_long _length; + DDS_Security_BinaryProperty_t *_buffer; +} DDS_Security_BinaryPropertySeq; + + + + +/************************************************************************** + * * + * DataTags. * + * * + **************************************************************************/ +typedef struct { + DDS_Security_string name; + DDS_Security_string value; +} DDS_Security_Tag; + +typedef struct { + DDS_Security_unsigned_long _maximum; + DDS_Security_unsigned_long _length; + DDS_Security_Tag *_buffer; +} DDS_Security_TagSeq; + +typedef struct { + DDS_Security_TagSeq tags; +} DDS_Security_DataTags; + + + + +/************************************************************************** + * * + * Attributes. * + * * + **************************************************************************/ +typedef DDS_Security_unsigned_long DDS_Security_EndpointSecurityAttributesMask; +typedef DDS_Security_unsigned_long DDS_Security_PluginEndpointSecurityAttributesMask; + +typedef DDS_Security_unsigned_long DDS_Security_ParticipantSecurityAttributesMask; +typedef DDS_Security_unsigned_long DDS_Security_PluginParticipantSecurityAttributesMask; + +typedef struct { + DDS_Security_boolean allow_unauthenticated_participants; + DDS_Security_boolean is_access_protected; + DDS_Security_boolean is_rtps_protected; + DDS_Security_boolean is_discovery_protected; + DDS_Security_boolean is_liveliness_protected; + DDS_Security_ParticipantSecurityAttributesMask plugin_participant_attributes; + DDS_Security_PropertySeq ac_endpoint_properties; +} DDS_Security_ParticipantSecurityAttributes; + +typedef struct { + DDS_Security_boolean is_read_protected; + DDS_Security_boolean is_write_protected; + DDS_Security_boolean is_discovery_protected; + DDS_Security_boolean is_liveliness_protected; +} DDS_Security_TopicSecurityAttributes; + +typedef struct { + DDS_Security_boolean is_read_protected; + DDS_Security_boolean is_write_protected; + DDS_Security_boolean is_discovery_protected; + DDS_Security_boolean is_liveliness_protected; + DDS_Security_boolean is_submessage_protected; + DDS_Security_boolean is_payload_protected; + DDS_Security_boolean is_key_protected; + DDS_Security_PluginEndpointSecurityAttributesMask plugin_endpoint_attributes; + DDS_Security_PropertySeq ac_endpoint_properties; +} DDS_Security_EndpointSecurityAttributes; + +typedef struct { + DDS_Security_ParticipantSecurityAttributesMask participant_security_attributes; + DDS_Security_PluginParticipantSecurityAttributesMask plugin_participant_security_attributes; +} DDS_Security_ParticipantSecurityInfo; + +typedef struct { + DDS_Security_EndpointSecurityAttributesMask endpoint_security_mask; + DDS_Security_PluginEndpointSecurityAttributesMask plugin_endpoint_security_mask; +} DDS_Security_EndpointSecurityInfo; + + + + +/************************************************************************** + * * + * Tokens. * + * * + **************************************************************************/ +typedef struct { + DDS_Security_string class_id; + DDS_Security_PropertySeq properties; + DDS_Security_BinaryPropertySeq binary_properties; +} DDS_Security_DataHolder; + +typedef struct { + DDS_Security_unsigned_long _maximum; + DDS_Security_unsigned_long _length; + DDS_Security_DataHolder *_buffer; +} DDS_Security_DataHolderSeq; + +typedef DDS_Security_DataHolder DDS_Security_Token; +typedef DDS_Security_DataHolder DDS_Security_MessageToken; +typedef DDS_Security_DataHolder DDS_Security_IdentityToken; +typedef DDS_Security_DataHolder DDS_Security_PermissionsToken; +typedef DDS_Security_DataHolder DDS_Security_IdentityStatusToken; +typedef DDS_Security_DataHolder DDS_Security_AuthRequestMessageToken; +typedef DDS_Security_DataHolder DDS_Security_HandshakeMessageToken; +typedef DDS_Security_DataHolder DDS_Security_AuthenticatedPeerCredentialToken; +typedef DDS_Security_DataHolder DDS_Security_PermissionsCredentialToken; +typedef DDS_Security_DataHolder DDS_Security_CryptoToken; +typedef DDS_Security_DataHolder DDS_Security_ParticipantCryptoToken; +typedef DDS_Security_DataHolder DDS_Security_DatawriterCryptoToken; +typedef DDS_Security_DataHolder DDS_Security_DatareaderCryptoToken; + +typedef DDS_Security_DataHolderSeq DDS_Security_CryptoTokenSeq; + +typedef DDS_Security_CryptoTokenSeq DDS_Security_ParticipantCryptoTokenSeq; +typedef DDS_Security_CryptoTokenSeq DDS_Security_DatareaderCryptoTokenSeq; +typedef DDS_Security_CryptoTokenSeq DDS_Security_DatawriterCryptoTokenSeq; + + + + +/************************************************************************** + * * + * Policies. * + * * + **************************************************************************/ +typedef DDS_Security_DataTags DDS_Security_DataTagQosPolicy; + +typedef struct { + DDS_Security_PropertySeq value; + DDS_Security_BinaryPropertySeq binary_value; +} DDS_Security_PropertyQosPolicy; + +typedef struct { + DDS_Security_DurabilityQosPolicyKind kind; +} DDS_Security_DurabilityQosPolicy; + +typedef struct { + DDS_Security_Duration_t period; +} DDS_Security_DeadlineQosPolicy; + +typedef struct { + DDS_Security_Duration_t duration; +} DDS_Security_LatencyBudgetQosPolicy; + +typedef struct { + DDS_Security_OwnershipQosPolicyKind kind; +} DDS_Security_OwnershipQosPolicy; + +typedef struct { + DDS_Security_LivelinessQosPolicyKind kind; + DDS_Security_Duration_t lease_duration; +} DDS_Security_LivelinessQosPolicy; + +typedef struct { + DDS_Security_ReliabilityQosPolicyKind kind; + DDS_Security_Duration_t max_blocking_time; + DDS_Security_boolean synchronous; +} DDS_Security_ReliabilityQosPolicy; + +typedef struct { + DDS_Security_Duration_t duration; +} DDS_Security_LifespanQosPolicy; + +typedef struct { + DDS_Security_DestinationOrderQosPolicyKind kind; +} DDS_Security_DestinationOrderQosPolicy; + +typedef struct { + DDS_Security_OctetSeq value; +} DDS_Security_UserDataQosPolicy; + +typedef struct { + DDS_Security_long value; +} DDS_Security_OwnershipStrengthQosPolicy; + +typedef struct { + DDS_Security_PresentationQosPolicyAccessScopeKind access_scope; + DDS_Security_boolean coherent_access; + DDS_Security_boolean ordered_access; +} DDS_Security_PresentationQosPolicy; + +typedef struct { + DDS_Security_StringSeq name; +} DDS_Security_PartitionQosPolicy; + +typedef struct { + DDS_Security_OctetSeq value; +} DDS_Security_TopicDataQosPolicy; + +typedef struct { + DDS_Security_OctetSeq value; +} DDS_Security_GroupDataQosPolicy; + +typedef struct { + DDS_Security_Duration_t minimum_separation; +} DDS_Security_TimeBasedFilterQosPolicy; + +typedef struct { + DDS_Security_Duration_t service_cleanup_delay; + DDS_Security_HistoryQosPolicyKind history_kind; + DDS_Security_long history_depth; + DDS_Security_long max_samples; + DDS_Security_long max_instances; + DDS_Security_long max_samples_per_instance; +} DDS_Security_DurabilityServiceQosPolicy; + +typedef struct { + DDS_Security_long value; +} DDS_Security_TransportPriorityQosPolicy; + +typedef struct { + DDS_Security_HistoryQosPolicyKind kind; + DDS_Security_long depth; +} DDS_Security_HistoryQosPolicy; + +typedef struct { + DDS_Security_long max_samples; + DDS_Security_long max_instances; + DDS_Security_long max_samples_per_instance; +} DDS_Security_ResourceLimitsQosPolicy; + + + + +/************************************************************************** + * * + * QoS. * + * * + **************************************************************************/ +typedef struct { + // Existing policies from the DDS specification are ignored. + DDS_Security_PropertyQosPolicy property; + DDS_Security_DataTagQosPolicy data_tags; +} DDS_Security_Qos; + + + + +/************************************************************************** + * * + * Messages. * + * * + **************************************************************************/ +typedef struct { + DDS_Security_BuiltinTopicKey_t key; + DDS_Security_BuiltinTopicKey_t participant_key; + DDS_Security_string topic_name; + DDS_Security_string type_name; + DDS_Security_DurabilityQosPolicy durability; + DDS_Security_DeadlineQosPolicy deadline; + DDS_Security_LatencyBudgetQosPolicy latency_budget; + DDS_Security_LivelinessQosPolicy liveliness; + DDS_Security_ReliabilityQosPolicy reliability; + DDS_Security_LifespanQosPolicy lifespan; + DDS_Security_DestinationOrderQosPolicy destination_order; + DDS_Security_UserDataQosPolicy user_data; + DDS_Security_OwnershipQosPolicy ownership; + DDS_Security_OwnershipStrengthQosPolicy ownership_strength; + DDS_Security_PresentationQosPolicy presentation; + DDS_Security_PartitionQosPolicy partition; + DDS_Security_TopicDataQosPolicy topic_data; + DDS_Security_GroupDataQosPolicy group_data; + DDS_Security_EndpointSecurityInfo security_info; + DDS_Security_DataTags data_tags; +} DDS_Security_PublicationBuiltinTopicDataSecure; + +typedef struct { + DDS_Security_BuiltinTopicKey_t key; + DDS_Security_BuiltinTopicKey_t participant_key; + DDS_Security_string topic_name; + DDS_Security_string type_name; + DDS_Security_DurabilityQosPolicy durability; + DDS_Security_DeadlineQosPolicy deadline; + DDS_Security_LatencyBudgetQosPolicy latency_budget; + DDS_Security_LivelinessQosPolicy liveliness; + DDS_Security_ReliabilityQosPolicy reliability; + DDS_Security_OwnershipQosPolicy ownership; + DDS_Security_DestinationOrderQosPolicy destination_order; + DDS_Security_UserDataQosPolicy user_data; + DDS_Security_TimeBasedFilterQosPolicy time_based_filter; + DDS_Security_PresentationQosPolicy presentation; + DDS_Security_PartitionQosPolicy partition; + DDS_Security_TopicDataQosPolicy topic_data; + DDS_Security_GroupDataQosPolicy group_data; + DDS_Security_EndpointSecurityInfo security_info; + DDS_Security_DataTags data_tags; +} DDS_Security_SubscriptionBuiltinTopicDataSecure; + +typedef struct { + DDS_Security_BuiltinTopicKey_t key; + DDS_Security_string name; + DDS_Security_string type_name; + DDS_Security_DurabilityQosPolicy durability; + DDS_Security_DurabilityServiceQosPolicy durability_service; + DDS_Security_DeadlineQosPolicy deadline; + DDS_Security_LatencyBudgetQosPolicy latency_budget; + DDS_Security_LivelinessQosPolicy liveliness; + DDS_Security_ReliabilityQosPolicy reliability; + DDS_Security_TransportPriorityQosPolicy transport_priority; + DDS_Security_LifespanQosPolicy lifespan; + DDS_Security_DestinationOrderQosPolicy destination_order; + DDS_Security_HistoryQosPolicy history; + DDS_Security_ResourceLimitsQosPolicy resource_limits; + DDS_Security_OwnershipQosPolicy ownership; + DDS_Security_TopicDataQosPolicy topic_data; +} DDS_Security_TopicBuiltinTopicData; + +typedef struct { + DDS_Security_BuiltinTopicKey_t key; + DDS_Security_UserDataQosPolicy user_data; + DDS_Security_IdentityToken identity_token; + DDS_Security_PermissionsToken permissions_token; + DDS_Security_PropertyQosPolicy property; + DDS_Security_ParticipantSecurityInfo security_info; +} DDS_Security_ParticipantBuiltinTopicData; + +typedef struct { + DDS_Security_BuiltinTopicKey_t key; + DDS_Security_UserDataQosPolicy user_data; + DDS_Security_IdentityToken identity_token; + DDS_Security_PermissionsToken permissions_token; + DDS_Security_PropertyQosPolicy property; + DDS_Security_ParticipantSecurityInfo security_info; + DDS_Security_IdentityStatusToken identity_status_token; +} DDS_Security_ParticipantBuiltinTopicDataSecure; + + + +#if defined (__cplusplus) +} +#endif + +#endif /* DDS_SECURITY_API_TYPES_H */ + diff --git a/src/security/builtin_plugins/CMakeLists.txt b/src/security/builtin_plugins/CMakeLists.txt new file mode 100644 index 0000000..93feffb --- /dev/null +++ b/src/security/builtin_plugins/CMakeLists.txt @@ -0,0 +1,21 @@ +# +# 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 +# +cmake_minimum_required(VERSION 3.7) + +add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/access_control") +add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/authentication") +add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/cryptographic") + +# TODO: improve test inclusion. +if((BUILD_TESTING) AND ((NOT DEFINED MSVC_VERSION) OR (MSVC_VERSION GREATER "1800"))) + add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/tests") +endif() \ No newline at end of file diff --git a/src/security/builtin_plugins/access_control/CMakeLists.txt b/src/security/builtin_plugins/access_control/CMakeLists.txt new file mode 100644 index 0000000..d21815c --- /dev/null +++ b/src/security/builtin_plugins/access_control/CMakeLists.txt @@ -0,0 +1,51 @@ +# +# Copyright(c) 2006 to 2019 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +include (GenerateExportHeader) + +PREPEND(srcs_accesscontrol "${CMAKE_CURRENT_LIST_DIR}/src" + access_control_objects.c + access_control_parser.c + access_control_utils.c + access_control.c +) + +add_library(dds_security_ac SHARED "") + +generate_export_header( + dds_security_ac + BASE_NAME SECURITY + EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/include/dds/security/export.h" +) + +target_link_libraries(dds_security_ac PRIVATE security_openssl) +target_link_libraries(dds_security_ac PUBLIC ddsc) +target_link_libraries(dds_security_ac PUBLIC OpenSSL::SSL) +if(CMAKE_GENERATOR MATCHES "Visual Studio") + set_target_properties(dds_security_ac PROPERTIES LINK_FLAGS "/ignore:4099") +endif() +target_sources(dds_security_ac PRIVATE ${srcs_accesscontrol}) +target_include_directories(dds_security_ac + PUBLIC + "$>" + "$>" + "$>" + "$>" + "$" +) + +install( + TARGETS dds_security_ac + EXPORT "${PROJECT_NAME}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT lib + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib +) diff --git a/src/security/builtin_plugins/access_control/src/access_control.c b/src/security/builtin_plugins/access_control/src/access_control.c new file mode 100644 index 0000000..1a45c4e --- /dev/null +++ b/src/security/builtin_plugins/access_control/src/access_control.c @@ -0,0 +1,2464 @@ +/* + * 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 + */ +#define ACCESS_CONTROL_USE_ONE_PERMISSION + +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/misc.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/dds_security_timed_cb.h" +#include "dds/security/openssl_support.h" +#include "access_control.h" +#include "access_control_utils.h" +#include "access_control_objects.h" +#include "access_control_parser.h" + +static const char *ACCESS_CONTROL_PROTOCOL_CLASS = "DDS:Access"; +static const unsigned ACCESS_CONTROL_PROTOCOL_VERSION_MAJOR = 1; +static const unsigned ACCESS_CONTROL_PROTOCOL_VERSION_MINOR = 0; + +static const char *ACCESS_CONTROL_PERMISSIONS_CLASS_ID = "Permissions"; + +static const char *QOS_PROPERTY_PERMISSIONS_DOCUMENT = "dds.sec.access.permissions"; +static const char *QOS_PROPERTY_GOVERNANCE_DOCUMENT = "dds.sec.access.governance"; +static const char *QOS_PROPERTY_PERMISSIONS_CA = "dds.sec.access.permissions_ca"; +static const char *QOS_PROPERTY_IDENTITY_CERT = "dds.sec.auth.identity_certificate"; + +static const char *ACCESS_PERMISSIONS_CREDENTIAL_TOKEN_ID = "DDS:Access:PermissionsCredential"; +static const char *ACCESS_PROPERTY_PERMISSION_DOCUMENT = "dds.perm.cert"; + +typedef enum TOPIC_TYPE +{ + TOPIC_TYPE_USER = 0, + TOPIC_TYPE_NON_SECURE_BUILTIN, + TOPIC_TYPE_SECURE_ParticipantsSecure, + TOPIC_TYPE_SECURE_PublicationsSecure, + TOPIC_TYPE_SECURE_SubscriptionsSecure, + TOPIC_TYPE_SECURE_ParticipantMessageSecure, + TOPIC_TYPE_SECURE_ParticipantStatelessMessage, + TOPIC_TYPE_SECURE_ParticipantVolatileMessageSecure +} TOPIC_TYPE; + +/** + * Implementation structure for storing encapsulated members of the instance + * while giving only the interface definition to user + */ + +typedef struct dds_security_access_control_impl +{ + dds_security_access_control base; + ddsrt_mutex_t lock; + +#ifdef ACCESS_CONTROL_USE_ONE_PERMISSION + local_participant_access_rights *local_access_rights; +#else + /* TODO: implement access rights per participant */ + struct AccessControlTable *local_permissions; +#endif + struct AccessControlTable *remote_permissions; + + struct dds_security_timed_cb_data *timed_callbacks; + struct dds_security_timed_dispatcher_t *dispatcher; +} dds_security_access_control_impl; + +static bool get_sec_attributes(dds_security_access_control_impl *ac, const DDS_Security_PermissionsHandle permissions_handle, const char *topic_name, + DDS_Security_EndpointSecurityAttributes *attributes, DDS_Security_SecurityException *ex); +static char *get_access_control_class_id(const char *classid); +static local_participant_access_rights *check_and_create_local_participant_rights(DDS_Security_IdentityHandle identity_handle, int domain_id, const DDS_Security_Qos *participant_qos, DDS_Security_SecurityException *ex); +static remote_participant_access_rights *check_and_create_remote_participant_rights(DDS_Security_IdentityHandle remote_identity_handle, local_participant_access_rights *local_rights, + const DDS_Security_PermissionsToken *remote_permissions_token, const DDS_Security_AuthenticatedPeerCredentialToken *remote_credential_token, DDS_Security_SecurityException *ex); +static local_participant_access_rights *find_local_access_rights(dds_security_access_control_impl *ac, DDS_Security_PermissionsHandle handle); +static local_participant_access_rights *find_local_rights_by_identity(dds_security_access_control_impl *ac, DDS_Security_IdentityHandle identity_handle); +static remote_participant_access_rights *find_remote_rights_by_identity(dds_security_access_control_impl *ac, DDS_Security_IdentityHandle identity_handle); +static DDS_Security_boolean domainid_within_sets(struct domain_id_set *domain, int domain_id); +static DDS_Security_boolean is_topic_in_criteria(const struct criteria *criteria, const char *topic_name); +static DDS_Security_boolean is_partition_qos_in_criteria(const struct criteria *criteria, const DDS_Security_PartitionQosPolicy *partitions); +static DDS_Security_boolean is_partition_in_criteria(const struct criteria *criteria, const char *partition_name); +static struct domain_rule *find_domain_rule_in_governance(struct domain_rule *rule, int domain_id); +static DDS_Security_boolean get_participant_sec_attributes(dds_security_access_control *instance, const DDS_Security_PermissionsHandle permissions_handle, + DDS_Security_ParticipantSecurityAttributes *attributes, DDS_Security_SecurityException *ex); +static DDS_Security_boolean get_permissions_token(dds_security_access_control *instance, DDS_Security_PermissionsToken *permissions_token, const DDS_Security_PermissionsHandle handle, DDS_Security_SecurityException *ex); +static remote_participant_access_rights *find_remote_permissions_by_permissions_handle(dds_security_access_control_impl *ac, DDS_Security_PermissionsHandle permissions_handle); +static struct topic_rule *find_topic_from_domain_rule(struct domain_rule *domain_rule, const char *topic_name); +static DDS_Security_boolean domainid_within_sets(struct domain_id_set *domain, int domain_id); +static DDS_Security_boolean compare_class_id_plugin_classname(DDS_Security_string class_id_1, DDS_Security_string class_id_2); +static DDS_Security_boolean compare_class_id_major_ver(DDS_Security_string class_id_1, DDS_Security_string class_id_2); +static void add_validity_end_trigger(dds_security_access_control_impl *ac, const DDS_Security_PermissionsHandle permissions_handle, dds_time_t end); +static DDS_Security_boolean is_allowed_by_permissions(struct permissions_parser *permissions, int domain_id, const char *topic_name, const DDS_Security_PartitionQosPolicy *partitions, + const char *identity_subject_name, permission_criteria_type criteria_type, DDS_Security_SecurityException *ex); +static void sanity_check_local_access_rights(local_participant_access_rights *rights); +static void sanity_check_remote_access_rights(remote_participant_access_rights *rights); +static TOPIC_TYPE get_topic_type(const char *topic_name); + + +static DDS_Security_PermissionsHandle +validate_local_permissions( + dds_security_access_control *instance, + const dds_security_authentication *auth_plugin, + const DDS_Security_IdentityHandle identity_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_Qos *participant_qos, + DDS_Security_SecurityException *ex) +{ + dds_security_access_control_impl *ac = (dds_security_access_control_impl *)instance; + local_participant_access_rights *rights; + DDS_Security_PermissionsHandle permissions_handle = DDS_SECURITY_HANDLE_NIL; + + if (!instance || !auth_plugin || identity_handle == DDS_SECURITY_HANDLE_NIL || !participant_qos) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return DDS_SECURITY_HANDLE_NIL; + } + +#ifdef ACCESS_CONTROL_USE_ONE_PERMISSION + ddsrt_mutex_lock(&ac->lock); + if (ac->local_access_rights == NULL) + { + rights = check_and_create_local_participant_rights(identity_handle, domain_id, participant_qos, ex); + ac->local_access_rights = rights; + } + else + { + ACCESS_CONTROL_OBJECT_KEEP(ac->local_access_rights); + rights = ac->local_access_rights; + } + ddsrt_mutex_unlock(&ac->lock); +#else + { + local_participant_access_rights *existing = find_local_rights_by_identity(ac, identity_handle); + if (existing) + { + ACCESS_CONTROL_OBJECT_RELEASE(existing); + return ACCESS_CONTROL_OBJECT_HANDLE(existing); + } + + rights = check_and_create_local_participant_rights(identity_handle, domain_id, participant_qos, ex); + if (rights) + access_control_table_insert(ac->local_permissions, (AccessControlObject *)rights); + } +#endif + + if ((permissions_handle = ACCESS_CONTROL_OBJECT_HANDLE(rights)) != DDS_SECURITY_HANDLE_NIL) + { + assert (rights->permissions_expiry != DDS_TIME_INVALID); + if (rights->permissions_expiry != 0) + add_validity_end_trigger(ac, permissions_handle, rights->permissions_expiry); + } + + return permissions_handle; +} + +static DDS_Security_PermissionsHandle +validate_remote_permissions( + dds_security_access_control *instance, + const dds_security_authentication *auth_plugin, + const DDS_Security_IdentityHandle local_identity_handle, + const DDS_Security_IdentityHandle remote_identity_handle, + const DDS_Security_PermissionsToken *remote_permissions_token, + const DDS_Security_AuthenticatedPeerCredentialToken *remote_credential_token, + DDS_Security_SecurityException *ex) +{ + dds_security_access_control_impl *ac = (dds_security_access_control_impl *)instance; + local_participant_access_rights *local_rights; + remote_participant_access_rights *remote_rights, *existing; + DDS_Security_PermissionsHandle permissions_handle = DDS_SECURITY_HANDLE_NIL; + + if (!instance || !auth_plugin || local_identity_handle == DDS_SECURITY_HANDLE_NIL || remote_identity_handle == DDS_SECURITY_HANDLE_NIL || + !remote_permissions_token || !remote_permissions_token->class_id || !remote_credential_token) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return DDS_SECURITY_HANDLE_NIL; + } + + if (!(local_rights = find_local_rights_by_identity(ac, local_identity_handle))) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return DDS_SECURITY_HANDLE_NIL; + } + + if ((existing = find_remote_rights_by_identity(ac, remote_identity_handle))) + { + if (existing->local_rights->local_identity == local_identity_handle) + { + ACCESS_CONTROL_OBJECT_RELEASE(existing); + return ACCESS_CONTROL_OBJECT_HANDLE(existing); + } + } + +#ifdef ACCESS_CONTROL_USE_ONE_PERMISSION + if (existing) + { + /* No check because it has already been checked */ + remote_rights = ac_remote_participant_access_rights_new(remote_identity_handle, local_rights, existing->permissions, existing->permissions_expiry, remote_permissions_token, existing->identity_subject_name); + sanity_check_remote_access_rights(remote_rights); + /* TODO: copy or relate security attributes of existing with new remote permissions object */ + } + else + { + remote_rights = check_and_create_remote_participant_rights(remote_identity_handle, local_rights, remote_permissions_token, remote_credential_token, ex); + } +#else + remote_rights = check_and_create_remote_participant_rights(remote_identity_handle, local_rights, remote_permissions_token, remote_credential_token, ex); +#endif + + if ((permissions_handle = ACCESS_CONTROL_OBJECT_HANDLE(remote_rights)) != DDS_SECURITY_HANDLE_NIL) + { + assert (remote_rights->permissions_expiry != DDS_TIME_INVALID); + if (remote_rights->permissions_expiry != 0) + add_validity_end_trigger(ac, permissions_handle, remote_rights->permissions_expiry); + } + + if (remote_rights) + access_control_table_insert(ac->remote_permissions, (AccessControlObject *)remote_rights); + + ACCESS_CONTROL_OBJECT_RELEASE(existing); + ACCESS_CONTROL_OBJECT_RELEASE(remote_rights); + ACCESS_CONTROL_OBJECT_RELEASE(local_rights); + + return permissions_handle; +} + +static DDS_Security_boolean +check_create_participant(dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_Qos *participant_qos, + DDS_Security_SecurityException *ex) +{ + dds_security_access_control_impl *ac = (dds_security_access_control_impl *)instance; + local_participant_access_rights *rights; + struct domain_rule *domainRule = NULL; + struct topic_rule *topicRule = NULL; + DDS_Security_ParticipantSecurityAttributes participantSecurityAttributes; + DDS_Security_boolean result = false; + + if (instance == NULL || permissions_handle == DDS_SECURITY_HANDLE_NIL || participant_qos == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + + /* Retrieve rights */ + if ((rights = find_local_access_rights(ac, permissions_handle)) == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "Could not find local rights for the participant."); + return false; + } + + /* Retrieve domain rules */ + domainRule = find_domain_rule_in_governance(rights->governance_tree->dds->domain_access_rules->domain_rule, domain_id); + if (domainRule == NULL || domainRule->topic_access_rules == NULL || domainRule->topic_access_rules->topic_rule == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_FIND_DOMAIN_IN_GOVERNANCE_CODE, 0, DDS_SECURITY_ERR_CAN_NOT_FIND_DOMAIN_IN_GOVERNANCE_MESSAGE, domain_id); + goto exit; + } + + /* Iterate over topics rules*/ + topicRule = domainRule->topic_access_rules->topic_rule; + while (topicRule != NULL) + { + if (!topicRule->enable_read_access_control->value || !topicRule->enable_write_access_control->value) + { + /* Governance specifies any topics on the DomainParticipant + domain_id with enable_read_access_control set to false or with enable_write_access_control set to false */ + result = true; + goto exit; + } + topicRule = (struct topic_rule *)topicRule->node.next; + } + + if (!get_participant_sec_attributes(instance, permissions_handle, &participantSecurityAttributes, ex)) + goto exit; + + if (!participantSecurityAttributes.is_access_protected) + { + result = true; + goto exit; + } + + /* Is this participant permitted? */ + result = is_allowed_by_permissions(rights->permissions_tree, domain_id, NULL /* topic_name */, NULL /* partitions */, rights->identity_subject_name, UNKNOWN_CRITERIA, ex); + +exit: + ACCESS_CONTROL_OBJECT_RELEASE(rights); + return result; +} + +static DDS_Security_boolean +check_create_datawriter(dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, const char *topic_name, + const DDS_Security_Qos *writer_qos, + const DDS_Security_PartitionQosPolicy *partition, + const DDS_Security_DataTags *data_tag, + DDS_Security_SecurityException *ex) +{ + DDS_Security_TopicSecurityAttributes topic_sec_attr; + local_participant_access_rights *local_rights; + DDS_Security_boolean result = false; + DDSRT_UNUSED_ARG(data_tag); + + if (instance == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "Plugin instance not provided"); + return false; + } + if (permissions_handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "Permissions handle not provided"); + return false; + } + if (topic_name == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "Topic name not provided"); + return false; + } + if (writer_qos == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "QoS not provided"); + return false; + } + if (partition == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "Partition not provided"); + return false; + } + if ((local_rights = find_local_access_rights((dds_security_access_control_impl *)instance, permissions_handle)) == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "Could not find rights material"); + return false; + } + if (local_rights->domain_id != domain_id) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, + "Given domain_id (%d) does not match the related participant domain_id (%d)\n", domain_id, local_rights->domain_id); + goto exit; + } + + /* Find a topic with the specified topic name in the Governance */ + if (!(result = instance->get_topic_sec_attributes(instance, permissions_handle, topic_name, &topic_sec_attr, ex))) + goto exit; + + if (!topic_sec_attr.is_write_protected) + { + result = true; + goto exit; + } + + /* Find a topic with the specified topic name in the Governance */ + result = is_allowed_by_permissions(local_rights->permissions_tree, domain_id, topic_name, partition, local_rights->identity_subject_name, PUBLISH_CRITERIA, ex); + +exit: + ACCESS_CONTROL_OBJECT_RELEASE(local_rights); + return result; +} + +static DDS_Security_boolean +check_create_datareader(dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const char *topic_name, + const DDS_Security_Qos *reader_qos, + const DDS_Security_PartitionQosPolicy *partition, + const DDS_Security_DataTags *data_tag, + DDS_Security_SecurityException *ex) +{ + DDS_Security_TopicSecurityAttributes topic_sec_attr; + local_participant_access_rights *local_rights; + DDS_Security_boolean result = false; + + DDSRT_UNUSED_ARG(data_tag); + + if (instance == NULL || permissions_handle == DDS_SECURITY_HANDLE_NIL || topic_name == NULL || reader_qos == NULL || partition == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + if ((local_rights = find_local_access_rights((dds_security_access_control_impl *)instance, permissions_handle)) == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + if (local_rights->domain_id != domain_id) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, + "Given domain_id (%d) does not match the related participant domain_id (%d)\n", domain_id, local_rights->domain_id); + goto exit; + } + + /* Find a topic with the specified topic name in the Governance */ + if ((result = instance->get_topic_sec_attributes(instance, permissions_handle, topic_name, &topic_sec_attr, ex)) == false) + goto exit; + + if (topic_sec_attr.is_read_protected == false) + { + result = true; + goto exit; + } + + /* Find a topic with the specified topic name in the Governance */ + result = is_allowed_by_permissions(local_rights->permissions_tree, domain_id, topic_name, partition, local_rights->identity_subject_name, SUBSCRIBE_CRITERIA, ex); + +exit: + ACCESS_CONTROL_OBJECT_RELEASE(local_rights); + return result; +} + +static DDS_Security_boolean +check_create_topic(dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, const char *topic_name, + const DDS_Security_Qos *qos, DDS_Security_SecurityException *ex) +{ + DDS_Security_TopicSecurityAttributes topic_sec_attr; + local_participant_access_rights *local_rights; + DDS_Security_boolean result = false; + + if (instance == NULL || permissions_handle == DDS_SECURITY_HANDLE_NIL || qos == NULL || topic_name == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + if ((local_rights = find_local_access_rights((dds_security_access_control_impl *)instance, permissions_handle)) == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + if (local_rights->domain_id != domain_id) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, + "Given domain_id (%d) does not match the related participant domain_id (%d)\n", domain_id, local_rights->domain_id); + goto exit; + } + + /* Find a topic with the specified topic name in the Governance */ + if ((result = instance->get_topic_sec_attributes(instance, permissions_handle, topic_name, &topic_sec_attr, ex)) == false) + goto exit; + + if (topic_sec_attr.is_read_protected == false || topic_sec_attr.is_write_protected == false) + { + result = true; + goto exit; + } + + /* Find a topic with the specified topic name in the Governance */ + result = is_allowed_by_permissions(local_rights->permissions_tree, domain_id, topic_name, NULL, local_rights->identity_subject_name, UNKNOWN_CRITERIA /* both publish and subscribe rules */, ex); + +exit: + ACCESS_CONTROL_OBJECT_RELEASE(local_rights); + return result; +} + +static DDS_Security_boolean +check_local_datawriter_register_instance( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_Entity *writer, const DDS_Security_DynamicData *key, + DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(permissions_handle); + DDSRT_UNUSED_ARG(writer); + DDSRT_UNUSED_ARG(key); + DDSRT_UNUSED_ARG(ex); + DDSRT_UNUSED_ARG(instance); + + /* Not implemented */ + return true; +} + +static DDS_Security_boolean +check_local_datawriter_dispose_instance( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_Entity *writer, const DDS_Security_DynamicData key, + DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(permissions_handle); + DDSRT_UNUSED_ARG(writer); + DDSRT_UNUSED_ARG(key); + DDSRT_UNUSED_ARG(ex); + DDSRT_UNUSED_ARG(instance); + + /* Not implemented */ + return true; +} + +static DDS_Security_boolean +check_remote_participant(dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_ParticipantBuiltinTopicDataSecure *participant_data, + DDS_Security_SecurityException *ex) +{ + dds_security_access_control_impl *ac = (dds_security_access_control_impl *)instance; + remote_participant_access_rights *remote_rights = NULL; + DDS_Security_boolean isValid = false; + DDS_Security_ParticipantSecurityAttributes participantSecurityAttributes; + DDS_Security_PermissionsHandle local_permissions_handle; + DDS_Security_string class_id_remote_str; + DDS_Security_string class_id_local_str; + DDS_Security_boolean result = false; + + if (instance == NULL || permissions_handle == DDS_SECURITY_HANDLE_NIL || participant_data == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + + /* retrieve the cached remote DomainParticipant Governance; the permissions_handle is associated with the remote participant */ + if ((remote_rights = find_remote_permissions_by_permissions_handle(ac, permissions_handle)) == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + + /* The local rights pointer is actually the local permissions handle. */ + local_permissions_handle = ACCESS_CONTROL_OBJECT_HANDLE(remote_rights->local_rights); + if ((isValid = get_participant_sec_attributes(instance, local_permissions_handle, &participantSecurityAttributes, ex)) == false) + goto exit; + if (participantSecurityAttributes.is_access_protected == false) + { + result = true; + goto exit; + } + + /* 2) If the PluginClassName or the MajorVersion of the local permissions_token differ from those in the remote_permissions_token, + the operation shall return false. */ + class_id_remote_str = remote_rights->permissions->remote_permissions_token_class_id; + class_id_local_str = get_access_control_class_id(ACCESS_CONTROL_PERMISSIONS_CLASS_ID); + if (compare_class_id_plugin_classname(class_id_remote_str, class_id_local_str) == false) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_CLASSNAME_CODE, 0, DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_CLASSNAME_MESSAGE); + goto exit_free_classid; + } + if (compare_class_id_major_ver(class_id_remote_str, class_id_local_str) == false) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_MAJORVERSION_CODE, 0, DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_MAJORVERSION_MESSAGE); + goto exit_free_classid; + } + + /* 3) If the Permissions document contains a Grant for the remote DomainParticipant and the Grant contains an allow rule on + the DomainParticipant domain_id, then the operation shall succeed and return true. */ + /* Iterate over the grants and rules of the remote participant */ + result = is_allowed_by_permissions(remote_rights->permissions->permissions_tree, domain_id, NULL, NULL, remote_rights->identity_subject_name, UNKNOWN_CRITERIA, ex); + +exit_free_classid: + ddsrt_free(class_id_local_str); +exit: + ACCESS_CONTROL_OBJECT_RELEASE(remote_rights); + return result; +} + +static DDS_Security_boolean +check_remote_datawriter(dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_PublicationBuiltinTopicDataSecure *publication_data, + DDS_Security_SecurityException *ex) +{ + dds_security_access_control_impl *ac = (dds_security_access_control_impl *)instance; + DDS_Security_TopicSecurityAttributes topic_sec_attr; + remote_participant_access_rights *remote_rights; + DDS_Security_string class_id_remote_str; + DDS_Security_string class_id_local_str; + DDS_Security_boolean result = false; + + if (instance == NULL || permissions_handle == DDS_SECURITY_HANDLE_NIL || publication_data == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + if ((remote_rights = find_remote_permissions_by_permissions_handle(ac, permissions_handle)) == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + if ((result = instance->get_topic_sec_attributes(instance, ACCESS_CONTROL_OBJECT_HANDLE(remote_rights->local_rights), publication_data->topic_name, &topic_sec_attr, ex)) == false) + goto exit; + if (topic_sec_attr.is_write_protected == false) + { + result = true; + goto exit; + } + + /* Compare PluginClassName and MajorVersion parts */ + class_id_remote_str = remote_rights->permissions->remote_permissions_token_class_id; + class_id_local_str = get_access_control_class_id(ACCESS_CONTROL_PERMISSIONS_CLASS_ID); + if (compare_class_id_plugin_classname(class_id_remote_str, class_id_local_str) == false) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_CLASSNAME_CODE, 0, + DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_CLASSNAME_MESSAGE); + goto exit_free_classid; + } + if (compare_class_id_major_ver(class_id_remote_str, class_id_local_str) == false) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_MAJORVERSION_CODE, 0, + DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_MAJORVERSION_MESSAGE); + goto exit_free_classid; + } + + /* Find a topic with the specified topic name in the Governance */ + result = is_allowed_by_permissions(remote_rights->permissions->permissions_tree, domain_id, publication_data->topic_name, + &(publication_data->partition), remote_rights->identity_subject_name, PUBLISH_CRITERIA, ex); + +exit_free_classid: + ddsrt_free(class_id_local_str); +exit: + ACCESS_CONTROL_OBJECT_RELEASE(remote_rights); + return result; +} + +static DDS_Security_boolean +check_remote_datareader(dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_SubscriptionBuiltinTopicDataSecure *subscription_data, + DDS_Security_boolean *relay_only, + DDS_Security_SecurityException *ex) +{ + dds_security_access_control_impl *ac = (dds_security_access_control_impl *)instance; + DDS_Security_TopicSecurityAttributes topic_sec_attr; + remote_participant_access_rights *remote_rights; + DDS_Security_string class_id_remote_str; + DDS_Security_string class_id_local_str; + + DDS_Security_boolean result = false; + + if (instance == NULL || permissions_handle == DDS_SECURITY_HANDLE_NIL || subscription_data == NULL || relay_only == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + + *relay_only = false; + if ((remote_rights = find_remote_permissions_by_permissions_handle(ac, permissions_handle)) == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + if (!(instance->get_topic_sec_attributes(instance, ACCESS_CONTROL_OBJECT_HANDLE(remote_rights->local_rights), subscription_data->topic_name, &topic_sec_attr, ex))) + goto exit; + if (!topic_sec_attr.is_read_protected) + { + result = true; + goto exit; + } + + /* Compare PluginClassName and MajorVersion parts */ + class_id_remote_str = remote_rights->permissions->remote_permissions_token_class_id; + class_id_local_str = get_access_control_class_id(ACCESS_CONTROL_PERMISSIONS_CLASS_ID); + if (compare_class_id_plugin_classname(class_id_remote_str, class_id_local_str) == false) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_CLASSNAME_CODE, 0, + DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_CLASSNAME_MESSAGE); + goto exit_free_classid; + } + if (compare_class_id_major_ver(class_id_remote_str, class_id_local_str) == false) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_MAJORVERSION_CODE, 0, + DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_MAJORVERSION_MESSAGE); + ACCESS_CONTROL_OBJECT_RELEASE(remote_rights); + goto exit_free_classid; + } + + /* Find a topic with the specified topic name in the Governance */ + result = is_allowed_by_permissions(remote_rights->permissions->permissions_tree, domain_id, subscription_data->topic_name, + &(subscription_data->partition), remote_rights->identity_subject_name, SUBSCRIBE_CRITERIA, ex); + +exit_free_classid: + ddsrt_free(class_id_local_str); +exit: + ACCESS_CONTROL_OBJECT_RELEASE(remote_rights); + return result; +} + +static DDS_Security_boolean +check_remote_topic(dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_TopicBuiltinTopicData *topic_data, + DDS_Security_SecurityException *ex) +{ + dds_security_access_control_impl *ac = (dds_security_access_control_impl *)instance; + DDS_Security_TopicSecurityAttributes topic_sec_attr; + remote_participant_access_rights *remote_rights; + DDS_Security_string class_id_remote_str; + DDS_Security_string class_id_local_str; + DDS_Security_boolean result = false; + + if (instance == NULL || permissions_handle == DDS_SECURITY_HANDLE_NIL || topic_data == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + if ((remote_rights = find_remote_permissions_by_permissions_handle(ac, permissions_handle)) == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + if ((result = instance->get_topic_sec_attributes(instance, ACCESS_CONTROL_OBJECT_HANDLE(remote_rights->local_rights), topic_data->name, &topic_sec_attr, ex)) == false) + goto exit; + if (!topic_sec_attr.is_read_protected || !topic_sec_attr.is_write_protected) + { + result = true; + goto exit; + } + + /* Compare PluginClassName and MajorVersion parts */ + class_id_remote_str = remote_rights->permissions->remote_permissions_token_class_id; + class_id_local_str = get_access_control_class_id(ACCESS_CONTROL_PERMISSIONS_CLASS_ID); + if (!compare_class_id_plugin_classname(class_id_remote_str, class_id_local_str)) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_CLASSNAME_CODE, 0, + DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_CLASSNAME_MESSAGE); + goto exit_free_classid; + } + if (!compare_class_id_major_ver(class_id_remote_str, class_id_local_str)) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_MAJORVERSION_CODE, 0, + DDS_SECURITY_ERR_INCOMPATIBLE_REMOTE_PLUGIN_MAJORVERSION_MESSAGE); + goto exit_free_classid; + } + + result = is_allowed_by_permissions(remote_rights->permissions->permissions_tree, domain_id, topic_data->name, NULL, remote_rights->identity_subject_name, UNKNOWN_CRITERIA, ex); + +exit_free_classid: + ddsrt_free(class_id_local_str); +exit: + ACCESS_CONTROL_OBJECT_RELEASE(remote_rights); + return result; +} + +static DDS_Security_boolean +check_local_datawriter_match( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle writer_permissions_handle, + const DDS_Security_PermissionsHandle reader_permissions_handle, + const DDS_Security_PublicationBuiltinTopicDataSecure *publication_data, + const DDS_Security_SubscriptionBuiltinTopicDataSecure *subscription_data, + DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(writer_permissions_handle); + DDSRT_UNUSED_ARG(reader_permissions_handle); + DDSRT_UNUSED_ARG(publication_data); + DDSRT_UNUSED_ARG(subscription_data); + DDSRT_UNUSED_ARG(ex); + DDSRT_UNUSED_ARG(instance); + + /* This function is not implemented because it relies on DataTagging, + an optional DDS Security feature that is not implemented */ + return true; +} + +static DDS_Security_boolean +check_local_datareader_match( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle reader_permissions_handle, + const DDS_Security_PermissionsHandle writer_permissions_handle, + const DDS_Security_SubscriptionBuiltinTopicDataSecure *subscription_data, + const DDS_Security_PublicationBuiltinTopicDataSecure *publication_data, + DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(reader_permissions_handle); + DDSRT_UNUSED_ARG(writer_permissions_handle); + DDSRT_UNUSED_ARG(subscription_data); + DDSRT_UNUSED_ARG(publication_data); + DDSRT_UNUSED_ARG(ex); + DDSRT_UNUSED_ARG(instance); + + /* Not implemented */ + return true; +} + +static DDS_Security_boolean +check_remote_datawriter_register_instance( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_Entity *reader, + const DDS_Security_InstanceHandle publication_handle, + const DDS_Security_DynamicData key, + const DDS_Security_InstanceHandle instance_handle, + DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(permissions_handle); + DDSRT_UNUSED_ARG(reader); + DDSRT_UNUSED_ARG(publication_handle); + DDSRT_UNUSED_ARG(key); + DDSRT_UNUSED_ARG(instance_handle); + DDSRT_UNUSED_ARG(ex); + DDSRT_UNUSED_ARG(instance); + + /* Not implemented */ + return true; +} + +static DDS_Security_boolean +check_remote_datawriter_dispose_instance( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_Entity *reader, + const DDS_Security_InstanceHandle publication_handle, + const DDS_Security_DynamicData key, + DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(permissions_handle); + DDSRT_UNUSED_ARG(reader); + DDSRT_UNUSED_ARG(publication_handle); + DDSRT_UNUSED_ARG(key); + DDSRT_UNUSED_ARG(ex); + DDSRT_UNUSED_ARG(instance); + + /* Not implemented */ + return true; +} + +static DDS_Security_boolean +get_permissions_token(dds_security_access_control *instance, + DDS_Security_PermissionsToken *permissions_token, + const DDS_Security_PermissionsHandle handle, + DDS_Security_SecurityException *ex) +{ + local_participant_access_rights *rights; + if (!ex) + return false; + if (!instance) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, DDS_SECURITY_VALIDATION_FAILED, "get_permissions_token: No instance provided"); + return false; + } + if (!permissions_token) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, DDS_SECURITY_VALIDATION_FAILED, "get_permissions_token: No permissions token provided"); + return false; + } + if (handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, DDS_SECURITY_VALIDATION_FAILED, "get_permissions_token: No permissions handle provided"); + return false; + } + if ((rights = find_local_access_rights((dds_security_access_control_impl *)instance, handle)) == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "get_permissions_token: Unused permissions handle provided"); + return false; + } + + ACCESS_CONTROL_OBJECT_RELEASE(rights); + memset(permissions_token, 0, sizeof(*permissions_token)); + permissions_token->class_id = get_access_control_class_id(ACCESS_CONTROL_PERMISSIONS_CLASS_ID); + return true; +} + +static DDS_Security_boolean +get_permissions_credential_token( + dds_security_access_control *instance, + DDS_Security_PermissionsCredentialToken *permissions_credential_token, + const DDS_Security_PermissionsHandle handle, + DDS_Security_SecurityException *ex) +{ + dds_security_access_control_impl *ac = (dds_security_access_control_impl *)instance; + local_participant_access_rights *rights; + if (!ex) + return false; + if (!instance) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, DDS_SECURITY_VALIDATION_FAILED, "get_permissions_credential_token: No instance provided"); + return false; + } + if (!permissions_credential_token) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, DDS_SECURITY_VALIDATION_FAILED, "get_permissions_credential_token: No permissions credential token provided"); + return false; + } + if (handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, DDS_SECURITY_VALIDATION_FAILED, "get_permissions_credential_token: No permissions handle provided"); + return false; + } + if ((rights = find_local_access_rights(ac, handle)) == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "get_permissions_credential_token: Unused permissions handle provided"); + return false; + } + + memset(permissions_credential_token, 0, sizeof(*permissions_credential_token)); + permissions_credential_token->class_id = ddsrt_strdup(ACCESS_PERMISSIONS_CREDENTIAL_TOKEN_ID); + permissions_credential_token->properties._length = permissions_credential_token->properties._maximum = 1; + permissions_credential_token->properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + permissions_credential_token->properties._buffer[0].name = ddsrt_strdup(ACCESS_PROPERTY_PERMISSION_DOCUMENT); + permissions_credential_token->properties._buffer[0].value = ddsrt_strdup(rights->permissions_document); + ACCESS_CONTROL_OBJECT_RELEASE(rights); + return true; +} + + +static DDS_Security_boolean +set_listener(dds_security_access_control *instance, + const dds_security_access_control_listener *listener, + DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(ex); + + dds_security_access_control_impl *ac = (dds_security_access_control_impl *)instance; + if (listener) + dds_security_timed_dispatcher_enable(ac->timed_callbacks, ac->dispatcher, (void *)listener); + else + dds_security_timed_dispatcher_disable(ac->timed_callbacks, ac->dispatcher); + + return true; +} + +static DDS_Security_boolean +return_permissions_token( + dds_security_access_control *instance, + const DDS_Security_PermissionsToken *token, + DDS_Security_SecurityException *ex) +{ + if (!instance || !token) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)token); + return true; +} + +static DDS_Security_boolean +return_permissions_credential_token( + dds_security_access_control *instance, + const DDS_Security_PermissionsCredentialToken *permissions_credential_token, + DDS_Security_SecurityException *ex) +{ + if (!instance || !permissions_credential_token) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)permissions_credential_token); + return true; +} + +static void +protectionkind_to_participant_attribute( + DDS_Security_ProtectionKind kind, + DDS_Security_boolean *is_protected, + DDS_Security_ParticipantSecurityAttributesMask *mask, + DDS_Security_ParticipantSecurityAttributesMask encryption_bit, + DDS_Security_ParticipantSecurityAttributesMask authentication_bit) +{ + switch (kind) + { + case DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION: + (*mask) |= authentication_bit; + (*mask) |= encryption_bit; + (*is_protected) = true; + break; + case DDS_SECURITY_PROTECTION_KIND_ENCRYPT: + (*mask) |= encryption_bit; + (*is_protected) = true; + break; + case DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION: + (*mask) |= authentication_bit; + (*is_protected) = true; + break; + case DDS_SECURITY_PROTECTION_KIND_SIGN: + (*is_protected) = true; + break; + case DDS_SECURITY_PROTECTION_KIND_NONE: + default: + (*is_protected) = false; + break; + } +} + +static DDS_Security_PluginEndpointSecurityAttributesMask +get_plugin_endpoint_security_attributes_mask( + DDS_Security_boolean is_payload_encrypted, + DDS_Security_boolean is_submessage_encrypted, + DDS_Security_boolean is_submessage_origin_authenticated) +{ + DDS_Security_PluginEndpointSecurityAttributesMask mask = DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_VALID; + if (is_submessage_encrypted) + mask |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + if (is_payload_encrypted) + mask |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + if (is_submessage_origin_authenticated) + mask |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + return mask; +} + +static void +domain_rule_to_participant_attributes( + const struct domain_rule *rule, + DDS_Security_ParticipantSecurityAttributes *attributes) +{ + /* Expect proper rule. */ + assert(rule); + assert(rule->allow_unauthenticated_participants); + assert(rule->enable_join_access_control); + assert(rule->liveliness_protection_kind); + assert(rule->discovery_protection_kind); + assert(rule->rtps_protection_kind); + assert(attributes); + + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + + attributes->allow_unauthenticated_participants = rule->allow_unauthenticated_participants->value; + attributes->is_access_protected = rule->enable_join_access_control->value; + + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + + protectionkind_to_participant_attribute( + rule->discovery_protection_kind->value, + &(attributes->is_discovery_protected), + &(attributes->plugin_participant_attributes), + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_ENCRYPTED, + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_AUTHENTICATED); + + protectionkind_to_participant_attribute( + rule->liveliness_protection_kind->value, + &(attributes->is_liveliness_protected), + &(attributes->plugin_participant_attributes), + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_ENCRYPTED, + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_AUTHENTICATED); + + protectionkind_to_participant_attribute( + rule->rtps_protection_kind->value, + &(attributes->is_rtps_protected), + &(attributes->plugin_participant_attributes), + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED, + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED); +} + +static DDS_Security_boolean +domainid_within_sets( + struct domain_id_set *domain, + int domain_id) +{ + DDS_Security_boolean found = false; + int32_t min; + int32_t max; + + while (domain != NULL && !found) + { + assert(domain->min); + min = domain->min->value; + max = domain->max ? domain->max->value : min; + if ((domain_id >= min) && (domain_id <= max)) + found = true; + domain = (struct domain_id_set *)domain->node.next; + } + return found; +} + +static struct domain_rule * +find_domain_rule_in_governance(struct domain_rule *rule, int domain_id) +{ + struct domain_rule *found = NULL; + while ((rule != NULL) && (found == NULL)) + { + assert(rule->domains); + if (domainid_within_sets(rule->domains->domain_id_set, domain_id)) + found = rule; + rule = (struct domain_rule *)rule->node.next; + } + return found; +} + +static DDS_Security_boolean +get_participant_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + DDS_Security_ParticipantSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + dds_security_access_control_impl *ac = (dds_security_access_control_impl *)instance; + local_participant_access_rights *local_rights; + struct domain_rule *found = NULL; + DDS_Security_boolean result = false; + + if (instance == 0 || permissions_handle == DDS_SECURITY_HANDLE_NIL || attributes == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + + /* The local rights are actually the local permissions handle. Check that. */ + if ((local_rights = find_local_access_rights(ac, permissions_handle)) == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "Invalid permissions handle"); + return false; + } + if ((found = find_domain_rule_in_governance(local_rights->governance_tree->dds->domain_access_rules->domain_rule, local_rights->domain_id))) + { + domain_rule_to_participant_attributes(found, attributes); + result = true; + } + else + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Could not domain id within governance file."); + } + ACCESS_CONTROL_OBJECT_RELEASE(local_rights); + return result; +} + +static DDS_Security_boolean +compare_class_id_plugin_classname(DDS_Security_string classid1, DDS_Security_string classid2) +{ + char *classname1 = strrchr(classid1, ':'); + char *classname2 = strrchr(classid2, ':'); + const ptrdiff_t len1 = classname1 - classid1; + const ptrdiff_t len2 = classname2 - classid2; + return len1 == len2 && classname1 && classname2 && + ddsrt_strncasecmp(classid1, classid2, (size_t) len1) == 0; +} + +static DDS_Security_boolean +compare_class_id_major_ver(DDS_Security_string classid1, DDS_Security_string classid2) +{ + char *version_1 = strrchr(classid1, ':'); + char *version_2 = strrchr(classid2, ':'); + if (version_1 && version_2) + { + const char *majorVersion_1 = strrchr(version_1, '.'); + const char *majorVersion_2 = strrchr(version_2, '.'); + const ptrdiff_t len1 = majorVersion_1 - version_1; + const ptrdiff_t len2 = majorVersion_2 - version_2; + return len1 == len2 && majorVersion_1 && majorVersion_2 && + ddsrt_strncasecmp(version_1, version_2, (size_t) len1) == 0; + } + return false; +} + +static DDS_Security_boolean +is_partition_qos_in_criteria( + const struct criteria *criteria, + const DDS_Security_PartitionQosPolicy *partitions) +{ + unsigned int partition_index = 0; + const char *partitionDefault[] = {""}; + const DDS_Security_PartitionQosPolicy *partitionsToCheck; + DDS_Security_PartitionQosPolicy defaultPartitions; + defaultPartitions.name._length = 1; + defaultPartitions.name._maximum = 1; + defaultPartitions.name._buffer = (char **)partitionDefault; + + if (criteria == NULL) + return false; + + if (!partitions || partitions->name._length == 0) + partitionsToCheck = &defaultPartitions; + else + partitionsToCheck = partitions; + + for (partition_index = 0; partition_index < partitionsToCheck->name._length; partition_index++) + { + if (is_partition_in_criteria(criteria, partitionsToCheck->name._buffer[partition_index]) == false) + return false; + } + + return true; +} + +static DDS_Security_boolean +is_partition_in_criteria( + const struct criteria *criteria, + const char *partition_name) +{ + struct partitions *current_partitions; + struct string_value *current_partition; + + if (criteria == NULL || partition_name == NULL) + return false; + + current_partitions = (struct partitions *)criteria->partitions; + while (current_partitions != NULL) + { + current_partition = current_partitions->partition; + while (current_partition != NULL) + { + if (ac_fnmatch(current_partition->value, partition_name)) + return true; + current_partition = (struct string_value *)current_partition->node.next; + } + current_partitions = (struct partitions *)current_partitions->node.next; + } + return false; +} + +static DDS_Security_boolean +is_topic_in_criteria( + const struct criteria *criteria, + const char *topic_name) +{ + struct topics *current_topics; + struct string_value *current_topic; + + if (criteria == NULL || topic_name == NULL) + return false; + + /* Start by checking for a matching topic */ + current_topics = criteria->topics; + while (current_topics != NULL) + { + current_topic = current_topics->topic; + while (current_topic != NULL) + { + if (ac_fnmatch(current_topic->value, topic_name)) + return true; + current_topic = (struct string_value *)current_topic->node.next; + } + current_topics = (struct topics *)current_topics->node.next; + } + return false; +} + +static struct topic_rule * +find_topic_from_domain_rule( + struct domain_rule *domain_rule, + const char *topic_name) +{ + struct topic_rule *topic_rule; + struct topic_rule *topic_found = NULL; + + if (domain_rule->topic_access_rules != NULL && + domain_rule->topic_access_rules->topic_rule != NULL) + { + topic_rule = domain_rule->topic_access_rules->topic_rule; + while (topic_rule != NULL && topic_found == NULL) + { + assert(topic_rule->topic_expression); + if (ac_fnmatch(topic_rule->topic_expression->value, topic_name)) + topic_found = topic_rule; + topic_rule = (struct topic_rule *)topic_rule->node.next; + } + } + return topic_found; +} + +static DDS_Security_boolean +get_topic_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const char *topic_name, + DDS_Security_TopicSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + dds_security_access_control_impl *ac = (dds_security_access_control_impl *)instance; + local_participant_access_rights *rights; + struct domain_rule *found; + DDS_Security_boolean result = false; + + if (instance == 0) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "No plugin instance provided"); + return false; + } + if (permissions_handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "No permissions handle provided"); + return false; + } + if (topic_name == NULL || strlen(topic_name) == 0) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "No topic name provided"); + return false; + } + if (attributes == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "No attributes provided"); + return false; + } + rights = find_local_access_rights(ac, permissions_handle); + if (rights == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "Unused permissions handle provided"); + return false; + } + + memset(attributes, 0, sizeof(*attributes)); + + if (get_topic_type(topic_name) != TOPIC_TYPE_USER) + { + /* No attributes are set for builtin topics. */ + ACCESS_CONTROL_OBJECT_RELEASE(rights); + return true; + } + + if ((found = find_domain_rule_in_governance(rights->governance_tree->dds->domain_access_rules->domain_rule, rights->domain_id))) + { + struct topic_rule *topic_rule = find_topic_from_domain_rule(found, topic_name); + if (topic_rule) + { + attributes->is_discovery_protected = topic_rule->enable_discovery_protection->value; + attributes->is_liveliness_protected = topic_rule->enable_liveliness_protection->value; + attributes->is_read_protected = topic_rule->enable_read_access_control->value; + attributes->is_write_protected = topic_rule->enable_write_access_control->value; + result = true; + } + else + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_FIND_TOPIC_IN_DOMAIN_CODE, 0, DDS_SECURITY_ERR_CAN_NOT_FIND_TOPIC_IN_DOMAIN_MESSAGE, topic_name, rights->domain_id); + } + } + else + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_FIND_DOMAIN_IN_GOVERNANCE_CODE, 0, DDS_SECURITY_ERR_CAN_NOT_FIND_DOMAIN_IN_GOVERNANCE_MESSAGE, rights->domain_id); + } + + ACCESS_CONTROL_OBJECT_RELEASE(rights); + return result; +} + +static DDS_Security_boolean +get_datawriter_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const char *topic_name, + const DDS_Security_PartitionQosPolicy *partition, + const DDS_Security_DataTagQosPolicy *data_tag, + DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(partition); + DDSRT_UNUSED_ARG(data_tag); + dds_security_access_control_impl *ac = (dds_security_access_control_impl *)instance; + + if (instance == 0 || permissions_handle == DDS_SECURITY_HANDLE_NIL || topic_name == 0 || strlen(topic_name) == 0 || attributes == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + return get_sec_attributes(ac, permissions_handle, topic_name, attributes, ex); +} + +static DDS_Security_boolean +get_datareader_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const char *topic_name, + const DDS_Security_PartitionQosPolicy *partition, + const DDS_Security_DataTagQosPolicy *data_tag, + DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(partition); + DDSRT_UNUSED_ARG(data_tag); + dds_security_access_control_impl *ac = (dds_security_access_control_impl *)instance; + + if (instance == 0 || permissions_handle == DDS_SECURITY_HANDLE_NIL || topic_name == 0 || strlen(topic_name) == 0 || attributes == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + return get_sec_attributes(ac, permissions_handle, topic_name, attributes, ex); +} + +static DDS_Security_boolean +return_participant_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_ParticipantSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(attributes); + DDSRT_UNUSED_ARG(ex); + DDSRT_UNUSED_ARG(instance); + /* Nothing to do. */ + return true; +} + +static DDS_Security_boolean +return_topic_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_TopicSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(attributes); + DDSRT_UNUSED_ARG(ex); + DDSRT_UNUSED_ARG(instance); + /* Nothing to do. */ + return true; +} + +static DDS_Security_boolean +return_datawriter_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(attributes); + DDSRT_UNUSED_ARG(ex); + DDSRT_UNUSED_ARG(instance); + /* Nothing to do. */ + return true; +} + +static DDS_Security_boolean +return_datareader_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(attributes); + DDSRT_UNUSED_ARG(ex); + DDSRT_UNUSED_ARG(instance); + /* Nothing to do. */ + return true; +} + +static DDS_Security_boolean +return_permissions_handle( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + DDS_Security_SecurityException *ex) +{ + dds_security_access_control_impl *ac = (dds_security_access_control_impl *)instance; + AccessControlObject *object; + + if (!instance || !permissions_handle) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + +#ifdef ACCESS_CONTROL_USE_ONE_PERMISSION + ddsrt_mutex_lock(&ac->lock); + if (permissions_handle == ACCESS_CONTROL_OBJECT_HANDLE(ac->local_access_rights)) + { + ddsrt_mutex_unlock(&ac->lock); + return true; + } + ddsrt_mutex_unlock(&ac->lock); +#else + object = access_control_table_find(ac->local_permissions, permissions_handle); + if (object) + { + access_control_table_remove_object(ac->local_permissions, object); + access_control_object_release(object); + return true; + } +#endif + + object = access_control_table_find(ac->remote_permissions, permissions_handle); + if (!object) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + + access_control_table_remove_object(ac->remote_permissions, object); + access_control_object_release(object); + return true; +} + +int init_access_control(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + DDSRT_UNUSED_ARG(argument); + + dds_security_access_control_impl *access_control = ddsrt_malloc(sizeof(*access_control)); + memset(access_control, 0, sizeof(*access_control)); + access_control->base.gv = gv; + access_control->timed_callbacks = dds_security_timed_cb_new(); + access_control->dispatcher = dds_security_timed_dispatcher_new(access_control->timed_callbacks); + access_control->base.validate_local_permissions = &validate_local_permissions; + access_control->base.validate_remote_permissions = &validate_remote_permissions; + access_control->base.check_create_participant = &check_create_participant; + access_control->base.check_create_datawriter = &check_create_datawriter; + access_control->base.check_create_datareader = &check_create_datareader; + access_control->base.check_create_topic = &check_create_topic; + access_control->base.check_local_datawriter_register_instance = &check_local_datawriter_register_instance; + access_control->base.check_local_datawriter_dispose_instance = &check_local_datawriter_dispose_instance; + access_control->base.check_remote_participant = &check_remote_participant; + access_control->base.check_remote_datawriter = &check_remote_datawriter; + access_control->base.check_remote_datareader = &check_remote_datareader; + access_control->base.check_remote_topic = &check_remote_topic; + access_control->base.check_local_datawriter_match = &check_local_datawriter_match; + access_control->base.check_local_datareader_match = &check_local_datareader_match; + access_control->base.check_remote_datawriter_register_instance = &check_remote_datawriter_register_instance; + access_control->base.check_remote_datawriter_dispose_instance = &check_remote_datawriter_dispose_instance; + access_control->base.get_permissions_token = &get_permissions_token; + access_control->base.get_permissions_credential_token = &get_permissions_credential_token; + access_control->base.set_listener = &set_listener; + access_control->base.return_permissions_token = &return_permissions_token; + access_control->base.return_permissions_credential_token = &return_permissions_credential_token; + access_control->base.get_participant_sec_attributes = &get_participant_sec_attributes; + access_control->base.get_topic_sec_attributes = &get_topic_sec_attributes; + access_control->base.get_datawriter_sec_attributes = &get_datawriter_sec_attributes; + access_control->base.get_datareader_sec_attributes = &get_datareader_sec_attributes; + access_control->base.return_participant_sec_attributes = &return_participant_sec_attributes; + access_control->base.return_topic_sec_attributes = &return_topic_sec_attributes; + access_control->base.return_datawriter_sec_attributes = &return_datawriter_sec_attributes; + access_control->base.return_datareader_sec_attributes = &return_datareader_sec_attributes; + access_control->base.return_permissions_handle = &return_permissions_handle; + ddsrt_mutex_init(&access_control->lock); + +#ifdef ACCESS_CONTROL_USE_ONE_PERMISSION + access_control->local_access_rights = NULL; +#else + access_control->local_permissions = access_control_table_new(); +#endif + access_control->remote_permissions = access_control_table_new(); + + dds_openssl_init (); + *context = access_control; + return 0; +} + +static bool +get_sec_attributes( + dds_security_access_control_impl *ac, + const DDS_Security_PermissionsHandle permissions_handle, + const char *topic_name, + DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + local_participant_access_rights *rights; + DDS_Security_boolean result = false; + TOPIC_TYPE topic_type; + assert(topic_name); + assert(attributes); + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + if ((rights = find_local_access_rights(ac, permissions_handle)) == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, "Invalid permissions handle"); + return false; + } + + if ((topic_type = get_topic_type(topic_name)) != TOPIC_TYPE_USER) + { + /* Builtin topics are treated in a special manner. */ + result = true; + + if (topic_type == TOPIC_TYPE_SECURE_ParticipantsSecure || topic_type == TOPIC_TYPE_SECURE_PublicationsSecure || + topic_type == TOPIC_TYPE_SECURE_SubscriptionsSecure || topic_type == TOPIC_TYPE_SECURE_ParticipantMessageSecure) + { + struct domain_rule *found = find_domain_rule_in_governance(rights->governance_tree->dds->domain_access_rules->domain_rule, rights->domain_id); + if (found) + { /* Domain matched */ + /* is_submessage_protected should match is_liveliness_protected of + * ParticipantSecurityAttributes for DCPSParticipantMessageSecure. + * is_submessage_protected should match is_discovery_protected of + * ParticipantSecurityAttributes for OTHER 3.*/ + if (topic_type == TOPIC_TYPE_SECURE_ParticipantMessageSecure) + { + attributes->is_submessage_protected = !(found->liveliness_protection_kind->value == DDS_SECURITY_PROTECTION_KIND_NONE); + attributes->plugin_endpoint_attributes = get_plugin_endpoint_security_attributes_mask( + /* payload encrypted */ + false, + /* submsg encrypted */ + found->liveliness_protection_kind->value == DDS_SECURITY_PROTECTION_KIND_ENCRYPT || + found->liveliness_protection_kind->value == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION, + /* submsg authenticated */ + found->liveliness_protection_kind->value == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION || + found->liveliness_protection_kind->value == DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION); + } + else + { + attributes->is_submessage_protected = !(found->discovery_protection_kind->value == DDS_SECURITY_PROTECTION_KIND_NONE); + attributes->plugin_endpoint_attributes = get_plugin_endpoint_security_attributes_mask( + /* payload encrypted */ + false, + /* submsg encrypted */ + found->discovery_protection_kind->value == DDS_SECURITY_PROTECTION_KIND_ENCRYPT || + found->discovery_protection_kind->value == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION, + /* submsg authenticated */ + found->discovery_protection_kind->value == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION || + found->discovery_protection_kind->value == DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION); + } + } + else + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_FIND_DOMAIN_IN_GOVERNANCE_CODE, 0, DDS_SECURITY_ERR_CAN_NOT_FIND_DOMAIN_IN_GOVERNANCE_MESSAGE, rights->domain_id); + result = false; + } + attributes->is_read_protected = false; + attributes->is_write_protected = false; + attributes->is_payload_protected = false; + attributes->is_key_protected = false; + } + else if (topic_type == TOPIC_TYPE_SECURE_ParticipantStatelessMessage) + { + attributes->plugin_endpoint_attributes = DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_VALID; + attributes->is_read_protected = false; + attributes->is_write_protected = false; + attributes->is_payload_protected = false; + attributes->is_key_protected = false; + attributes->is_submessage_protected = false; + } + else if (topic_type == TOPIC_TYPE_SECURE_ParticipantVolatileMessageSecure) + { + attributes->plugin_endpoint_attributes = DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_VALID | + DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + attributes->is_read_protected = false; + attributes->is_write_protected = false; + attributes->is_payload_protected = false; + attributes->is_key_protected = false; + attributes->is_submessage_protected = true; + } + else + { + /* Non secure builtin topics. */ + attributes->plugin_endpoint_attributes = DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_VALID; + attributes->is_read_protected = false; + attributes->is_write_protected = false; + attributes->is_payload_protected = false; + attributes->is_key_protected = false; + attributes->is_submessage_protected = false; + } + } + else + { + /* Normal user topic attributes are acquired from governance and permission documents. */ + struct domain_rule *found = find_domain_rule_in_governance(rights->governance_tree->dds->domain_access_rules->domain_rule, rights->domain_id); + if (found) + { /* Domain matched */ + struct topic_rule *topic_rule = find_topic_from_domain_rule(found, topic_name); + if (topic_rule) + { /* Topic matched */ + attributes->is_discovery_protected = topic_rule->enable_discovery_protection->value; + attributes->is_liveliness_protected = topic_rule->enable_liveliness_protection->value; + attributes->is_read_protected = topic_rule->enable_read_access_control->value; + attributes->is_write_protected = topic_rule->enable_write_access_control->value; + attributes->is_payload_protected = topic_rule->data_protection_kind->value != DDS_SECURITY_BASICPROTECTION_KIND_NONE; + attributes->is_submessage_protected = topic_rule->metadata_protection_kind->value != DDS_SECURITY_PROTECTION_KIND_NONE; + attributes->is_key_protected = topic_rule->data_protection_kind->value == DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT; + + /*calculate and assign the mask */ + attributes->plugin_endpoint_attributes = get_plugin_endpoint_security_attributes_mask( + topic_rule->data_protection_kind->value == DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT, + topic_rule->metadata_protection_kind->value == DDS_SECURITY_PROTECTION_KIND_ENCRYPT || + topic_rule->metadata_protection_kind->value == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION, + topic_rule->metadata_protection_kind->value == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION || + topic_rule->metadata_protection_kind->value == DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION); + + memset(&attributes->ac_endpoint_properties, 0, sizeof(DDS_Security_PropertySeq)); + result = true; + } + else + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_FIND_TOPIC_IN_DOMAIN_CODE, 0, DDS_SECURITY_ERR_CAN_NOT_FIND_TOPIC_IN_DOMAIN_MESSAGE, topic_name, rights->domain_id); + } + } + else + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_FIND_DOMAIN_IN_GOVERNANCE_CODE, 0, DDS_SECURITY_ERR_CAN_NOT_FIND_DOMAIN_IN_GOVERNANCE_MESSAGE, rights->domain_id); + } + } + ACCESS_CONTROL_OBJECT_RELEASE(rights); + return result; +} + +static char * +get_access_control_class_id( + const char *classid) +{ + size_t sz = strlen(ACCESS_CONTROL_PROTOCOL_CLASS) + strlen(classid) + 6; + char *classId = ddsrt_malloc(sz); + snprintf(classId, sz, "%s:%s:%1u.%1u", ACCESS_CONTROL_PROTOCOL_CLASS, classid, ACCESS_CONTROL_PROTOCOL_VERSION_MAJOR, ACCESS_CONTROL_PROTOCOL_VERSION_MINOR); + return classId; +} + +static void +sanity_check_local_access_rights( + local_participant_access_rights *rights) +{ +#ifndef NDEBUG + if (rights) + { + assert(rights->permissions_document); + assert(rights->governance_tree); + assert(rights->governance_tree->dds); + assert(rights->governance_tree->dds->domain_access_rules); + assert(rights->governance_tree->dds->domain_access_rules->domain_rule); + assert(rights->permissions_tree); + assert(rights->permissions_tree->dds); + assert(rights->permissions_tree->dds->permissions); + assert(rights->permissions_tree->dds->permissions->grant); + } +#else + DDSRT_UNUSED_ARG(rights); +#endif +} + +static void +sanity_check_remote_access_rights( + remote_participant_access_rights *rights) +{ +#ifndef NDEBUG + /* Just some sanity checks. */ + if (rights) + { + assert(rights->permissions); + assert(rights->permissions->permissions_tree); + assert(rights->permissions->permissions_tree->dds); + assert(rights->permissions->permissions_tree->dds->permissions); + assert(rights->permissions->remote_permissions_token_class_id); + assert(rights->local_rights); + sanity_check_local_access_rights(rights->local_rights); + } +#else + DDSRT_UNUSED_ARG(rights); +#endif +} + +static local_participant_access_rights * +find_local_access_rights( + dds_security_access_control_impl *ac, + DDS_Security_PermissionsHandle handle) +{ + local_participant_access_rights *rights = NULL; + +#ifdef ACCESS_CONTROL_USE_ONE_PERMISSION + DDSRT_UNUSED_ARG(handle); + + ddsrt_mutex_lock(&ac->lock); + if (handle == ACCESS_CONTROL_OBJECT_HANDLE(ac->local_access_rights)) + rights = (local_participant_access_rights *)ACCESS_CONTROL_OBJECT_KEEP(ac->local_access_rights); + ddsrt_mutex_unlock(&ac->lock); +#else + rights = (local_participant_access_rights *)access_control_table_find(ac->local_permissions, handle); +#endif + + sanity_check_local_access_rights(rights); + return rights; +} + +struct find_by_identity_arg +{ + AccessControlObject *object; + DDS_Security_IdentityHandle handle; +}; + +#ifndef ACCESS_CONTROL_USE_ONE_PERMISSION +static int +local_identity_handle_match( + AccessControlObject *obj, + void *arg) +{ + local_participant_access_rights *rights = (local_participant_access_rights *)obj; + struct find_by_identity_arg *info = arg; + + if (rights->local_identity == info->handle) + { + info->object = obj; + return 0; + } + + return 1; +} +#endif + +static int +remote_identity_handle_match( + AccessControlObject *obj, + void *arg) +{ + remote_participant_access_rights *rights = (remote_participant_access_rights *)obj; + struct find_by_identity_arg *info = arg; + + if (rights->remote_identity == info->handle) + { + info->object = ACCESS_CONTROL_OBJECT_KEEP(obj); + return 0; + } + + return 1; +} + +static local_participant_access_rights * +find_local_rights_by_identity( + dds_security_access_control_impl *ac, + DDS_Security_IdentityHandle identity_handle) +{ + local_participant_access_rights *rights = NULL; + +#ifdef ACCESS_CONTROL_USE_ONE_PERMISSION + DDSRT_UNUSED_ARG(identity_handle); + + ddsrt_mutex_lock(&ac->lock); + rights = (local_participant_access_rights *)ACCESS_CONTROL_OBJECT_KEEP(ac->local_access_rights); + ddsrt_mutex_unlock(&ac->lock); +#else + { + struct find_by_identity_arg args; + args.object = NULL; + args.handle = identity_handle; + access_control_table_walk(ac->local_permissions, local_identity_handle_match, &args); + rights = (local_participant_access_rights *)args.object; + } +#endif + sanity_check_local_access_rights(rights); + return rights; +} + +static remote_participant_access_rights * +find_remote_rights_by_identity( + dds_security_access_control_impl *ac, + DDS_Security_IdentityHandle identity_handle) +{ + struct find_by_identity_arg args; + args.object = NULL; + args.handle = identity_handle; + access_control_table_walk(ac->remote_permissions, remote_identity_handle_match, &args); + sanity_check_remote_access_rights((remote_participant_access_rights *)args.object); + return (remote_participant_access_rights *)args.object; +} + +struct find_by_permissions_handle_arg +{ + AccessControlObject *object; + DDS_Security_PermissionsHandle handle; +}; + +static int +remote_permissions_handle_match( + AccessControlObject *obj, + void *arg) +{ + struct find_by_permissions_handle_arg *info = arg; + if (obj->handle == info->handle) + { + info->object = ACCESS_CONTROL_OBJECT_KEEP(obj); + return 0; + } + return 1; +} + +static remote_participant_access_rights * +find_remote_permissions_by_permissions_handle( + dds_security_access_control_impl *ac, + DDS_Security_PermissionsHandle permissions_handle) +{ + struct find_by_permissions_handle_arg args; + args.object = NULL; + args.handle = permissions_handle; + access_control_table_walk(ac->remote_permissions, remote_permissions_handle_match, &args); + sanity_check_remote_access_rights((remote_participant_access_rights *)args.object); + return (remote_participant_access_rights *)args.object; +} + + +typedef struct +{ + dds_security_access_control_impl *ac; + DDS_Security_PermissionsHandle hdl; +} validity_cb_info; + +static void +validity_callback(struct dds_security_timed_dispatcher_t *d, + dds_security_timed_cb_kind kind, + void *listener, + void *arg) +{ + validity_cb_info *info = arg; + DDSRT_UNUSED_ARG(d); + assert(d); + assert(arg); + if (kind == DDS_SECURITY_TIMED_CB_KIND_TIMEOUT) + { + assert(listener); + if (1 /* TODO: Check if hdl is still valid or if it has been already returned. */) + { + dds_security_access_control_listener *ac_listener = (dds_security_access_control_listener *)listener; + if (ac_listener->on_revoke_permissions) + ac_listener->on_revoke_permissions((dds_security_access_control *)info->ac, info->hdl); + } + } + ddsrt_free(arg); +} + +static void +add_validity_end_trigger(dds_security_access_control_impl *ac, + const DDS_Security_PermissionsHandle permissions_handle, + dds_time_t end) +{ + validity_cb_info *arg = ddsrt_malloc(sizeof(validity_cb_info)); + arg->ac = ac; + arg->hdl = permissions_handle; + dds_security_timed_dispatcher_add(ac->timed_callbacks, ac->dispatcher, validity_callback, end, (void *)arg); +} + +static DDS_Security_boolean +is_allowed_by_permissions(struct permissions_parser *permissions, + int domain_id, + const char *topic_name, + const DDS_Security_PartitionQosPolicy *partitions, + const char *identity_subject_name, + permission_criteria_type criteria_type, + DDS_Security_SecurityException *ex) +{ + struct grant *permissions_grant; + struct allow_deny_rule *current_rule; + struct criteria *current_criteria; + + assert(permissions); + assert(permissions->dds); + assert(permissions->dds->permissions); + + permissions_grant = permissions->dds->permissions->grant; + + /* Check for a matching grant */ + while (permissions_grant != NULL) + { + /* Verify that it is within the validity date and the subject name matches */ + if (permissions_grant->subject_name != NULL && + permissions_grant->subject_name->value != NULL && + strcmp(permissions_grant->subject_name->value, identity_subject_name) == 0) + { + dds_time_t tnow = dds_time(); + if (tnow <= DDS_Security_parse_xml_date(permissions_grant->validity->not_before->value)) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_VALIDITY_PERIOD_NOT_STARTED_CODE, 0, + DDS_SECURITY_ERR_VALIDITY_PERIOD_NOT_STARTED_MESSAGE, permissions_grant->subject_name->value, permissions_grant->validity->not_before->value); + return false; + } + if (tnow >= DDS_Security_parse_xml_date(permissions_grant->validity->not_after->value)) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_CODE, 0, + DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_MESSAGE, permissions_grant->subject_name->value, permissions_grant->validity->not_after->value); + return false; + } + + current_rule = permissions_grant->allow_deny_rule; + while (current_rule != NULL) + { + /* Check if the domain matches the given ID otherwise move on */ + if (domainid_within_sets(current_rule->domains->domain_id_set, domain_id)) + { + if (topic_name == NULL) + { + if (current_rule->rule_type == ALLOW_RULE) + return true; + } + + /* Check all subscribe criteria to find the topics, partition and tags */ + current_criteria = current_rule->criteria; + while (current_criteria != NULL) + { + if (current_criteria->criteria_type == criteria_type || (int)criteria_type == UNKNOWN_CRITERIA) + { + if (is_topic_in_criteria(current_criteria, topic_name) && is_partition_qos_in_criteria(current_criteria, partitions)) + { + if (current_rule->rule_type == ALLOW_RULE) + return true; + if (current_rule->rule_type == DENY_RULE) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_ACCESS_DENIED_CODE, 0, "%s found in deny_rule.", topic_name); + return false; + } + } + } + current_criteria = (struct criteria *)current_criteria->node.next; + } + } + current_rule = (struct allow_deny_rule *)current_rule->node.next; + } + + /* If nothing found but the grant matches, return the default value */ + if (permissions_grant->default_action == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_ACCESS_DENIED_CODE, 0, "No rule found for %s", topic_name ? topic_name : "participant"); + return false; + } + + if (strcmp(permissions_grant->default_action->value, "ALLOW") != 0) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_ACCESS_DENIED_CODE, 0, "%s denied by default rule", topic_name ? topic_name : "participant"); + return false; + } + + return true; + } + permissions_grant = (struct grant *)permissions_grant->node.next; + } + + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_FIND_PERMISSIONS_GRANT_CODE, 0, DDS_SECURITY_ERR_CAN_NOT_FIND_PERMISSIONS_GRANT_MESSAGE); + return false; +} + +static bool +read_document_from_file( + const char *filename, + char **doc, + DDS_Security_SecurityException *ex) +{ + DDSRT_WARNING_MSVC_OFF(4996); + FILE *fp; + char *document = NULL; + char *fname = NULL; + size_t sz, r; + + assert(doc); + *doc = NULL; + /* Get portable file name. */ + fname = DDS_Security_normalize_file(filename); + if (fname) + { + /* Get size if it is a accessible regular file (no dir or link). */ + sz = ac_regular_file_size(fname); + if (sz > 0) + { + /* Open the actual file. */ + fp = fopen(fname, "r"); + if (fp) + { + /* Read the content. */ + document = ddsrt_malloc(sz + 1); + r = fread(document, 1, sz, fp); + if (r == 0) + { + ddsrt_free(document); + } + else + { + document[r] = '\0'; + *doc = document; + } + (void)fclose(fp); + } + } + ddsrt_free(fname); + } + + if ((*doc) == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE, 0, DDS_SECURITY_ERR_INVALID_FILE_PATH_MESSAGE, (filename ? filename : "NULL")); + return false; + } + return true; + DDSRT_WARNING_MSVC_ON(4996); +} + +static bool +read_document( + const char *doc_uri, + char **doc, + DDS_Security_SecurityException *ex) +{ + char *data = NULL; + switch (DDS_Security_get_conf_item_type(doc_uri, &data)) + { + case DDS_SECURITY_CONFIG_ITEM_PREFIX_DATA: + *doc = data; + return true; + + case DDS_SECURITY_CONFIG_ITEM_PREFIX_FILE: { + const bool result = read_document_from_file(data, doc, ex); + ddsrt_free(data); + return result; + } + + case DDS_SECURITY_CONFIG_ITEM_PREFIX_PKCS11: + case DDS_SECURITY_CONFIG_ITEM_PREFIX_UNKNOWN: + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_URI_TYPE_NOT_SUPPORTED_CODE, 0, DDS_SECURITY_ERR_URI_TYPE_NOT_SUPPORTED_MESSAGE, doc_uri); + ddsrt_free(data); + return false; + } + assert (0); + return false; +} + +static bool +validate_subject_name_in_permissions(struct permissions_parser *permissions_tree, + const char *identity_subject_name, + char **permission_subject_name, + dds_time_t *permission_validity_not_after, + DDS_Security_SecurityException *ex) +{ + + struct grant *permissions_grant; + assert(permission_subject_name); + + *permission_subject_name = NULL; + if (permissions_tree == NULL || permissions_tree->dds == NULL || permissions_tree->dds->permissions == NULL || permissions_tree->dds->permissions->grant == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + + permissions_grant = permissions_tree->dds->permissions->grant; + while (permissions_grant != NULL) + { + /* Verify that it is within the validity date and the subject name matches */ + if (identity_subject_name != NULL && ac_check_subjects_are_equal(permissions_grant->subject_name->value, identity_subject_name)) + { + dds_time_t tnow = dds_time (); + if (tnow <= DDS_Security_parse_xml_date(permissions_grant->validity->not_before->value)) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_VALIDITY_PERIOD_NOT_STARTED_CODE, 0, + DDS_SECURITY_ERR_VALIDITY_PERIOD_NOT_STARTED_MESSAGE, permissions_grant->subject_name->value, permissions_grant->validity->not_before->value); + return false; + } + if (tnow >= DDS_Security_parse_xml_date(permissions_grant->validity->not_after->value)) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_CODE, 0, + DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_MESSAGE, permissions_grant->subject_name->value, permissions_grant->validity->not_after->value); + return false; + } + + /* identity subject name and permission subject name may not be exactly same because of different string representations + * That's why we are returning the string in permissions file to be stored for further comparisons */ + *permission_subject_name = ddsrt_strdup(permissions_grant->subject_name->value); + *permission_validity_not_after = DDS_Security_parse_xml_date(permissions_grant->validity->not_after->value); + return true; + } + permissions_grant = (struct grant *)permissions_grant->node.next; + } + + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_SUBJECT_NAME_CODE, 0, + DDS_SECURITY_ERR_INVALID_SUBJECT_NAME_MESSAGE); + return false; +} + +static local_participant_access_rights * +check_and_create_local_participant_rights( + DDS_Security_IdentityHandle identity_handle, + int domain_id, + const DDS_Security_Qos *participant_qos, + DDS_Security_SecurityException *ex) +{ + local_participant_access_rights *rights = NULL; + X509 *identity_cert; + X509 *permission_ca = NULL; + size_t pdlen; + size_t gvlen; + char *identity_cert_data = NULL; + char *permission_ca_data = NULL; + char *permission_document = NULL; + char *governance_document = NULL; + char *permission_xml = NULL; + char *governance_xml = NULL; + char *identity_subject = NULL; + struct governance_parser *governance_tree = NULL; + struct permissions_parser *permissions_tree = NULL; + char *permission_subject = NULL; + char *permissions_uri = NULL; + char *governance_uri = NULL; + dds_time_t permission_expiry = DDS_TIME_INVALID; + + /* Retrieve the identity certificate from the participant QoS */ + identity_cert_data = DDS_Security_Property_get_value(&participant_qos->property.value, QOS_PROPERTY_IDENTITY_CERT); + if (!identity_cert_data) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_MISSING_PROPERTY_CODE, 0, + DDS_SECURITY_ERR_MISSING_PROPERTY_MESSAGE, QOS_PROPERTY_IDENTITY_CERT); + goto err_no_identity_cert; + } + + if (!ac_X509_certificate_read(identity_cert_data, &identity_cert, ex)) + goto err_inv_identity_cert; + + if (!(identity_subject = ac_get_certificate_subject_name(identity_cert, ex))) + goto err_inv_identity_cert; + + if (!(governance_uri = DDS_Security_Property_get_value(&participant_qos->property.value, QOS_PROPERTY_GOVERNANCE_DOCUMENT))) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_MISSING_PROPERTY_CODE, 0, + DDS_SECURITY_ERR_MISSING_PROPERTY_MESSAGE, QOS_PROPERTY_GOVERNANCE_DOCUMENT); + goto err_no_governance; + } + + if (!(permissions_uri = DDS_Security_Property_get_value(&participant_qos->property.value, QOS_PROPERTY_PERMISSIONS_DOCUMENT))) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_MISSING_PROPERTY_CODE, 0, + DDS_SECURITY_ERR_MISSING_PROPERTY_MESSAGE, QOS_PROPERTY_PERMISSIONS_DOCUMENT); + goto err_no_permissions; + } + + if (!(permission_ca_data = DDS_Security_Property_get_value(&participant_qos->property.value, QOS_PROPERTY_PERMISSIONS_CA))) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_MISSING_PROPERTY_CODE, 0, + DDS_SECURITY_ERR_MISSING_PROPERTY_MESSAGE, QOS_PROPERTY_PERMISSIONS_CA); + goto err_no_permission_ca; + } + + if (strlen(governance_uri) == 0 && strlen(permissions_uri) == 0 && strlen(permission_ca_data) == 0) + { + bool result; + + result = ac_parse_governance_xml(DDS_SECURITY_DEFAULT_GOVERNANCE, &governance_tree, ex); + assert(result); + DDSRT_UNUSED_ARG(result); + + result = ac_parse_permissions_xml(DDS_SECURITY_DEFAULT_PERMISSIONS, &permissions_tree, ex); + assert(result); + DDSRT_UNUSED_ARG(result); + + /*set subject name on default permissions */ + ddsrt_free(permissions_tree->dds->permissions->grant->subject_name->value); + permissions_tree->dds->permissions->grant->subject_name->value = ddsrt_strdup(identity_subject); + permission_document = ddsrt_strdup(""); + + rights = ac_local_participant_access_rights_new(identity_handle, domain_id, permission_document, NULL, identity_subject, governance_tree, permissions_tree); + sanity_check_local_access_rights(rights); + } + else if (strlen(governance_uri) > 0 && strlen(permissions_uri) > 0 && strlen(permission_ca_data) > 0) + { + /* Retrieve the permission ca certificate from the participant QoS */ + if (!ac_X509_certificate_read(permission_ca_data, &permission_ca, ex)) + goto err_inv_permission_ca; + + /* Retrieve the permissions document from the participant QoS */ + if (!read_document(permissions_uri, &permission_document, ex)) + goto err_read_perm_doc; + + if ((pdlen = strlen(permission_document)) == 0) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PERMISSION_DOCUMENT_PROPERTY_CODE, + DDS_SECURITY_VALIDATION_FAILED, DDS_SECURITY_ERR_INVALID_PERMISSION_DOCUMENT_PROPERTY_MESSAGE); + goto err_read_perm_doc; + } + + /* Retrieve the governance from the participant QoS */ + if (!read_document(governance_uri, &governance_document, ex)) + goto err_read_gov_doc; + + if ((gvlen = strlen(governance_document)) == 0) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_GOVERNANCE_DOCUMENT_PROPERTY_CODE, + DDS_SECURITY_VALIDATION_FAILED, DDS_SECURITY_ERR_INVALID_GOVERNANCE_DOCUMENT_PROPERTY_MESSAGE); + goto err_read_gov_doc; + } + + if (!ac_PKCS7_document_check(permission_document, pdlen, permission_ca, &permission_xml, ex)) + goto err_inv_perm_doc; + + if (!ac_PKCS7_document_check(governance_document, gvlen, permission_ca, &governance_xml, ex)) + goto err_inv_gov_doc; + + if (!ac_parse_governance_xml(governance_xml, &governance_tree, ex)) + goto err_inv_gov_xml; + + if (!ac_parse_permissions_xml(permission_xml, &permissions_tree, ex)) + { + ac_return_governance_tree(governance_tree); + goto err_inv_perm_xml; + } + + /* check if subject name of identity certificate matches the subject name in the permissions document */ + if (!validate_subject_name_in_permissions(permissions_tree, identity_subject, &permission_subject, &permission_expiry, ex)) + { + ac_return_governance_tree(governance_tree); + ac_return_permissions_tree(permissions_tree); + goto err_inv_subject; + } + + rights = ac_local_participant_access_rights_new(identity_handle, domain_id, permission_document, permission_ca, permission_subject, governance_tree, permissions_tree); + rights->permissions_expiry = permission_expiry; + sanity_check_local_access_rights(rights); + } + else + { /*one of them is not empty but the others */ + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, DDS_SECURITY_VALIDATION_FAILED, + "Governance, Permissions and Permissions CA properties do not exist properly. Either all must be empty or all must be valid"); + goto err_inv_properties; + } + +err_inv_subject: +err_inv_perm_xml: +err_inv_gov_xml: + ddsrt_free(governance_xml); +err_inv_gov_doc: + ddsrt_free(permission_xml); +err_inv_perm_doc: +err_read_gov_doc: + ddsrt_free(governance_document); +err_read_perm_doc: + if (!rights) + { + ddsrt_free(permission_document); + X509_free(permission_ca); + } +err_inv_properties: +err_inv_permission_ca: + ddsrt_free(permission_ca_data); +err_no_permission_ca: + ddsrt_free(permissions_uri); +err_no_permissions: + ddsrt_free(governance_uri); +err_no_governance: + X509_free(identity_cert); +err_inv_identity_cert: + ddsrt_free(identity_subject); + ddsrt_free(permission_subject); + ddsrt_free(identity_cert_data); +err_no_identity_cert: + return rights; +} + +static remote_participant_access_rights * +check_and_create_remote_participant_rights( + DDS_Security_IdentityHandle remote_identity_handle, + local_participant_access_rights *local_rights, + const DDS_Security_PermissionsToken *remote_permissions_token, + const DDS_Security_AuthenticatedPeerCredentialToken *remote_credential_token, + DDS_Security_SecurityException *ex) +{ + remote_participant_access_rights *rights = NULL; + X509 *identity_cert = NULL; + const DDS_Security_Property_t *identity_cert_property; + const DDS_Security_Property_t *permission_doc_property; + char *identity_subject = NULL; + char *permissions_xml = NULL; + remote_permissions *permissions = NULL; + char *permission_subject = NULL; + dds_time_t permission_expiry = DDS_TIME_INVALID; + size_t len; + + /* Retrieve the remote identity certificate from the remote_credential_token */ + identity_cert_property = DDS_Security_DataHolder_find_property(remote_credential_token, "c.id"); + if (!identity_cert_property || !identity_cert_property->value) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_MISSING_PROPERTY_CODE, 0, + DDS_SECURITY_ERR_MISSING_PROPERTY_MESSAGE, "c.id"); + goto err_no_identity_cert; + } + + len = strlen(identity_cert_property->value); + assert (len <= INT32_MAX); + if (!ac_X509_certificate_from_data(identity_cert_property->value, (int) len, &identity_cert, ex)) + goto err_inv_identity_cert; + + if (!(identity_subject = ac_get_certificate_subject_name(identity_cert, ex))) + goto err_inv_identity_cert; + + /* Retrieve the remote permissions document from the remote_credential_token */ + permission_doc_property = DDS_Security_DataHolder_find_property(remote_credential_token, "c.perm"); + if (!permission_doc_property || !permission_doc_property->value) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_MISSING_PROPERTY_CODE, 0, DDS_SECURITY_ERR_MISSING_PROPERTY_MESSAGE, "c.perm"); + goto err_inv_perm_doc; + } + + if (strlen(permission_doc_property->value) == 0) + { + /* use default permissions document (all deny) if there is no permissions file + *to communicate with access_control=false and comply with previous release */ + struct domain_rule *domainRule = find_domain_rule_in_governance(local_rights->governance_tree->dds->domain_access_rules->domain_rule, local_rights->domain_id); + if (!domainRule->enable_join_access_control->value) + { + permissions_xml = ddsrt_str_replace(DDS_SECURITY_DEFAULT_PERMISSIONS, "DEFAULT_SUBJECT", identity_subject, 1); + } + else + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PERMISSION_DOCUMENT_PROPERTY_CODE, 0, DDS_SECURITY_ERR_INVALID_PERMISSION_DOCUMENT_PROPERTY_MESSAGE); + goto err_inv_perm_doc; + } + } + else + { + if (!ac_PKCS7_document_check(permission_doc_property->value, strlen(permission_doc_property->value), local_rights->permissions_ca, &permissions_xml, ex)) + goto err_inv_perm_doc; + } + + permissions = ddsrt_malloc(sizeof(remote_permissions)); + permissions->ref_cnt = 0; + permissions->permissions_tree = NULL; + permissions->remote_permissions_token_class_id = NULL; + if (!ac_parse_permissions_xml(permissions_xml, &(permissions->permissions_tree), ex)) + { + ddsrt_free(permissions); + goto err_inv_perm_xml; + } + + /* check if subject name of identity certificate matches the subject name in the permissions document */ + if (!validate_subject_name_in_permissions(permissions->permissions_tree, identity_subject, &permission_subject, &permission_expiry, ex)) + { + ac_return_permissions_tree(permissions->permissions_tree); + ddsrt_free(permissions); + goto err_inv_subject; + } + rights = ac_remote_participant_access_rights_new(remote_identity_handle, local_rights, permissions, permission_expiry, remote_permissions_token, permission_subject); + sanity_check_remote_access_rights(rights); + ddsrt_free(permission_subject); + +err_inv_subject: +err_inv_perm_xml: + ddsrt_free(permissions_xml); +err_inv_perm_doc: + X509_free(identity_cert); +err_inv_identity_cert: + ddsrt_free(identity_subject); +err_no_identity_cert: + return rights; +} + +static TOPIC_TYPE +get_topic_type( + const char *topic_name) +{ + TOPIC_TYPE type = TOPIC_TYPE_USER; + assert(topic_name); + + /* All builtin topics start with "DCPS" */ + if (strncmp(topic_name, "DCPS", 4) == 0) + { + /* There are a number of builtin topics starting with "DCPSParticipant" */ + if (strncmp(&(topic_name[4]), "Participant", 11) == 0) + { + if (strcmp(&(topic_name[15]), "") == 0) + type = TOPIC_TYPE_NON_SECURE_BUILTIN; /* DCPSParticipant */ + else if (strcmp(&(topic_name[15]), "Message") == 0) + type = TOPIC_TYPE_NON_SECURE_BUILTIN; /* DCPSParticipantMessage */ + else if (strcmp(&(topic_name[15]), "MessageSecure") == 0) + type = TOPIC_TYPE_SECURE_ParticipantMessageSecure; /* DCPSParticipantMessageSecure */ + else if (strcmp(&(topic_name[15]), "VolatileMessageSecure") == 0) + type = TOPIC_TYPE_SECURE_ParticipantVolatileMessageSecure; /* DCPSParticipantVolatileMessageSecure */ + else if (strcmp(&(topic_name[15]), "StatelessMessage") == 0) + type = TOPIC_TYPE_SECURE_ParticipantStatelessMessage; /* DCPSParticipantStatelessMessage */ + else if (strcmp(&(topic_name[15]), "sSecure") == 0) + type = TOPIC_TYPE_SECURE_ParticipantsSecure; /* DCPSParticipantsSecure */ + } + else if (strcmp(&(topic_name[4]), "SubscriptionsSecure") == 0) + type = TOPIC_TYPE_SECURE_SubscriptionsSecure; /* DCPSSubscriptionsSecure */ + else if (strcmp(&(topic_name[4]), "PublicationsSecure") == 0) + type = TOPIC_TYPE_SECURE_PublicationsSecure; /* DCPSPublicationsSecure */ + else if ((strcmp(&(topic_name[4]), "Topic") == 0) || + (strcmp(&(topic_name[4]), "Publication") == 0) || + (strcmp(&(topic_name[4]), "Subscription") == 0)) + { + /* DCPSTopic */ + /* DCPSPublication */ + /* DCPSSubscription */ + type = TOPIC_TYPE_NON_SECURE_BUILTIN; + } + } + return type; +} + +int finalize_access_control(void *context) +{ + dds_security_access_control_impl *access_control = context; + if (access_control) + { + + dds_security_timed_dispatcher_free(access_control->timed_callbacks, access_control->dispatcher); + dds_security_timed_cb_free(access_control->timed_callbacks); + + access_control_table_free(access_control->remote_permissions); +#ifdef ACCESS_CONTROL_USE_ONE_PERMISSION + if (access_control->local_access_rights) + access_control_object_free((AccessControlObject *)access_control->local_access_rights); +#else + access_control_table_free(access_control->local_permissions); +#endif + ddsrt_mutex_destroy(&access_control->lock); + ddsrt_free(access_control); + } + return 0; +} diff --git a/src/security/builtin_plugins/access_control/src/access_control.h b/src/security/builtin_plugins/access_control/src/access_control.h new file mode 100644 index 0000000..e89ca00 --- /dev/null +++ b/src/security/builtin_plugins/access_control/src/access_control.h @@ -0,0 +1,22 @@ +/* + * 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 ACCESS_CONTROL_H +#define ACCESS_CONTROL_H + +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/export.h" + +SECURITY_EXPORT int init_access_control(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_access_control(void *context); + +#endif /* ACCESS_CONTROL_H */ diff --git a/src/security/builtin_plugins/access_control/src/access_control_objects.c b/src/security/builtin_plugins/access_control/src/access_control_objects.c new file mode 100644 index 0000000..d418c21 --- /dev/null +++ b/src/security/builtin_plugins/access_control/src/access_control_objects.c @@ -0,0 +1,286 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/hopscotch.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/types.h" +#include "access_control_objects.h" +#include "access_control_utils.h" +#include "access_control_parser.h" + +struct AccessControlTable +{ + struct ddsrt_hh *htab; + ddsrt_mutex_t lock; +}; + +bool access_control_object_valid(const AccessControlObject *obj, const AccessControlObjectKind_t kind) +{ + if (!obj) + return false; + if (obj->kind != kind) + return false; + if (obj->handle != (int64_t)(uintptr_t)obj) + return false; + + return true; +} + +static uint32_t access_control_object_hash(const void *obj) +{ + const AccessControlObject *object = obj; + const uint64_t c = 0xE21B371BEB9E6C05; + const uint32_t x = (uint32_t)object->handle; + return (unsigned)((x * c) >> 32); +} + +static int access_control_object_equal(const void *ha, const void *hb) +{ + const AccessControlObject *la = ha; + const AccessControlObject *lb = hb; + return la->handle == lb->handle; +} + +void access_control_object_init(AccessControlObject *obj, AccessControlObjectKind_t kind, AccessControlObjectDestructor destructor) +{ + assert(obj); + obj->kind = kind; + obj->handle = (int64_t)(uintptr_t)obj; + obj->destructor = destructor; + ddsrt_atomic_st32(&obj->refcount, 1); +} + +static void access_control_object_deinit(AccessControlObject *obj) +{ + assert(obj); + obj->handle = DDS_SECURITY_HANDLE_NIL; + obj->kind = ACCESS_CONTROL_OBJECT_KIND_UNKNOWN; + obj->destructor = NULL; +} + +void access_control_object_free(AccessControlObject *obj) +{ + if (obj && obj->destructor) + obj->destructor(obj); +} + +AccessControlObject *access_control_object_keep(AccessControlObject *obj) +{ + if (obj) + ddsrt_atomic_inc32(&obj->refcount); + return obj; +} + +void access_control_object_release(AccessControlObject *obj) +{ + if (obj) + { + if (ddsrt_atomic_dec32_nv(&obj->refcount) == 0) + access_control_object_free(obj); + } +} + +struct AccessControlTable *access_control_table_new(void) +{ + struct AccessControlTable *table; + + table = ddsrt_malloc(sizeof(*table)); + table->htab = ddsrt_hh_new(32, access_control_object_hash, access_control_object_equal); + ddsrt_mutex_init(&table->lock); + return table; +} + +void access_control_table_free(struct AccessControlTable *table) +{ + struct ddsrt_hh_iter it; + AccessControlObject *obj; + + if (!table) + return; + for (obj = ddsrt_hh_iter_first(table->htab, &it); obj; obj = ddsrt_hh_iter_next(&it)) + { + (void)ddsrt_hh_remove(table->htab, obj); + access_control_object_release(obj); + } + ddsrt_hh_free(table->htab); + ddsrt_mutex_destroy(&table->lock); + ddsrt_free(table); +} + +AccessControlObject *access_control_table_insert(struct AccessControlTable *table, AccessControlObject *object) +{ + AccessControlObject template; + AccessControlObject *cur; + assert(table); + assert(object); + template.handle = object->handle; + ddsrt_mutex_lock(&table->lock); + if (!(cur = access_control_object_keep(ddsrt_hh_lookup(table->htab, &template)))) + { + cur = access_control_object_keep(object); + (void)ddsrt_hh_add(table->htab, cur); + } + ddsrt_mutex_unlock(&table->lock); + return cur; +} + +void access_control_table_remove_object(struct AccessControlTable *table, AccessControlObject *object) +{ + assert(table); + assert(object); + ddsrt_mutex_lock(&table->lock); + (void)ddsrt_hh_remove(table->htab, object); + ddsrt_mutex_unlock(&table->lock); + access_control_object_release(object); +} + +AccessControlObject *access_control_table_remove(struct AccessControlTable *table, int64_t handle) +{ + AccessControlObject template; + AccessControlObject *object; + assert(table); + template.handle = handle; + ddsrt_mutex_lock(&table->lock); + if ((object = access_control_object_keep(ddsrt_hh_lookup(table->htab, &template)))) + { + (void)ddsrt_hh_remove(table->htab, object); + access_control_object_release(object); + } + ddsrt_mutex_unlock(&table->lock); + return object; +} + +AccessControlObject *access_control_table_find(struct AccessControlTable *table, int64_t handle) +{ + AccessControlObject template; + AccessControlObject *object; + assert(table); + template.handle = handle; + ddsrt_mutex_lock(&table->lock); + object = access_control_object_keep(ddsrt_hh_lookup(table->htab, &template)); + ddsrt_mutex_unlock(&table->lock); + return object; +} + +void access_control_table_walk(struct AccessControlTable *table, AccessControlTableCallback callback, void *arg) +{ + struct ddsrt_hh_iter it; + AccessControlObject *obj; + int r = 1; + assert(table); + assert(callback); + ddsrt_mutex_lock(&table->lock); + for (obj = ddsrt_hh_iter_first(table->htab, &it); r && obj; obj = ddsrt_hh_iter_next(&it)) + r = callback(obj, arg); + ddsrt_mutex_unlock(&table->lock); +} + +static void local_participant_access_rights_free(AccessControlObject *obj) +{ + local_participant_access_rights *rights = (local_participant_access_rights *)obj; + if (rights) + { + ddsrt_free(rights->permissions_document); + if (rights->permissions_ca) + X509_free(rights->permissions_ca); + access_control_object_deinit((AccessControlObject *)rights); + if (rights->governance_tree) + ac_return_governance_tree(rights->governance_tree); + if (rights->permissions_tree) + ac_return_permissions_tree(rights->permissions_tree); + ddsrt_free(rights->identity_subject_name); + ddsrt_free(rights); + } +} + +local_participant_access_rights *ac_local_participant_access_rights_new( + DDS_Security_IdentityHandle local_identity, + int domain_id, + char *permissions_document, + X509 *permissions_ca, + const char *identity_subject_name, + struct governance_parser *governance_tree, + struct permissions_parser *permissions_tree) +{ + local_participant_access_rights *rights = ddsrt_malloc(sizeof(local_participant_access_rights)); + memset(rights, 0, sizeof(local_participant_access_rights)); + access_control_object_init((AccessControlObject *)rights, ACCESS_CONTROL_OBJECT_KIND_LOCAL_PARTICIPANT, local_participant_access_rights_free); + rights->local_identity = local_identity; + rights->domain_id = domain_id; + rights->permissions_document = permissions_document; + rights->permissions_ca = permissions_ca; + rights->identity_subject_name = ddsrt_strdup(identity_subject_name); + rights->governance_tree = governance_tree; + rights->permissions_tree = permissions_tree; + return rights; +} + + +static void remote_participant_access_rights_free(AccessControlObject *obj) +{ + remote_participant_access_rights *rights = (remote_participant_access_rights *)obj; + if (rights) + { + if (rights->permissions) + { + assert(rights->permissions->ref_cnt > 0); + rights->permissions->ref_cnt--; + if (rights->permissions->ref_cnt == 0) + { + ac_return_permissions_tree(rights->permissions->permissions_tree); + ddsrt_free(rights->permissions->remote_permissions_token_class_id); + ddsrt_free(rights->permissions); + } + } + ddsrt_free(rights->identity_subject_name); + ACCESS_CONTROL_OBJECT_RELEASE(rights->local_rights); + access_control_object_deinit((AccessControlObject *)rights); + ddsrt_free(rights); + } +} + +remote_participant_access_rights * +ac_remote_participant_access_rights_new( + DDS_Security_IdentityHandle remote_identity, + const local_participant_access_rights *local_rights, + remote_permissions *permissions, + dds_time_t permission_expiry, + const DDS_Security_PermissionsToken *remote_permissions_token, + const char *identity_subject) +{ + remote_participant_access_rights *rights = ddsrt_malloc(sizeof(remote_participant_access_rights)); + memset(rights, 0, sizeof(remote_participant_access_rights)); + access_control_object_init((AccessControlObject *)rights, ACCESS_CONTROL_OBJECT_KIND_REMOTE_PARTICIPANT, remote_participant_access_rights_free); + rights->remote_identity = remote_identity; + rights->permissions = permissions; + rights->permissions_expiry = permission_expiry; + rights->local_rights = (local_participant_access_rights *)ACCESS_CONTROL_OBJECT_KEEP(local_rights); + if (rights->permissions) + { + rights->permissions->ref_cnt++; + if (rights->permissions->remote_permissions_token_class_id == NULL) + rights->permissions->remote_permissions_token_class_id = ddsrt_strdup(remote_permissions_token->class_id); + else + assert (strcmp (rights->permissions->remote_permissions_token_class_id, remote_permissions_token->class_id) == 0); + rights->identity_subject_name = ddsrt_strdup(identity_subject); + } + else + { + assert(identity_subject == NULL); + rights->identity_subject_name = NULL; + } + return rights; +} diff --git a/src/security/builtin_plugins/access_control/src/access_control_objects.h b/src/security/builtin_plugins/access_control/src/access_control_objects.h new file mode 100644 index 0000000..867bab9 --- /dev/null +++ b/src/security/builtin_plugins/access_control/src/access_control_objects.h @@ -0,0 +1,106 @@ +/* + * 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 ACCESS_CONTROL_OBJECTS_H +#define ACCESS_CONTROL_OBJECTS_H + +#include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/openssl_support.h" + +#define ACCESS_CONTROL_OBJECT(o) ((AccessControlObject *)(o)) +#define ACCESS_CONTROL_OBJECT_HANDLE(o) ((o) ? ACCESS_CONTROL_OBJECT(o)->handle : DDS_SECURITY_HANDLE_NIL) + +#define ACCESS_CONTROL_OBJECT_KEEP(o) access_control_object_keep((AccessControlObject *)(o)) +#define ACCESS_CONTROL_OBJECT_RELEASE(o) access_control_object_release((AccessControlObject *)(o)) +#define ACCESS_CONTROL_OBJECT_VALID(o,k) access_control_object_valid((AccessControlObject *)(o), k) + +typedef enum { + ACCESS_CONTROL_OBJECT_KIND_UNKNOWN, + ACCESS_CONTROL_OBJECT_KIND_LOCAL_PARTICIPANT, + ACCESS_CONTROL_OBJECT_KIND_REMOTE_PARTICIPANT, +} AccessControlObjectKind_t; + +typedef struct AccessControlObject AccessControlObject; +typedef void (*AccessControlObjectDestructor)(AccessControlObject *obj); + +struct AccessControlObject { + int64_t handle; + ddsrt_atomic_uint32_t refcount; + AccessControlObjectKind_t kind; + AccessControlObjectDestructor destructor; +}; + +typedef struct local_participant_access_rights { + AccessControlObject _parent; + DDS_Security_ParticipantSecurityAttributes participant_attributes; + DDS_Security_IdentityHandle local_identity; + struct governance_parser *governance_tree; + struct permissions_parser *permissions_tree; + int domain_id; + char *identity_subject_name; + char *permissions_document; + X509 *permissions_ca; + dds_time_t permissions_expiry; +} local_participant_access_rights; + + +typedef struct remote_permissions { + int ref_cnt; + struct permissions_parser *permissions_tree; + DDS_Security_string remote_permissions_token_class_id; +} remote_permissions; + +typedef struct remote_participant_access_rights { + AccessControlObject _parent; + DDS_Security_IdentityHandle remote_identity; + local_participant_access_rights *local_rights; + remote_permissions *permissions; + char *identity_subject_name; + dds_time_t permissions_expiry; +} remote_participant_access_rights; + +void access_control_object_init(AccessControlObject *obj, AccessControlObjectKind_t kind, AccessControlObjectDestructor destructor); +AccessControlObject *access_control_object_keep(AccessControlObject *obj); +void access_control_object_release(AccessControlObject *obj); +bool access_control_object_valid(const AccessControlObject *obj, AccessControlObjectKind_t kind); +void access_control_object_free(AccessControlObject *obj); + +struct AccessControlTable; +typedef int (*AccessControlTableCallback)(AccessControlObject *obj, void *arg); +struct AccessControlTable *access_control_table_new(void); + +void access_control_table_free(struct AccessControlTable *table); +AccessControlObject *access_control_table_insert(struct AccessControlTable *table, AccessControlObject *object); +void access_control_table_remove_object(struct AccessControlTable *table, AccessControlObject *object); +AccessControlObject *access_control_table_remove(struct AccessControlTable *table, int64_t handle); +AccessControlObject *access_control_table_find(struct AccessControlTable *table, int64_t handle); +void access_control_table_walk(struct AccessControlTable *table, AccessControlTableCallback callback, void *arg); + +local_participant_access_rights *ac_local_participant_access_rights_new( + DDS_Security_IdentityHandle local_identity, + int domain_id, + char *permissions_document, + X509 *permissions_ca, + const char* identity_subject_name, + struct governance_parser *governance_tree, + struct permissions_parser *permissions_tree); + +remote_participant_access_rights *ac_remote_participant_access_rights_new( + DDS_Security_IdentityHandle remote_identity, + const local_participant_access_rights *local_rights, + remote_permissions *permissions, + dds_time_t permission_expiry, + const DDS_Security_PermissionsToken *remote_permissions_token, + const char *identity_subject); + +#endif /* ACCESS_CONTROL_OBJECTS_H */ 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 new file mode 100644 index 0000000..2d7d3af --- /dev/null +++ b/src/security/builtin_plugins/access_control/src/access_control_parser.c @@ -0,0 +1,1210 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/misc.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/strtol.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/xmlparser.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "access_control_parser.h" +#include "access_control_utils.h" + +#define DEBUG_PARSER 0 +#if (DEBUG_PARSER) + +static void print_tab(int spaces) +{ + while (spaces > 0) + { + printf(" "); + spaces--; + } +} + +static void print_string_value(struct string_value *val, const char *info, int spaces) +{ + print_tab(spaces); + printf("%s", info); + if (val) + printf(": %s", val->value ? val->value : ""); + printf("\n"); +} + +#define PRINT_VALUE_BASIC(name_, type_) \ + static void print_##name_##_value (type_ *val, const char *info, int spaces) \ + { \ + print_tab(spaces); \ + printf("%s", info); \ + if (val) \ + printf(": %d", val->value); \ + printf("\n"); \ + } +PRINT_VALUE_BASIC(bool, struct boolean_value) +PRINT_VALUE_BASIC(int, struct integer_value) +PRINT_VALUE_BASIC(protection, struct protection_kind_value) +PRINT_VALUE_BASIC(basic_protection, struct basicprotection_kind_value) +#undef PRINT_VALUE_BASIC + +static void print_domains(struct domains *domains, int spaces) +{ + print_tab(spaces); + printf("domains {\n"); + if (domains) + { + struct domain_id_set *current = domains->domain_id_set; + while (current != NULL) + { + if (current->max == NULL) + { + print_int_value(current->min, "id", spaces + 3); + } + else + { + print_int_value(current->min, "min", spaces + 3); + print_int_value(current->max, "max", spaces + 3); + } + current = (struct domain_id_set *)current->node.next; + } + } + else + { + printf(" {\n"); + } + print_tab(spaces); + printf("}\n"); +} + +static void print_topic_rule(struct topic_rule *rule, int spaces) +{ + print_tab(spaces); + printf("topic_rule {\n"); + if (rule) + { + print_string_value(rule->topic_expression, "topic_expression", spaces + 3); + print_bool_value(rule->enable_discovery_protection, "enable_discovery_protection", spaces + 3); + print_bool_value(rule->enable_liveliness_protection, "enable_liveliness_protection", spaces + 3); + print_bool_value(rule->enable_read_access_control, "enable_read_access_control", spaces + 3); + print_bool_value(rule->enable_write_access_control, "enable_write_access_control", spaces + 3); + print_protection_value(rule->metadata_protection_kind, "metadata_protection_kind", spaces + 3); + print_basic_protection_value(rule->data_protection_kind, "data_protection_kind", spaces + 3); + } + else + { + printf(" {\n"); + } + print_tab(spaces); + printf("}\n"); +} + +static void print_topic_access_rules(struct topic_access_rules *tar, int spaces) +{ + print_tab(spaces); + printf("topic_access_rules {\n"); + if (tar) + { + struct topic_rule *current = tar->topic_rule; + while (current != NULL) + { + print_topic_rule(current, spaces + 3); + current = (struct topic_rule *)current->node.next; + } + } + else + { + printf(" {\n"); + } + print_tab(spaces); + printf("}\n"); +} + +static void print_domain_rule(struct domain_rule *rule, int spaces) +{ + print_tab(spaces); + printf("domain_rule {\n"); + if (rule) + { + print_domains(rule->domains, spaces + 3); + print_bool_value(rule->allow_unauthenticated_participants, "allow_unauthenticated_participants", spaces + 3); + print_bool_value(rule->enable_join_access_control, "enable_join_access_control", spaces + 3); + print_protection_value(rule->rtps_protection_kind, "rtps_protection_kind", spaces + 3); + print_protection_value(rule->discovery_protection_kind, "discovery_protection_kind", spaces + 3); + print_protection_value(rule->liveliness_protection_kind, "liveliness_protection_kind", spaces + 3); + print_topic_access_rules(rule->topic_access_rules, spaces + 3); + } + else + { + printf(" {\n"); + } + print_tab(spaces); + printf("}\n"); +} + +static void print_domain_access_rules(struct domain_access_rules *dar, int spaces) +{ + print_tab(spaces); + printf("domain_access_rules {\n"); + if (dar) + { + struct domain_rule *current = dar->domain_rule; + while (current != NULL) + { + print_domain_rule(current, spaces + 3); + current = (struct domain_rule *)current->node.next; + } + } + else + { + printf(" {\n"); + } + print_tab(spaces); + printf("}\n"); +} + +static void print_governance_parser_result(struct governance_parser *parser) +{ + assert(parser); + assert(parser->dds); + assert(parser->dds->domain_access_rules); + printf("-----------------------------------------------\n"); + print_domain_access_rules(parser->dds->domain_access_rules, 0); + printf("-----------------------------------------------\n"); +} + +static void print_topic(struct string_value *topic, int spaces) +{ + if (topic) + { + print_string_value(topic, "topic", spaces); + print_topic((struct string_value *)topic->node.next, spaces); + } +} + +static void print_topics(struct topics *topics, int spaces) +{ + if (topics) + { + print_tab(spaces); + printf("topics {\n"); + print_topic(topics->topic, spaces + 3); + print_tab(spaces); + printf("}\n"); + } +} + +static void print_partition(struct string_value *partition, int spaces) +{ + if (partition) + { + print_string_value(partition, "partition", spaces); + print_partition((struct string_value *)partition->node.next, spaces); + } +} + +static void print_partitions(struct partitions *partitions, int spaces) +{ + if (partitions) + { + print_tab(spaces); + printf("partitions {\n"); + print_partition(partitions->partition, spaces + 3); + print_tab(spaces); + printf("}\n"); + } +} + +static void print_criteria(struct criteria *criteria, int spaces) +{ + if (criteria) + { + struct criteria *current = criteria; + while (current != NULL) + { + print_tab(spaces); + if (current->criteria_type == SUBSCRIBE_CRITERIA) + printf("subscribe {\n"); + else if (current->criteria_type == PUBLISH_CRITERIA) + printf("publish {\n"); + else + assert(0); + print_topics(current->topics, spaces + 3); + print_partitions(current->partitions, spaces + 3); + print_tab(spaces); + printf("}\n"); + current = (struct criteria *)current->node.next; + } + } +} + +static void print_allow_deny_rule(struct allow_deny_rule *allow_deny_rule, int spaces) +{ + if (allow_deny_rule) + { + struct allow_deny_rule *current = allow_deny_rule; + while (current != NULL) + { + print_tab(spaces); + if (current->rule_type == ALLOW_RULE) + printf("allow_rule {\n"); + else if (current->rule_type == DENY_RULE) + printf("deny_rule {\n"); + else + assert(0); + print_domains(current->domains, spaces + 3); + print_criteria(current->criteria, spaces + 3); + print_tab(spaces); + printf("}\n"); + current = (struct allow_deny_rule *)current->node.next; + } + } +} + +static void print_permissions(struct permissions *permissions, int spaces) +{ + struct grant *current = permissions->grant; + print_tab(spaces); + printf("permissions {\n"); + while (current != NULL) + { + print_tab(spaces + 3); + printf("grant {\n"); + print_tab(spaces + 6); + printf("name: %s\n", current->name); + print_string_value(current->subject_name, "subject_name", spaces + 6); + print_string_value(current->validity->not_before, "validity_not_before", spaces + 6); + print_string_value(current->validity->not_after, "validity_not_after", spaces + 6); + print_allow_deny_rule(current->allow_deny_rule, spaces + 6); + print_string_value(current->default_action, "default", spaces + 6); + current = (struct grant *)current->node.next; + print_tab(spaces + 3); + printf("}\n"); + } + print_tab(spaces); + printf("}\n"); +} + +static void print_permissions_parser_result(struct permissions_parser *parser) +{ + assert(parser); + assert(parser->dds); + assert(parser->dds->permissions); + printf("-----------------------------------------------\n"); + print_permissions(parser->dds->permissions, 0); + printf("-----------------------------------------------\n"); +} + +#endif /* DEBUG_PARSER */ + +static struct element *new_element(element_kind kind, struct element *parent, size_t size) +{ + struct element *e = ddsrt_malloc(size); + memset(e, 0, size); + e->parent = parent; + e->kind = kind; + e->next = NULL; + return e; +} + +#define PREPARE_NODE(element_type, element_kind, element_name, parent_type, parent_kind, current) \ + { \ + xml_##parent_type *P = (xml_##parent_type *)current; \ + if (!current || current->kind != ELEMENT_KIND_##parent_kind) \ + { \ + return -1; \ + } \ + current = new_element(ELEMENT_KIND_##element_kind, current, sizeof(xml_##element_type)); \ + P->element_name = (xml_##element_type *)current; \ + } + +#define PREPARE_NODE_WITH_LIST(element_type, element_kind, element_name, parent_type, parent_kind, current) \ + { \ + xml_##parent_type *P = (xml_##parent_type *)current; \ + xml_element *tail; \ + if (!current || current->kind != ELEMENT_KIND_##parent_kind) \ + { \ + return -1; \ + } \ + tail = (xml_element *)P->element_name; \ + current = new_element(ELEMENT_KIND_##element_kind, current, sizeof(xml_##element_type)); \ + if (!P->element_name) \ + { \ + P->element_name = (xml_##element_type *)current; \ + } \ + else \ + { \ + while (tail->next != NULL) \ + { \ + tail = tail->next; \ + } \ + tail->next = current; \ + tail->next->next = NULL; \ + } \ + } + +static void validate_domains(const struct domain_id_set *domains_set, DDS_Security_SecurityException *ex) +{ + const struct domain_id_set *domain = domains_set; + if (!domains_set) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found domain set in Governance file without domain ids."); + return; + } + while (domain != NULL && ex->code == 0) + { + if (!domain->min) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found domain range in Governance file without minimum value."); + else if (!domain->max) + ; /* The max isn't set with only an id (no range), so no error. */ + else if (domain->max->value < domain->min->value) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found domain range in Governance file with invalid range min(%d) max(%d).", domain->min->value, domain->max->value); + domain = (struct domain_id_set *)domain->node.next; + } +} + +static void validate_topic_rules(const struct topic_rule *topic_rule, DDS_Security_SecurityException *ex) +{ + while (topic_rule && ex->code == 0) + { + if (!topic_rule->data_protection_kind) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found topic rule in Governance file without data_protection_kind"); + else if (!topic_rule->enable_discovery_protection) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found topic rule in Governance file without enable_discovery_protection"); + else if (!topic_rule->enable_liveliness_protection) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found topic rule in Governance file without enable_liveliness_protection"); + else if (!topic_rule->enable_read_access_control) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found topic rule in Governance file without enable_read_access_control"); + else if (!topic_rule->enable_write_access_control) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found topic rule in Governance file without enable_write_access_control"); + else if (!topic_rule->metadata_protection_kind) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found topic rule in Governance file without metadata_protection_kind"); + else + topic_rule = (struct topic_rule *)topic_rule->node.next; + } +} + +static DDS_Security_boolean validate_rules(const struct domain_rule *rule, DDS_Security_SecurityException *ex) +{ + while (rule && ex->code == 0) + { + if (!rule->domains) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found rule in Governance file without domain ids."); + else if (!rule->allow_unauthenticated_participants) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found rule in Governance file without allow_unauthenticated_participants."); + else if (!rule->enable_join_access_control) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found rule in Governance file without enable_join_access_control."); + else if (!rule->rtps_protection_kind) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found rule in Governance file without rtps_protection_kind."); + else if (!rule->discovery_protection_kind) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found rule in Governance file without discovery_protection_kind."); + else if (!rule->liveliness_protection_kind) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found rule in Governance file without liveliness_protection_kind."); + else + { + /* Last but not least, check the domain ids (ex is set when there's a failure) */ + validate_domains(rule->domains->domain_id_set, ex); + if (!(rule->topic_access_rules && rule->topic_access_rules->topic_rule)) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, "Found rule in Governance file without topic_access_rules"); + else + { + validate_topic_rules(rule->topic_access_rules->topic_rule, ex); + rule = (struct domain_rule *)rule->node.next; + } + } + } + return (ex->code == 0); +} + +static int validate_permissions_tree(const struct grant *grant, DDS_Security_SecurityException *ex) +{ + while (grant && (ex->code == 0)) + { + xml_allow_deny_rule *allow_deny_rule; + if (!grant->subject_name || !grant->subject_name->value) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_CODE, 0, "Found tree in Permissions file without subject name."); + else if (!grant->validity) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_CODE, 0, "Found tree in Permissions file without Validity."); + else if (!grant->validity->not_after || !grant->validity->not_after->value) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_CODE, 0, "Found tree in Permissions file without Validity/not_after."); + else if (!grant->validity->not_before || !grant->validity->not_before->value) + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_CODE, 0, "Found tree in Permissions file without Validity/not_before."); + else + { + /*validate partitions*/ + allow_deny_rule = grant->allow_deny_rule; + while (allow_deny_rule) + { + xml_criteria *criteria = allow_deny_rule->criteria; + while (criteria) + { + /* set to default partition, if there is no partition specifien in the XML. (DDS Security SPEC 9.4.1.3.2.3.1.4)*/ + if (criteria->partitions == NULL) + { + xml_element *criteria_element = &(criteria->node); + xml_element *partitions_element; + PREPARE_NODE(partitions, PARTITIONS, partitions, criteria, CRITERIA, criteria_element) + assert(criteria->partitions); + partitions_element = &(criteria->partitions->node); + PREPARE_NODE_WITH_LIST(string_value, STRING_VALUE, partition, partitions, PARTITIONS, partitions_element) + assert(criteria->partitions->partition); + criteria->partitions->partition->value = ddsrt_strdup(""); + } + criteria = (xml_criteria *)criteria->node.next; + } + allow_deny_rule = (xml_allow_deny_rule *)allow_deny_rule->node.next; + } + } + grant = (struct grant *)grant->node.next; + } + return (ex->code == 0); +} + +static int to_protection_kind(const char *kindStr, DDS_Security_ProtectionKind *kindEnum) +{ + if (strcmp(kindStr, "ENCRYPT_WITH_ORIGIN_AUTHENTICATION") == 0) + *kindEnum = DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION; + else if (strcmp(kindStr, "SIGN_WITH_ORIGIN_AUTHENTICATION") == 0) + *kindEnum = DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION; + else if (strcmp(kindStr, "ENCRYPT") == 0) + *kindEnum = DDS_SECURITY_PROTECTION_KIND_ENCRYPT; + else if (strcmp(kindStr, "SIGN") == 0) + *kindEnum = DDS_SECURITY_PROTECTION_KIND_SIGN; + else if (strcmp(kindStr, "NONE") == 0) + *kindEnum = DDS_SECURITY_PROTECTION_KIND_NONE; + else + return -1; + return 0; +} + +static int to_basic_protection_kind(const char *kindStr, DDS_Security_BasicProtectionKind *kindEnum) +{ + if (strcmp(kindStr, "ENCRYPT") == 0) + *kindEnum = DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT; + else if (strcmp(kindStr, "SIGN") == 0) + *kindEnum = DDS_SECURITY_BASICPROTECTION_KIND_SIGN; + else if (strcmp(kindStr, "NONE") == 0) + *kindEnum = DDS_SECURITY_BASICPROTECTION_KIND_NONE; + else + return -1; + return 0; +} + +static int governance_element_open_cb(void *varg, uintptr_t parentinfo, uintptr_t *eleminfo, const char *name, int line) +{ + governance_parser *parser = (governance_parser *)varg; + DDS_Security_SecurityException ex; + memset(&ex, 0, sizeof(DDS_Security_SecurityException)); + DDSRT_UNUSED_ARG(parentinfo); + DDSRT_UNUSED_ARG(eleminfo); + DDSRT_UNUSED_ARG(line); + if (ddsrt_strcasecmp(name, "dds") == 0) + { + /* This should be the first element. */ + if (parser->current || parser->dds) + return -1; + parser->current = new_element(ELEMENT_KIND_DDS, NULL, sizeof(struct governance_dds)); + parser->dds = (struct governance_dds *)parser->current; + } + else if (ddsrt_strcasecmp(name, "domain_access_rules") == 0) + PREPARE_NODE(domain_access_rules, DOMAIN_ACCESS_RULES, domain_access_rules, governance_dds, DDS, parser->current) + else if (ddsrt_strcasecmp(name, "domain_rule") == 0) + PREPARE_NODE_WITH_LIST(domain_rule, DOMAIN_RULE, domain_rule, domain_access_rules, DOMAIN_ACCESS_RULES, parser->current) + else if (ddsrt_strcasecmp(name, "domains") == 0) + PREPARE_NODE(domains, DOMAINS, domains, domain_rule, DOMAIN_RULE, parser->current) + else if (ddsrt_strcasecmp(name, "id") == 0) + { + xml_domains *domains = (xml_domains *)parser->current; + xml_domain_id_set *tail; + if (!parser->current || parser->current->kind != ELEMENT_KIND_DOMAINS) + return -1; + tail = domains->domain_id_set; + parser->current = new_element(ELEMENT_KIND_DOMAIN_VALUE, parser->current, sizeof(xml_integer_value)); + if (!tail) + { + domains->domain_id_set = (xml_domain_id_set *)new_element(ELEMENT_KIND_DOMAIN_ID_SET, parser->current, sizeof(xml_domain_id_set)); + tail = domains->domain_id_set; + } + else + { + while (tail->node.next != NULL) + tail = (xml_domain_id_set *)tail->node.next; + tail->node.next = new_element(ELEMENT_KIND_DOMAIN_ID_SET, parser->current, sizeof(xml_domain_id_set)); + tail = (xml_domain_id_set *)tail->node.next; + } + tail->min = (xml_integer_value *)parser->current; + tail->max = NULL; + } + else if (ddsrt_strcasecmp(name, "id_range") == 0) + PREPARE_NODE_WITH_LIST(domain_id_set, DOMAIN_ID_SET, domain_id_set, domains, DOMAINS, parser->current) + else if (ddsrt_strcasecmp(name, "min") == 0) + PREPARE_NODE(integer_value, DOMAIN_VALUE, min, domain_id_set, DOMAIN_ID_SET, parser->current) + else if (ddsrt_strcasecmp(name, "max") == 0) + PREPARE_NODE(integer_value, DOMAIN_VALUE, max, domain_id_set, DOMAIN_ID_SET, parser->current) + else if (ddsrt_strcasecmp(name, "allow_unauthenticated_participants") == 0) + PREPARE_NODE(boolean_value, BOOLEAN_VALUE, allow_unauthenticated_participants, domain_rule, DOMAIN_RULE, parser->current) + else if (ddsrt_strcasecmp(name, "enable_join_access_control") == 0) + PREPARE_NODE(boolean_value, BOOLEAN_VALUE, enable_join_access_control, domain_rule, DOMAIN_RULE, parser->current) + else if (ddsrt_strcasecmp(name, "rtps_protection_kind") == 0) + PREPARE_NODE(protection_kind_value, PROTECTION_KIND_VALUE, rtps_protection_kind, domain_rule, DOMAIN_RULE, parser->current) + else if (ddsrt_strcasecmp(name, "discovery_protection_kind") == 0) + PREPARE_NODE(protection_kind_value, PROTECTION_KIND_VALUE, discovery_protection_kind, domain_rule, DOMAIN_RULE, parser->current) + else if (ddsrt_strcasecmp(name, "liveliness_protection_kind") == 0) + PREPARE_NODE(protection_kind_value, PROTECTION_KIND_VALUE, liveliness_protection_kind, domain_rule, DOMAIN_RULE, parser->current) + else if (ddsrt_strcasecmp(name, "topic_access_rules") == 0) + PREPARE_NODE(topic_access_rules, TOPIC_ACCESS_RULES, topic_access_rules, domain_rule, DOMAIN_RULE, parser->current) + else if (ddsrt_strcasecmp(name, "topic_rule") == 0) + PREPARE_NODE_WITH_LIST(topic_rule, TOPIC_RULE, topic_rule, topic_access_rules, TOPIC_ACCESS_RULES, parser->current) + else if (ddsrt_strcasecmp(name, "enable_read_access_control") == 0) + PREPARE_NODE(boolean_value, BOOLEAN_VALUE, enable_read_access_control, topic_rule, TOPIC_RULE, parser->current) + else if (ddsrt_strcasecmp(name, "enable_write_access_control") == 0) + PREPARE_NODE(boolean_value, BOOLEAN_VALUE, enable_write_access_control, topic_rule, TOPIC_RULE, parser->current) + else if (ddsrt_strcasecmp(name, "metadata_protection_kind") == 0) + PREPARE_NODE(protection_kind_value, PROTECTION_KIND_VALUE, metadata_protection_kind, topic_rule, TOPIC_RULE, parser->current) + else if (ddsrt_strcasecmp(name, "data_protection_kind") == 0) + PREPARE_NODE(basicprotection_kind_value, BASICPROTECTION_KIND_VALUE, data_protection_kind, topic_rule, TOPIC_RULE, parser->current) + else if (ddsrt_strcasecmp(name, "enable_liveliness_protection") == 0) + PREPARE_NODE(boolean_value, BOOLEAN_VALUE, enable_liveliness_protection, topic_rule, TOPIC_RULE, parser->current) + else if (ddsrt_strcasecmp(name, "enable_discovery_protection") == 0) + PREPARE_NODE(boolean_value, BOOLEAN_VALUE, enable_discovery_protection, topic_rule, TOPIC_RULE, parser->current) + else if (ddsrt_strcasecmp(name, "topic_expression") == 0) + { + /* Current should be topic_rule. */ + struct topic_rule *topicRule = (struct topic_rule *)parser->current; + if (!parser->current || parser->current->kind != ELEMENT_KIND_TOPIC_RULE) + return -1; + parser->current = new_element(ELEMENT_KIND_STRING_VALUE, parser->current, sizeof(struct string_value)); + topicRule->topic_expression = (struct string_value *)parser->current; + } + else + { + printf("Unknown XML element: %s\n", name); + return -1; + } + + return 0; +} + +/* The function that is called on each attribute captured in XML. + * Only the following attributes will be handled: + * - name : the name of an element or attribute + */ +static int governance_element_attr_cb(void *varg, uintptr_t eleminfo, const char *name, const char *value, int line) +{ + /* There is no attribute in that XML */ + DDSRT_UNUSED_ARG(eleminfo); + DDSRT_UNUSED_ARG(varg); + DDSRT_UNUSED_ARG(value); + DDSRT_UNUSED_ARG(line); + + if (ddsrt_strcasecmp(name, "xmlns:xsi") == 0 || ddsrt_strcasecmp(name, "xsi:noNamespaceSchemaLocation") == 0) + return 0; + return -1; +} + +static bool str_to_intvalue(const char *image, int32_t *value) +{ + char *endptr; + long long l; + if (ddsrt_strtoll(image, &endptr, 0, &l) != DDS_RETCODE_OK) + return false; + *value = (int32_t)l; + if (*endptr != '\0') + return false; + return true; +} + +/* The function that is called on each data item captured in XML. + * - data: the string value between the element tags + */ +static int governance_element_data_cb(void *varg, uintptr_t eleminfo, const char *data, int line) +{ + struct governance_parser *parser = (struct governance_parser *)varg; + DDSRT_UNUSED_ARG(eleminfo); + DDSRT_UNUSED_ARG(line); + if (!parser || !parser->current) + return -1; + if (parser->current->kind == ELEMENT_KIND_STRING_VALUE) + { + struct string_value *value = (struct string_value *)parser->current; + value->value = ddsrt_strdup(data); + } + else if (parser->current->kind == ELEMENT_KIND_DOMAIN_VALUE) + { + struct integer_value *value = (struct integer_value *)parser->current; + if (str_to_intvalue(data, &value->value)) + { + if (value->value < 0 || value->value > 230) + return -1; + } + else + { + return -1; + } + } + else if (parser->current->kind == ELEMENT_KIND_BOOLEAN_VALUE) + { + struct boolean_value *value = (struct boolean_value *)parser->current; + if (ddsrt_strcasecmp("true", data) == 0 || strcmp("1", data) == 0) + value->value = true; + else if (ddsrt_strcasecmp("false", data) == 0 || strcmp("0", data) == 0) + value->value = false; + else + return -1; + } + else if (parser->current->kind == ELEMENT_KIND_PROTECTION_KIND_VALUE) + { + struct protection_kind_value *value = (struct protection_kind_value *)parser->current; + if (to_protection_kind(data, &(value->value)) != 0) + return -1; + } + else if (parser->current->kind == ELEMENT_KIND_BASICPROTECTION_KIND_VALUE) + { + struct basicprotection_kind_value *value = (struct basicprotection_kind_value *)parser->current; + if (to_basic_protection_kind(data, &(value->value)) != 0) + return -1; + } + else + { + return -1; + } + + return 0; +} + +static int governance_element_close_cb(void *varg, uintptr_t eleminfo, int line) +{ + struct governance_parser *parser = (struct governance_parser *)varg; + DDSRT_UNUSED_ARG(eleminfo); + DDSRT_UNUSED_ARG(line); + if (!parser->current) + return -1; + parser->current = parser->current->parent; + return 0; +} + +static void governance_error_cb(void *varg, const char *msg, int line) +{ + DDSRT_UNUSED_ARG(varg); + printf("Failed to parse configuration file: error %d - %s\n", line, msg); +} + +static void free_stringvalue(struct string_value *str) +{ + if (str) + { + ddsrt_free(str->value); + ddsrt_free(str); + } +} + +static void free_domainid_set(struct domain_id_set *dis) +{ + if (dis) + { + if (dis->node.next) + { + free_domainid_set((struct domain_id_set *)dis->node.next); + } + ddsrt_free(dis->min); + ddsrt_free(dis->max); + ddsrt_free(dis); + } +} + +static void free_domains(struct domains *domains) +{ + if (domains) + { + free_domainid_set(domains->domain_id_set); + ddsrt_free(domains); + } +} + +static void free_topic_rule(struct topic_rule *rule) +{ + if (rule) + { + if (rule->node.next) + free_topic_rule((struct topic_rule *)rule->node.next); + free_stringvalue(rule->topic_expression); + ddsrt_free(rule->enable_discovery_protection); + ddsrt_free(rule->enable_liveliness_protection); + ddsrt_free(rule->enable_read_access_control); + ddsrt_free(rule->enable_write_access_control); + ddsrt_free(rule->metadata_protection_kind); + ddsrt_free(rule->data_protection_kind); + ddsrt_free(rule); + } +} + +static void free_topic_access_rules(struct topic_access_rules *tar) +{ + if (tar) + { + struct topic_rule *current = tar->topic_rule; + free_topic_rule(current); + } + ddsrt_free(tar); +} + +static void free_domain_rule(struct domain_rule *rule) +{ + if (rule) + { + if (rule->node.next) + free_domain_rule((struct domain_rule *)rule->node.next); + free_domains(rule->domains); + ddsrt_free(rule->allow_unauthenticated_participants); + ddsrt_free(rule->enable_join_access_control); + ddsrt_free(rule->rtps_protection_kind); + ddsrt_free(rule->discovery_protection_kind); + ddsrt_free(rule->liveliness_protection_kind); + free_topic_access_rules(rule->topic_access_rules); + ddsrt_free(rule); + } +} + +static void free_domain_access_rules(struct domain_access_rules *dar) +{ + if (dar) + { + free_domain_rule(dar->domain_rule); + ddsrt_free(dar); + } +} + +bool ac_parse_governance_xml(const char *xml, struct governance_parser **governance_tree, DDS_Security_SecurityException *ex) +{ + struct governance_parser *parser = NULL; + struct ddsrt_xmlp_state *st = NULL; + if (xml) + { + struct ddsrt_xmlp_callbacks cb; + cb.elem_open = governance_element_open_cb; + cb.elem_data = governance_element_data_cb; + cb.elem_close = governance_element_close_cb; + cb.attr = governance_element_attr_cb; + cb.error = governance_error_cb; + parser = ddsrt_malloc(sizeof(struct governance_parser)); + parser->current = NULL; + parser->dds = NULL; + st = ddsrt_xmlp_new_string(xml, parser, &cb); + if (ddsrt_xmlp_parse(st) != 0) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_PARSE_GOVERNANCE_CODE, 0, DDS_SECURITY_ERR_CAN_NOT_PARSE_GOVERNANCE_MESSAGE); + goto err_xml_parsing; + } +#if DEBUG_PARSER + print_governance_parser_result(parser); +#endif + if ((parser->dds != NULL) && (parser->dds->domain_access_rules != NULL) && (parser->dds->domain_access_rules->domain_rule != NULL)) + { + if (!validate_rules(parser->dds->domain_access_rules->domain_rule, ex)) + goto err_rules_validation; + } + else + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_PARSE_GOVERNANCE_CODE, 0, DDS_SECURITY_ERR_CAN_NOT_PARSE_GOVERNANCE_MESSAGE); + goto err_parser_content; + } + *governance_tree = parser; + } + else + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_PARSE_GOVERNANCE_CODE, 0, DDS_SECURITY_ERR_CAN_NOT_PARSE_GOVERNANCE_MESSAGE); + goto err_xml; + } + ddsrt_xmlp_free(st); + return true; + +err_parser_content: +err_rules_validation: +err_xml_parsing: + ddsrt_xmlp_free(st); + ac_return_governance_tree(parser); +err_xml: + return false; +} + +void ac_return_governance_tree(struct governance_parser *parser) +{ + if (parser) + { + if (parser->dds) + { + free_domain_access_rules(parser->dds->domain_access_rules); + ddsrt_free(parser->dds); + } + ddsrt_free(parser); + } +} + +/* Permissions Callback functions */ + +static int permissions_element_open_cb(void *varg, uintptr_t parentinfo, uintptr_t *eleminfo, const char *name, int line) +{ + permissions_parser *parser = (permissions_parser *)varg; + DDS_Security_SecurityException ex; + memset(&ex, 0, sizeof(DDS_Security_SecurityException)); + DDSRT_UNUSED_ARG(parentinfo); + DDSRT_UNUSED_ARG(eleminfo); + DDSRT_UNUSED_ARG(line); + + /*it may be a valid element under an ignored element */ + if (parser->current && parser->current->kind == ELEMENT_KIND_IGNORED) + parser->current = new_element(ELEMENT_KIND_IGNORED, parser->current, sizeof(struct element)); + else if (ddsrt_strcasecmp(name, "dds") == 0) + { + /* This should be the first element. */ + if (parser->current || parser->dds) + return -1; + parser->current = new_element(ELEMENT_KIND_DDS, NULL, sizeof(struct permissions_dds)); + parser->dds = (struct permissions_dds *)parser->current; + } + else if (ddsrt_strcasecmp(name, "permissions") == 0) + PREPARE_NODE(permissions, PERMISSIONS, permissions, permissions_dds, DDS, parser->current) + else if (ddsrt_strcasecmp(name, "grant") == 0) + PREPARE_NODE_WITH_LIST(grant, GRANT, grant, permissions, PERMISSIONS, parser->current) + else if (ddsrt_strcasecmp(name, "domains") == 0) + PREPARE_NODE(domains, DOMAINS, domains, allow_deny_rule, ALLOW_DENY_RULE, parser->current) + else if (ddsrt_strcasecmp(name, "id") == 0) + { + xml_domains *domains = (xml_domains *)parser->current; + xml_domain_id_set *tail; + if (!parser->current || parser->current->kind != ELEMENT_KIND_DOMAINS) + return -1; + tail = domains->domain_id_set; + parser->current = new_element(ELEMENT_KIND_DOMAIN_VALUE, parser->current, sizeof(xml_integer_value)); + if (!tail) + { + domains->domain_id_set = (xml_domain_id_set *)new_element(ELEMENT_KIND_DOMAIN_ID_SET, parser->current, sizeof(xml_domain_id_set)); + tail = domains->domain_id_set; + } + else + { + while (tail->node.next != NULL) + tail = (xml_domain_id_set *)tail->node.next; + tail->node.next = new_element(ELEMENT_KIND_DOMAIN_ID_SET, parser->current, sizeof(xml_domain_id_set)); + tail = (xml_domain_id_set *)tail->node.next; + } + tail->min = (xml_integer_value *)parser->current; + tail->max = NULL; + } + else if (ddsrt_strcasecmp(name, "id_range") == 0) + PREPARE_NODE_WITH_LIST(domain_id_set, DOMAIN_ID_SET, domain_id_set, domains, DOMAINS, parser->current) + else if (ddsrt_strcasecmp(name, "min") == 0) + PREPARE_NODE(integer_value, DOMAIN_VALUE, min, domain_id_set, DOMAIN_ID_SET, parser->current) + else if (ddsrt_strcasecmp(name, "max") == 0) + PREPARE_NODE(integer_value, DOMAIN_VALUE, max, domain_id_set, DOMAIN_ID_SET, parser->current) + else if (ddsrt_strcasecmp(name, "subject_name") == 0) + PREPARE_NODE(string_value, STRING_VALUE, subject_name, grant, GRANT, parser->current) + else if (ddsrt_strcasecmp(name, "validity") == 0) + PREPARE_NODE(validity, VALIDITY, validity, grant, GRANT, parser->current) + else if (ddsrt_strcasecmp(name, "not_before") == 0) + PREPARE_NODE(string_value, STRING_VALUE, not_before, validity, VALIDITY, parser->current) + else if (ddsrt_strcasecmp(name, "not_after") == 0) + PREPARE_NODE(string_value, STRING_VALUE, not_after, validity, VALIDITY, parser->current) + else if (ddsrt_strcasecmp(name, "allow_rule") == 0) + { + PREPARE_NODE_WITH_LIST(allow_deny_rule, ALLOW_DENY_RULE, allow_deny_rule, grant, GRANT, parser->current) + ((xml_allow_deny_rule *)parser->current)->rule_type = ALLOW_RULE; + } + else if (ddsrt_strcasecmp(name, "deny_rule") == 0) + { + PREPARE_NODE_WITH_LIST(allow_deny_rule, ALLOW_DENY_RULE, allow_deny_rule, grant, GRANT, parser->current) + ((xml_allow_deny_rule *)parser->current)->rule_type = DENY_RULE; + } + else if (ddsrt_strcasecmp(name, "subscribe") == 0) + { + PREPARE_NODE_WITH_LIST(criteria, CRITERIA, criteria, allow_deny_rule, ALLOW_DENY_RULE, parser->current) + ((xml_criteria *)parser->current)->criteria_type = SUBSCRIBE_CRITERIA; + } + else if (ddsrt_strcasecmp(name, "publish") == 0) + { + PREPARE_NODE_WITH_LIST(criteria, CRITERIA, criteria, allow_deny_rule, ALLOW_DENY_RULE, parser->current) + ((xml_criteria *)parser->current)->criteria_type = PUBLISH_CRITERIA; + } + else if (ddsrt_strcasecmp(name, "topics") == 0) + PREPARE_NODE(topics, TOPICS, topics, criteria, CRITERIA, parser->current) + else if (ddsrt_strcasecmp(name, "topic") == 0) + PREPARE_NODE_WITH_LIST(string_value, STRING_VALUE, topic, topics, TOPICS, parser->current) + else if (ddsrt_strcasecmp(name, "partitions") == 0) + PREPARE_NODE(partitions, PARTITIONS, partitions, criteria, CRITERIA, parser->current) + else if (ddsrt_strcasecmp(name, "partition") == 0) + PREPARE_NODE_WITH_LIST(string_value, STRING_VALUE, partition, partitions, PARTITIONS, parser->current) + else if (ddsrt_strcasecmp(name, "default") == 0) + PREPARE_NODE(string_value, STRING_VALUE, default_action, grant, GRANT, parser->current) + else if (ddsrt_strcasecmp(name, "relay") == 0 || + ddsrt_strcasecmp(name, "value") == 0 || + ddsrt_strcasecmp(name, "name") == 0 || + ddsrt_strcasecmp(name, "tag") == 0 || + ddsrt_strcasecmp(name, "data_tags") == 0) + { + 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 + { + printf("Unknown XML element: %s\n", name); + return -1; + } + + return 0; +} + +/* The function that is called on each attribute captured in XML. + * Only the following attributes will be handled: + * - name : the name of an element or attribute + */ +static int permissions_element_attr_cb(void *varg, uintptr_t eleminfo, const char *name, const char *value, int line) +{ + struct permissions_parser *parser = (struct permissions_parser *)varg; + DDSRT_UNUSED_ARG(eleminfo); + DDSRT_UNUSED_ARG(line); + if (ddsrt_strcasecmp(name, "xmlns:xsi") == 0 || ddsrt_strcasecmp(name, "xsi:noNamespaceSchemaLocation") == 0) + return 0; + if (strcmp(name, "name") == 0) + { + /* Parent should be grants. */ + struct grant *grant = (struct grant *)parser->current; + if (!parser->current || parser->current->kind != ELEMENT_KIND_GRANT) + return -1; + grant->name = ddsrt_strdup(value); + return 0; + } + return -1; +} + +/* The function that is called on each data item captured in XML. + * - data: the string value between the element tags */ +static int permissions_element_data_cb(void *varg, uintptr_t eleminfo, const char *data, int line) +{ + struct permissions_parser *parser = (struct permissions_parser *)varg; + DDS_Security_SecurityException ex; + memset(&ex, 0, sizeof(DDS_Security_SecurityException)); + DDSRT_UNUSED_ARG(eleminfo); + DDSRT_UNUSED_ARG(line); + if (!parser || !parser->current) + return -1; + if (parser->current->kind == ELEMENT_KIND_STRING_VALUE) + { + struct string_value *value = (struct string_value *)parser->current; + value->value = ddsrt_strdup(data); + } + else if (parser->current->kind == ELEMENT_KIND_DOMAIN_VALUE) + { + struct integer_value *value = (struct integer_value *)parser->current; + if (str_to_intvalue(data, &value->value)) + { + if (value->value < 0 || value->value > 230) + return -1; + } + else + return -1; + } + else + { + if (parser->current->kind != ELEMENT_KIND_IGNORED) + return -1; + } + return 0; +} + +static int permissions_element_close_cb(void *varg, uintptr_t eleminfo, int line) +{ + struct permissions_parser *parser = (struct permissions_parser *)varg; + struct element *parent; + DDSRT_UNUSED_ARG(eleminfo); + DDSRT_UNUSED_ARG(line); + + if (!parser->current) + return -1; + parent = parser->current->parent; + if (parser->current->kind == ELEMENT_KIND_IGNORED) + ddsrt_free(parser->current); + parser->current = parent; + return 0; +} + +static void permissions_error_cb(void *varg, const char *msg, int line) +{ + DDSRT_UNUSED_ARG(varg); + printf("Failed to parse configuration file: error %d - %s\n", line, msg); +} + +bool ac_parse_permissions_xml(const char *xml, struct permissions_parser **permissions_tree, DDS_Security_SecurityException *ex) +{ + struct permissions_parser *parser = NULL; + struct ddsrt_xmlp_state *st = NULL; + + if (xml) + { + struct ddsrt_xmlp_callbacks cb; + cb.elem_open = permissions_element_open_cb; + cb.elem_data = permissions_element_data_cb; + cb.elem_close = permissions_element_close_cb; + cb.attr = permissions_element_attr_cb; + cb.error = permissions_error_cb; + parser = ddsrt_malloc(sizeof(struct permissions_parser)); + parser->current = NULL; + parser->dds = NULL; + st = ddsrt_xmlp_new_string(xml, parser, &cb); + if (ddsrt_xmlp_parse(st) != 0) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_CODE, 0, DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_MESSAGE); + goto err_xml_parsing; + } +#if DEBUG_PARSER + print_permissions_parser_result(parser); +#endif + if ((parser->dds != NULL) && (parser->dds->permissions != NULL) && (parser->dds->permissions->grant != NULL)) + { + if (!validate_permissions_tree(parser->dds->permissions->grant, ex)) + goto err_parser_content; + } + else + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_CODE, 0, DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_MESSAGE); + goto err_parser_content; + } + *permissions_tree = parser; + } + else + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_CODE, 0, DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_MESSAGE); + goto err_xml; + } + ddsrt_xmlp_free(st); + return true; + +err_parser_content: +err_xml_parsing: + ddsrt_xmlp_free(st); + ac_return_permissions_tree(parser); +err_xml: + return false; +} + +static void free_topic(struct string_value *topic) +{ + if (topic) + { + if (topic->node.next != NULL) + free_topic((struct string_value *)topic->node.next); + free_stringvalue(topic); + } +} + +static void free_topics(struct topics *topics) +{ + if (topics) + { + free_topic(topics->topic); + ddsrt_free(topics); + } +} + +static void free_partition(struct string_value *partition) +{ + if (partition) + { + if (partition->node.next != NULL) + free_partition((struct string_value *)partition->node.next); + free_stringvalue(partition); + } +} + +static void free_partitions(struct partitions *partitions) +{ + if (partitions) + { + free_partition(partitions->partition); + ddsrt_free(partitions); + } +} + +static void free_validity(struct validity *validity) +{ + if (validity) + { + free_stringvalue(validity->not_after); + free_stringvalue(validity->not_before); + ddsrt_free(validity); + } +} + +static void free_criteria(struct criteria *criteria) +{ + if (criteria) + { + if (criteria->node.next) + free_criteria((struct criteria *)criteria->node.next); + free_partitions(criteria->partitions); + free_topics(criteria->topics); + ddsrt_free(criteria); + } +} + +static void free_allow_deny_rule(struct allow_deny_rule *rule) +{ + if (rule) + { + free_allow_deny_rule((struct allow_deny_rule *)rule->node.next); + free_domains(rule->domains); + free_criteria(rule->criteria); + ddsrt_free(rule); + } +} + +static void free_grant(struct grant *grant) +{ + if (grant) + { + if (grant->node.next) + free_grant((struct grant *)grant->node.next); + ddsrt_free(grant->name); + free_stringvalue(grant->subject_name); + free_stringvalue(grant->default_action); + free_validity(grant->validity); + free_allow_deny_rule(grant->allow_deny_rule); + ddsrt_free(grant); + } +} + +static void free_permissions(struct permissions *permissions) +{ + if (permissions) + { + free_grant(permissions->grant); + ddsrt_free(permissions); + } +} + +void ac_return_permissions_tree(struct permissions_parser *parser) +{ + if (parser) + { + if (parser->dds) + { + free_permissions(parser->dds->permissions); + ddsrt_free(parser->dds); + } + ddsrt_free(parser); + } +} diff --git a/src/security/builtin_plugins/access_control/src/access_control_parser.h b/src/security/builtin_plugins/access_control/src/access_control_parser.h new file mode 100644 index 0000000..b4ed491 --- /dev/null +++ b/src/security/builtin_plugins/access_control/src/access_control_parser.h @@ -0,0 +1,301 @@ +/* + * 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 ACCESS_CONTROL_PARSER_H +#define ACCESS_CONTROL_PARSER_H + +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" + +typedef enum +{ + ELEMENT_KIND_UNDEFINED, + ELEMENT_KIND_DDS, + ELEMENT_KIND_DOMAIN_ACCESS_RULES, + ELEMENT_KIND_DOMAIN_RULE, + ELEMENT_KIND_DOMAINS, + ELEMENT_KIND_DOMAIN_ID_SET, + ELEMENT_KIND_RANGE, + ELEMENT_KIND_ALLOW_UNAUTHENTICATED_PARTICIPANTS, + ELEMENT_KIND_ENABLE_JOIN_ACCESS_CONTROL, + ELEMENT_KIND_RTPS_PROTECTION, + ELEMENT_KIND_DISCOVERY_PROTECTION, + ELEMENT_KIND_LIVELINESS_PROTECTION, + ELEMENT_KIND_TOPIC_ACCESS_RULES, + ELEMENT_KIND_TOPIC_RULE, + ELEMENT_KIND_STRING_VALUE, + ELEMENT_KIND_BOOLEAN_VALUE, + ELEMENT_KIND_DOMAIN_VALUE, + ELEMENT_KIND_PROTECTION_KIND_VALUE, + ELEMENT_KIND_BASICPROTECTION_KIND_VALUE, + ELEMENT_KIND_PERMISSIONS, + ELEMENT_KIND_GRANT, + ELEMENT_KIND_ALLOW_DENY_RULE, + ELEMENT_KIND_CRITERIA, + ELEMENT_KIND_VALIDITY, + ELEMENT_KIND_TOPICS, + ELEMENT_KIND_PARTITIONS, + ELEMENT_KIND_DEFAULT, + ELEMENT_KIND_IGNORED +} element_kind; + +typedef enum +{ + UNKNOWN_CRITERIA, + SUBSCRIBE_CRITERIA, + PUBLISH_CRITERIA +} permission_criteria_type; + +typedef enum +{ + ALLOW_RULE, + DENY_RULE +} permission_rule_type; + +typedef struct element +{ + struct element *parent; + element_kind kind; + struct element *next; /*used in case of string list usage */ +} xml_element; + +/* TODO: Change the value nodes for specific nodes for + * proper value parsing and validating. */ + +typedef struct string_value +{ + struct element node; + char *value; +} xml_string_value; + +typedef struct boolean_value +{ + struct element node; + bool value; +} xml_boolean_value; + +typedef struct integer_value +{ + struct element node; + int32_t value; +} xml_integer_value; + +typedef struct protection_kind_value +{ + struct element node; + DDS_Security_ProtectionKind value; +} xml_protection_kind_value; + +typedef struct basicprotection_kind_value +{ + struct element node; + DDS_Security_BasicProtectionKind value; +} xml_basicprotection_kind_value; + +typedef struct domain_id_set +{ + struct element node; + struct integer_value *min; + struct integer_value *max; +} xml_domain_id_set; + +typedef struct domains +{ + struct element node; + struct domain_id_set *domain_id_set; /*linked list*/ +} xml_domains; + +typedef struct topic_rule +{ + struct element node; + struct string_value *topic_expression; + struct boolean_value *enable_discovery_protection; + struct boolean_value *enable_liveliness_protection; + struct boolean_value *enable_read_access_control; + struct boolean_value *enable_write_access_control; + struct protection_kind_value *metadata_protection_kind; + struct basicprotection_kind_value *data_protection_kind; +} xml_topic_rule; + +typedef struct topic_access_rules +{ + struct element node; + struct topic_rule *topic_rule; /*linked_list*/ +} xml_topic_access_rules; + +typedef struct domain_rule +{ + struct element node; + struct domains *domains; + struct boolean_value *allow_unauthenticated_participants; + struct boolean_value *enable_join_access_control; + struct protection_kind_value *discovery_protection_kind; + struct protection_kind_value *liveliness_protection_kind; + struct protection_kind_value *rtps_protection_kind; + struct topic_access_rules *topic_access_rules; +} xml_domain_rule; + +typedef struct domain_access_rules +{ + struct element node; + struct domain_rule *domain_rule; +} xml_domain_access_rules; + +typedef struct governance_dds +{ + struct element node; + struct domain_access_rules *domain_access_rules; +} xml_governance_dds; + +typedef struct governance_parser +{ + struct governance_dds *dds; + struct element *current; +} governance_parser; + +/* permissions file specific types */ +typedef struct validity +{ + struct element node; + struct string_value *not_before; + struct string_value *not_after; +} xml_validity; + +typedef struct topics +{ + struct element node; + struct string_value *topic; +} xml_topics; + +typedef struct partitions +{ + struct element node; + struct string_value *partition; +} xml_partitions; + +typedef struct criteria +{ + struct element node; + permission_criteria_type criteria_type; + struct topics *topics; + struct partitions *partitions; +} xml_criteria; + +typedef struct allow_deny_rule +{ + struct element node; + permission_rule_type rule_type; + struct domains *domains; + struct criteria *criteria; +} xml_allow_deny_rule; + +typedef struct grant +{ + struct element node; + char *name; + struct string_value *subject_name; + struct validity *validity; + struct allow_deny_rule *allow_deny_rule; + struct string_value *default_action; +} xml_grant; + +typedef struct permissions +{ + struct element node; + struct grant *grant; +} xml_permissions; + +typedef struct permissions_dds +{ + struct element node; + struct permissions *permissions; +} xml_permissions_dds; + +typedef struct permissions_parser +{ + struct permissions_dds *dds; + struct element *current; +} permissions_parser; + +bool ac_parse_governance_xml(const char *xml, struct governance_parser **governance_tree, DDS_Security_SecurityException *ex); +bool ac_parse_permissions_xml(const char *xml, struct permissions_parser **permissions_tree, DDS_Security_SecurityException *ex); +void ac_return_governance_tree(struct governance_parser *parser); +void ac_return_permissions_tree(struct permissions_parser *parser); + +#define DDS_SECURITY_DEFAULT_GOVERNANCE " \ + \ + \ + \ + \ + \ + \ + 0 \ + 230 \ + \ + \ + \ + false \ + false \ + ENCRYPT \ + ENCRYPT \ + NONE \ + \ + \ + * \ + true \ + true \ + false \ + false \ + ENCRYPT \ + ENCRYPT \ + \ + \ + \ + \ + " + +#define DDS_SECURITY_DEFAULT_PERMISSIONS " \ + \ + \ + \ + DEFAULT_SUBJECT \ + \ + 2015-09-15T01:00:00 \ + 2115-09-15T01:00:00 \ + \ + \ + \ + \ + 0 \ + 230 \ + \ + \ + \ + \ + * \ + \ + \ + \ + \ + \ + * \ + \ + \ + \ + \ + DENY \ + \ + \ + " + +#endif /* ACCESS_CONTROL_UTILS_H */ diff --git a/src/security/builtin_plugins/access_control/src/access_control_utils.c b/src/security/builtin_plugins/access_control/src/access_control_utils.c new file mode 100644 index 0000000..c30dbf2 --- /dev/null +++ b/src/security/builtin_plugins/access_control/src/access_control_utils.c @@ -0,0 +1,403 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/misc.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/time.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/openssl_support.h" +#include "access_control_utils.h" + +#define SEQ_ERR -1 +#define SEQ_NOMATCH 0 +#define SEQ_MATCH 1 + +bool ac_X509_certificate_from_data(const char *data, int len, X509 **x509Cert, DDS_Security_SecurityException *ex) +{ + BIO *bio; + assert(data); + assert(len >= 0); + assert(x509Cert); + + /* load certificate in buffer */ + if ((bio = BIO_new_mem_buf((void *)data, len)) == NULL) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_ALLOCATION_FAILED_CODE, 0, DDS_SECURITY_ERR_ALLOCATION_FAILED_MESSAGE ": "); + return false; + } + if ((*x509Cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) == NULL) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CERTIFICATE_CODE, 0, DDS_SECURITY_ERR_INVALID_CERTICICATE_MESSAGE ": "); + BIO_free(bio); + return false; + } + BIO_free(bio); + return true; +} + +static bool X509_certificate_from_file(const char *filename, X509 **x509Cert, DDS_Security_SecurityException *ex) +{ + DDSRT_WARNING_MSVC_OFF(4996); + FILE *fp; + assert(filename); + assert(x509Cert); + + /* Check if this is a valid file by getting its size. */ + if (ac_regular_file_size(filename) == 0) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE, 0, DDS_SECURITY_ERR_INVALID_FILE_PATH_MESSAGE, filename); + return false; + } + if ((fp = fopen(filename, "r")) == NULL) + { + DDS_Security_Exception_set(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE, 0, DDS_SECURITY_ERR_INVALID_FILE_PATH_MESSAGE, filename); + return false; + } + if ((*x509Cert = PEM_read_X509(fp, NULL, NULL, NULL)) == NULL) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CERTIFICATE_CODE, 0, DDS_SECURITY_ERR_INVALID_CERTICICATE_MESSAGE ": "); + fclose(fp); + return false; + } + fclose(fp); + return true; + DDSRT_WARNING_MSVC_ON(4996); +} + +bool ac_X509_certificate_read(const char *data, X509 **x509Cert, DDS_Security_SecurityException *ex) +{ + bool result = false; + char *contents = NULL; + assert(data); + assert(x509Cert); + + switch (DDS_Security_get_conf_item_type(data, &contents)) + { + case DDS_SECURITY_CONFIG_ITEM_PREFIX_FILE: + result = X509_certificate_from_file(contents, x509Cert, ex); + break; + case DDS_SECURITY_CONFIG_ITEM_PREFIX_DATA: + result = ac_X509_certificate_from_data(contents, (int)strlen(contents), x509Cert, ex); + break; + case DDS_SECURITY_CONFIG_ITEM_PREFIX_PKCS11: + DDS_Security_Exception_set( + ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CERTIFICATE_TYPE_NOT_SUPPORTED_CODE, 0, + DDS_SECURITY_ERR_CERTIFICATE_TYPE_NOT_SUPPORTED_MESSAGE " (pkcs11)"); + break; + default: + DDS_Security_Exception_set( + ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CERTIFICATE_TYPE_NOT_SUPPORTED_CODE, 0, + DDS_SECURITY_ERR_CERTIFICATE_TYPE_NOT_SUPPORTED_MESSAGE); + break; + } + ddsrt_free(contents); + return result; +} + +char *ac_get_certificate_subject_name(X509 *cert, DDS_Security_SecurityException *ex) +{ + X509_NAME *name; + BIO *bio; + char *subject = NULL; + char *pmem; + size_t sz; + assert(cert); + if (!(bio = BIO_new(BIO_s_mem()))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_ALLOCATION_FAILED_CODE, 0, DDS_SECURITY_ERR_ALLOCATION_FAILED_MESSAGE ": "); + goto err_bio_alloc; + } + if (!(name = X509_get_subject_name(cert))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_SUBJECT_NAME_CODE, 0, DDS_SECURITY_ERR_INVALID_SUBJECT_NAME_MESSAGE ": "); + goto err_get_subject; + } + + /* TODO: check if this is the correct format of the subject name: check spec */ + X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253); + + sz = (size_t) BIO_get_mem_data(bio, &pmem); + subject = ddsrt_malloc(sz + 1); + + if (BIO_gets(bio, subject, (int)sz + 1) < 0) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_SUBJECT_NAME_CODE, 0, DDS_SECURITY_ERR_INVALID_SUBJECT_NAME_MESSAGE ": "); + ddsrt_free(subject); + subject = NULL; + } + BIO_free(bio); + return subject; + +err_get_subject: + BIO_free(bio); +err_bio_alloc: + return NULL; +} + +static bool PKCS7_document_from_data(const char *data, size_t len, PKCS7 **p7, BIO **bcont, DDS_Security_SecurityException *ex) +{ + BIO *bio; + assert(data); + assert(p7); + assert(bcont); + + *bcont = NULL; + assert (len < INT32_MAX); + if ((bio = BIO_new_mem_buf((void *)data, (int)len)) == NULL) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_ALLOCATION_FAILED_CODE, 0, DDS_SECURITY_ERR_ALLOCATION_FAILED_MESSAGE ": "); + return false; + } + if ((*p7 = SMIME_read_PKCS7(bio, bcont)) == NULL) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_SMIME_DOCUMENT_CODE, 0, DDS_SECURITY_ERR_INVALID_SMIME_DOCUMENT_MESSAGE ": "); + BIO_free(bio); + return false; + } + BIO_free(bio); + return true; +} + +static bool PKCS7_document_verify(PKCS7 *p7, X509 *cert, BIO *inbio, BIO **outbio, DDS_Security_SecurityException *ex) +{ + bool result = false; + X509_STORE *store = NULL; + + assert(p7); + assert(cert); + assert(inbio); + assert(outbio); + + if ((*outbio = BIO_new(BIO_s_mem())) == NULL) + DDS_Security_Exception_set_with_openssl_error(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_ALLOCATION_FAILED_CODE, 0, DDS_SECURITY_ERR_ALLOCATION_FAILED_MESSAGE ": "); + else if ((store = X509_STORE_new()) == NULL) + DDS_Security_Exception_set_with_openssl_error(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_ALLOCATION_FAILED_CODE, 0, DDS_SECURITY_ERR_ALLOCATION_FAILED_MESSAGE ": "); + else + { + X509_STORE_add_cert(store, cert); + if (PKCS7_verify(p7, NULL, store, inbio, *outbio, PKCS7_TEXT) != 1) + DDS_Security_Exception_set_with_openssl_error(ex, DDS_ACCESS_CONTROL_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_SMIME_DOCUMENT_CODE, 0, DDS_SECURITY_ERR_INVALID_SMIME_DOCUMENT_MESSAGE ": "); + else + result = true; + } + if (store) + X509_STORE_free(store); + if (!result && *outbio) + { + BIO_free(*outbio); + *outbio = NULL; + } + return result; +} + +bool ac_PKCS7_document_check(const char *data, size_t len, X509 *cert, char **document, DDS_Security_SecurityException *ex) +{ + bool result = false; + PKCS7 *p7; + BIO *bcont, *bdoc; + char *pmem; + size_t sz; + + assert(data); + assert(cert); + assert(document); + + if (!PKCS7_document_from_data(data, len, &p7, &bcont, ex)) + goto err_read_data; + + if (!PKCS7_document_verify(p7, cert, bcont, &bdoc, ex)) + goto err_verify; + + sz = (size_t) BIO_get_mem_data(bdoc, &pmem); + *document = ddsrt_malloc(sz + 1); + memcpy(*document, pmem, sz); + (*document)[sz] = '\0'; + result = true; + BIO_free(bdoc); + +err_verify: + PKCS7_free(p7); + BIO_free(bcont); +err_read_data: + return result; +} + +static bool string_to_properties(const char *str, DDS_Security_PropertySeq *properties) +{ + char *copy = ddsrt_strdup (str), *cursor = copy, *tok; + while ((tok = ddsrt_strsep (&cursor, ",/|")) != NULL) + { + if (strlen(tok) == 0) + continue; + char *name = ddsrt_strsep (&tok, "="); + if (name == NULL || tok == NULL || properties->_length >= properties->_maximum) + { + ddsrt_free (copy); + return false; + } + properties->_buffer[properties->_length].name = ddsrt_strdup(name); + properties->_buffer[properties->_length].value = ddsrt_strdup(tok); + properties->_length++; + } + ddsrt_free (copy); + return true; +} + +bool ac_check_subjects_are_equal(const char *permissions_sn, const char *identity_sn) +{ + bool result = false; + char *copy_idsn = ddsrt_strdup (identity_sn), *cursor_idsn = copy_idsn, *tok_idsn; + DDS_Security_PropertySeq prop_pmsn; + prop_pmsn._length = 0; + prop_pmsn._maximum = 20; + prop_pmsn._buffer = ddsrt_malloc(prop_pmsn._maximum * sizeof(DDS_Security_Property_t)); + + if (!string_to_properties(permissions_sn, &prop_pmsn)) + goto check_subj_equal_failed; + + while ((tok_idsn = ddsrt_strsep (&cursor_idsn, ",/|")) != NULL) + { + char *value_pmsn; + char *name_idsn = ddsrt_strsep (&tok_idsn, "="); + if (name_idsn == NULL || tok_idsn == NULL) + goto check_subj_equal_failed; + value_pmsn = DDS_Security_Property_get_value(&prop_pmsn, name_idsn); + if (value_pmsn == NULL || strcmp(tok_idsn, value_pmsn) != 0) + { + ddsrt_free(value_pmsn); + goto check_subj_equal_failed; + } + ddsrt_free(value_pmsn); + } + result = true; + +check_subj_equal_failed: + ddsrt_free(copy_idsn); + DDS_Security_PropertySeq_deinit(&prop_pmsn); + return result; +} + +size_t ac_regular_file_size(const char *filename) +{ + if (filename) + { +#if _WIN32 + struct _stat stat_info; + if (_stat (filename, &stat_info) == 0) + if (stat_info.st_mode & _S_IFREG) + return (size_t) stat_info.st_size; +#else + struct stat stat_info; + if (stat (filename, &stat_info) == 0) + if (S_ISREG(stat_info.st_mode)) + return (size_t) stat_info.st_size; +#endif + } + return 0; +} + +static int sequencematch(const char *pat, char c, char **new_pat) +{ + char patc = *pat; + char rpatc; + const bool neg = (patc == '!'); + bool m = false; + + if (neg) + ++pat; + for (patc = *pat; patc != ']'; pat++) + { + patc = *pat; + if (patc == '\0') + return SEQ_ERR; + if (*(pat + 1) == '-') + { + rpatc = *(pat + 2); + if (rpatc == '\0' || rpatc == ']') + return SEQ_ERR; + if ((uint8_t)patc <= (uint8_t)c && (uint8_t)c <= (uint8_t)rpatc) + m = true; + pat += 2; + } + else if (patc == c) + m = true; + } + *new_pat = (char *) pat; + return (m != neg) ? SEQ_MATCH : SEQ_NOMATCH; +} + +bool ac_fnmatch(const char* pat, const char* str) +{ + char patc; + bool ret; + char *new_pat; + + assert(pat != NULL); + assert(str != NULL); + + for (;;) + { + switch (patc = *pat++) + { + case '\0': + return (*str == '\0'); + case '?': + if (*str == '\0') + return false; + ++str; + break; + case '*': + patc = *pat; + while (patc == '*') + patc = *++pat; + if (patc == '\0') + return true; + while (*str != '\0') + { + ret = ac_fnmatch(pat, str); + if (ret) + return true; + ++str; + } + return false; + break; + case '[': + if (*str == '\0') + return false; + switch (sequencematch(pat, *str, &new_pat)) + { + case SEQ_MATCH: + pat = new_pat; + ++str; + break; + case SEQ_NOMATCH: + case SEQ_ERR: + return false; + } + break; + default: /* Regular character */ + if (*str != patc) + return false; + str++; + break; + } + } +} + diff --git a/src/security/builtin_plugins/access_control/src/access_control_utils.h b/src/security/builtin_plugins/access_control/src/access_control_utils.h new file mode 100644 index 0000000..d786416 --- /dev/null +++ b/src/security/builtin_plugins/access_control/src/access_control_utils.h @@ -0,0 +1,30 @@ +/* + * 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 ACCESS_CONTROL_UTILS_H +#define ACCESS_CONTROL_UTILS_H + +#include "dds/ddsrt/types.h" +#include "dds/security/export.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/openssl_support.h" + +#define DDS_ACCESS_CONTROL_PLUGIN_CONTEXT "Access Control" + +bool ac_X509_certificate_read(const char *data, X509 **x509Cert, DDS_Security_SecurityException *ex); +bool ac_X509_certificate_from_data(const char *data, int len, X509 **x509Cert, DDS_Security_SecurityException *ex); +char *ac_get_certificate_subject_name(X509 *cert, DDS_Security_SecurityException *ex); +bool ac_PKCS7_document_check(const char *data, size_t len, X509 *cert, char **document, DDS_Security_SecurityException *ex); +bool ac_check_subjects_are_equal(const char *permissions_sn, const char *identity_sn); +size_t ac_regular_file_size(const char *filename); +SECURITY_EXPORT bool ac_fnmatch(const char* pattern, const char* string); + +#endif /* ACCESS_CONTROL_UTILS_H */ diff --git a/src/security/builtin_plugins/authentication/CMakeLists.txt b/src/security/builtin_plugins/authentication/CMakeLists.txt new file mode 100644 index 0000000..880b832 --- /dev/null +++ b/src/security/builtin_plugins/authentication/CMakeLists.txt @@ -0,0 +1,59 @@ +# +# Copyright(c) 2006 to 2019 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +include (GenerateExportHeader) + +PREPEND(srcs_authentication "${CMAKE_CURRENT_LIST_DIR}/src" + authentication.c + auth_utils.c +) + +PREPEND(hdrs_private_authentication "${CMAKE_CURRENT_LIST_DIR}/src" + auth_defs.h + authentication.h + auth_utils.h + dds_security_core_if.h +) + +add_library(dds_security_auth SHARED "") + +generate_export_header( + dds_security_auth + BASE_NAME SECURITY + EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/include/dds/security/export.h" +) + +target_link_libraries(dds_security_auth PRIVATE security_openssl) +target_link_libraries(dds_security_auth PUBLIC ddsc) +target_link_libraries(dds_security_auth PUBLIC OpenSSL::SSL) +if(CMAKE_GENERATOR MATCHES "Visual Studio") + set_target_properties(dds_security_auth PROPERTIES LINK_FLAGS "/ignore:4099") +endif() +target_sources(dds_security_auth PRIVATE ${srcs_authentication}) +target_include_directories(dds_security_auth + PUBLIC + "$>" + "$>" + "$>" + "$>" + "$" + "$" +) + +install( + TARGETS dds_security_auth + EXPORT "${PROJECT_NAME}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT lib + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib +) + + diff --git a/src/security/builtin_plugins/authentication/src/auth_utils.c b/src/security/builtin_plugins/authentication/src/auth_utils.c new file mode 100644 index 0000000..1eea973 --- /dev/null +++ b/src/security/builtin_plugins/authentication/src/auth_utils.c @@ -0,0 +1,988 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#include +#include + +#include "dds/ddsrt/time.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/filesystem.h" +#include "dds/ddsrt/retcode.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/io.h" +#include "dds/security/dds_security_api_defs.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/openssl_support.h" +#include "auth_utils.h" + +#define MAX_TRUSTED_CA 100 + +char *get_openssl_error_message(void) +{ + char *msg, *buf = NULL; + size_t len; + BIO *bio = BIO_new(BIO_s_mem()); + if (!bio) + return ddsrt_strdup("BIO_new failed"); + + ERR_print_errors(bio); + len = (size_t)BIO_get_mem_data(bio, &buf); + msg = ddsrt_malloc(len + 1); + memcpy(msg, buf, len); + msg[len] = '\0'; + BIO_free(bio); + return msg; +} + +char *get_certificate_subject_name(X509 *cert, DDS_Security_SecurityException *ex) +{ + X509_NAME *name; + assert(cert); + if (!(name = X509_get_subject_name(cert))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "X509_get_subject_name failed : "); + return NULL; + } + char *subject_openssl = X509_NAME_oneline(name, NULL, 0); + char *subject = ddsrt_strdup(subject_openssl); + OPENSSL_free(subject_openssl); + return subject; +} + +dds_time_t get_certificate_expiry(const X509 *cert) +{ + assert(cert); + ASN1_TIME *asn1 = X509_get_notAfter(cert); + if (asn1 != NULL) + { + int days, seconds; + if (ASN1_TIME_diff(&days, &seconds, NULL, asn1) == 1) + { + static const dds_duration_t secs_in_day = 86400; + const dds_time_t now = dds_time(); + const int64_t max_valid_days_to_wait = (INT64_MAX - now) / DDS_NSECS_IN_SEC / secs_in_day; + if (days < max_valid_days_to_wait) + { + dds_duration_t delta = ((dds_duration_t)seconds + ((dds_duration_t)days * secs_in_day)) * DDS_NSECS_IN_SEC; + return now + delta; + } + return DDS_NEVER; + } + } + return DDS_TIME_INVALID; +} + +DDS_Security_ValidationResult_t get_subject_name_DER_encoded(const X509 *cert, unsigned char **buffer, size_t *size, DDS_Security_SecurityException *ex) +{ + unsigned char *tmp = NULL; + int32_t sz; + X509_NAME *name; + + assert(cert); + assert(buffer); + assert(size); + + *size = 0; + if (!(name = X509_get_subject_name((X509 *)cert))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "X509_get_subject_name failed : "); + return DDS_SECURITY_VALIDATION_FAILED; + } + if ((sz = i2d_X509_NAME(name, &tmp)) <= 0) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "i2d_X509_NAME failed : "); + return DDS_SECURITY_VALIDATION_FAILED; + } + + *size = (size_t)sz; + *buffer = ddsrt_malloc(*size); + memcpy(*buffer, tmp, *size); + OPENSSL_free(tmp); + return DDS_SECURITY_VALIDATION_OK; +} + +static DDS_Security_ValidationResult_t check_key_type_and_size(EVP_PKEY *key, int isPrivate, DDS_Security_SecurityException *ex) +{ + const char *sub = isPrivate ? "private key" : "certificate"; + assert(key); + switch (EVP_PKEY_id(key)) + { + case EVP_PKEY_RSA: + if (EVP_PKEY_bits(key) != 2048) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "RSA %s has unsupported key size (%d)", sub, EVP_PKEY_bits(key)); + return DDS_SECURITY_VALIDATION_FAILED; + } + if (isPrivate) + { + RSA *rsaKey = EVP_PKEY_get1_RSA(key); + const bool fail = (rsaKey && RSA_check_key(rsaKey) != 1); + RSA_free(rsaKey); + if (fail) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "RSA key not correct : "); + return DDS_SECURITY_VALIDATION_FAILED; + } + } + return DDS_SECURITY_VALIDATION_OK; + + case EVP_PKEY_EC: + if (EVP_PKEY_bits(key) != 256) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "EC %s has unsupported key size (%d)", sub, EVP_PKEY_bits(key)); + return DDS_SECURITY_VALIDATION_FAILED; + } + EC_KEY *ecKey = EVP_PKEY_get1_EC_KEY(key); + const bool fail = (ecKey && EC_KEY_check_key(ecKey) != 1); + EC_KEY_free(ecKey); + if (fail) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "EC key not correct : "); + return DDS_SECURITY_VALIDATION_FAILED; + } + return DDS_SECURITY_VALIDATION_OK; + + default: + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "%s has not supported type", sub); + return DDS_SECURITY_VALIDATION_FAILED; + } +} + +static DDS_Security_ValidationResult_t check_certificate_type_and_size(X509 *cert, DDS_Security_SecurityException *ex) +{ + assert(cert); + EVP_PKEY *pkey = X509_get_pubkey(cert); + if (!pkey) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "X509_get_pubkey failed"); + return DDS_SECURITY_VALIDATION_FAILED; + } + DDS_Security_ValidationResult_t result = check_key_type_and_size(pkey, false, ex); + EVP_PKEY_free(pkey); + return result; +} + +DDS_Security_ValidationResult_t check_certificate_expiry(const X509 *cert, DDS_Security_SecurityException *ex) +{ + assert(cert); + if (X509_cmp_current_time(X509_get_notBefore(cert)) == 0) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CERT_STARTDATE_IN_FUTURE_CODE, DDS_SECURITY_VALIDATION_FAILED, DDS_SECURITY_ERR_CERT_STARTDATE_IN_FUTURE_MESSAGE); + return DDS_SECURITY_VALIDATION_FAILED; + } + if (X509_cmp_current_time(X509_get_notAfter(cert)) == 0) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CERT_EXPIRED_CODE, DDS_SECURITY_VALIDATION_FAILED, DDS_SECURITY_ERR_CERT_EXPIRED_MESSAGE); + return DDS_SECURITY_VALIDATION_FAILED; + } + return DDS_SECURITY_VALIDATION_OK; +} + +DDS_Security_ValidationResult_t load_X509_certificate_from_data(const char *data, int len, X509 **x509Cert, DDS_Security_SecurityException *ex) +{ + BIO *bio; + assert(data); + assert(len >= 0); + assert(x509Cert); + + if (!(bio = BIO_new_mem_buf((void *)data, len))) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "BIO_new_mem_buf failed"); + return DDS_SECURITY_VALIDATION_FAILED; + } + if (!(*x509Cert = PEM_read_bio_X509(bio, NULL, NULL, NULL))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to parse certificate: "); + BIO_free(bio); + return DDS_SECURITY_VALIDATION_FAILED; + } + BIO_free(bio); + + if (get_authentication_algo_kind(*x509Cert) == AUTH_ALGO_KIND_UNKNOWN) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CERT_AUTH_ALGO_KIND_UNKNOWN_CODE, DDS_SECURITY_VALIDATION_FAILED, DDS_SECURITY_ERR_CERT_AUTH_ALGO_KIND_UNKNOWN_MESSAGE); + X509_free(*x509Cert); + return DDS_SECURITY_VALIDATION_FAILED; + } + + return DDS_SECURITY_VALIDATION_OK; +} + +DDS_Security_ValidationResult_t load_X509_certificate_from_file(const char *filename, X509 **x509Cert, DDS_Security_SecurityException *ex) +{ + assert(filename); + assert(x509Cert); + + DDSRT_WARNING_MSVC_OFF(4996); + FILE *file_ptr = fopen(filename, "r"); + DDSRT_WARNING_MSVC_ON(4996); + + if (file_ptr == NULL) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE, DDS_SECURITY_VALIDATION_FAILED, DDS_SECURITY_ERR_INVALID_FILE_PATH_MESSAGE, filename); + return DDS_SECURITY_VALIDATION_FAILED; + } + if (!(*x509Cert = PEM_read_X509(file_ptr, NULL, NULL, NULL))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to parse certificate: "); + (void)fclose(file_ptr); + return DDS_SECURITY_VALIDATION_FAILED; + } + (void)fclose(file_ptr); + + if (get_authentication_algo_kind(*x509Cert) == AUTH_ALGO_KIND_UNKNOWN) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CERT_AUTH_ALGO_KIND_UNKNOWN_CODE, DDS_SECURITY_VALIDATION_FAILED, DDS_SECURITY_ERR_CERT_AUTH_ALGO_KIND_UNKNOWN_MESSAGE); + X509_free(*x509Cert); + return DDS_SECURITY_VALIDATION_FAILED; + } + + return DDS_SECURITY_VALIDATION_OK; +} + +static DDS_Security_ValidationResult_t load_private_key_from_data(const char *data, const char *password, EVP_PKEY **privateKey, DDS_Security_SecurityException *ex) +{ + BIO *bio; + assert(data); + assert(privateKey); + + if (!(bio = BIO_new_mem_buf((void *)data, -1))) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "BIO_new_mem_buf failed"); + return DDS_SECURITY_VALIDATION_FAILED; + } + if (!(*privateKey = PEM_read_bio_PrivateKey(bio, NULL, NULL, (void *)(password ? password : "")))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to parse private key: "); + BIO_free(bio); + return DDS_SECURITY_VALIDATION_FAILED; + } + + BIO_free(bio); + return DDS_SECURITY_VALIDATION_OK; +} + +static DDS_Security_ValidationResult_t load_private_key_from_file(const char *filepath, const char *password, EVP_PKEY **privateKey, DDS_Security_SecurityException *ex) +{ + FILE *file_ptr; + assert(filepath); + assert(privateKey); + + DDSRT_WARNING_MSVC_OFF(4996); + file_ptr = fopen(filepath, "r"); + DDSRT_WARNING_MSVC_ON(4996); + if (file_ptr == NULL) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE, DDS_SECURITY_VALIDATION_FAILED, DDS_SECURITY_ERR_INVALID_FILE_PATH_MESSAGE, filepath); + return DDS_SECURITY_VALIDATION_FAILED; + } + if (!(*privateKey = PEM_read_PrivateKey(file_ptr, NULL, NULL, (void *)(password ? password : "")))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to parse certificate: "); + (void)fclose(file_ptr); + return DDS_SECURITY_VALIDATION_FAILED; + } + + (void)fclose(file_ptr); + return DDS_SECURITY_VALIDATION_OK; +} + +/* + * Gets the URI string (as referred in DDS Security spec) and returns the URI type + * data: data part of the URI. Typically It contains different format according to URI type. + */ +AuthConfItemPrefix_t get_conf_item_type(const char *str, char **data) +{ + const char *f = "file:", *d = "data:,", *p = "pkcs11:"; + size_t sf = strlen(f), sd = strlen(d), sp = strlen(p); + assert(str); + assert(data); + + char *ptr = ddssec_strchrs(str, " \t", false); + if (strncmp(ptr, f, sf) == 0) + { + size_t e = strncmp(ptr + sf, "//", 2) == 0 ? 2 : 0; + *data = ddsrt_strdup(ptr + sf + e); + return AUTH_CONF_ITEM_PREFIX_FILE; + } + if (strncmp(ptr, d, sd) == 0) + { + *data = ddsrt_strdup(ptr + sd); + return AUTH_CONF_ITEM_PREFIX_DATA; + } + if (strncmp(ptr, p, sp) == 0) + { + *data = ddsrt_strdup(ptr + sp); + return AUTH_CONF_ITEM_PREFIX_PKCS11; + } + + return AUTH_CONF_ITEM_PREFIX_UNKNOWN; +} + +DDS_Security_ValidationResult_t load_X509_certificate(const char *data, X509 **x509Cert, DDS_Security_SecurityException *ex) +{ + DDS_Security_ValidationResult_t result; + char *contents = NULL; + assert(data); + assert(x509Cert); + + switch (get_conf_item_type(data, &contents)) + { + case AUTH_CONF_ITEM_PREFIX_FILE: + result = load_X509_certificate_from_file(contents, x509Cert, ex); + break; + case AUTH_CONF_ITEM_PREFIX_DATA: + result = load_X509_certificate_from_data(contents, (int)strlen(contents), x509Cert, ex); + break; + case AUTH_CONF_ITEM_PREFIX_PKCS11: + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Certificate pkcs11 format currently not supported:\n%s", data); + break; + default: + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Specified certificate has wrong format:\n%s", data); + break; + } + ddsrt_free(contents); + + if (result == DDS_SECURITY_VALIDATION_OK) + { + if (check_certificate_type_and_size(*x509Cert, ex) != DDS_SECURITY_VALIDATION_OK || + check_certificate_expiry(*x509Cert, ex) != DDS_SECURITY_VALIDATION_OK) + { + result = DDS_SECURITY_VALIDATION_FAILED; + X509_free(*x509Cert); + } + } + return result; +} + +DDS_Security_ValidationResult_t load_X509_private_key(const char *data, const char *password, EVP_PKEY **privateKey, DDS_Security_SecurityException *ex) +{ + DDS_Security_ValidationResult_t result; + char *contents = NULL; + assert(data); + assert(privateKey); + + switch (get_conf_item_type(data, &contents)) + { + case AUTH_CONF_ITEM_PREFIX_FILE: + result = load_private_key_from_file(contents, password, privateKey, ex); + break; + case AUTH_CONF_ITEM_PREFIX_DATA: + result = load_private_key_from_data(contents, password, privateKey, ex); + break; + case AUTH_CONF_ITEM_PREFIX_PKCS11: + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "PrivateKey pkcs11 format currently not supported:\n%s", data); + break; + default: + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Specified PrivateKey has wrong format:\n%s", data); + break; + } + ddsrt_free(contents); + + if (result == DDS_SECURITY_VALIDATION_OK) + { + if (check_key_type_and_size(*privateKey, true, ex) != DDS_SECURITY_VALIDATION_OK) + { + result = DDS_SECURITY_VALIDATION_FAILED; + EVP_PKEY_free(*privateKey); + } + } + + return result; +} + +DDS_Security_ValidationResult_t verify_certificate(X509 *identityCert, X509 *identityCa, DDS_Security_SecurityException *ex) +{ + X509_STORE_CTX *ctx; + X509_STORE *store; + assert(identityCert); + assert(identityCa); + + /* Currently only a self signed indentiyCa is supported. Verification of against a certificate chain is not yet supported */ + /* Verification of the certificate expiry using a CRL is not yet supported */ + + if (!(store = X509_STORE_new())) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "X509_STORE_new failed : "); + goto err_store_new; + } + if (X509_STORE_add_cert(store, identityCa) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "X509_STORE_add_cert failed : "); + goto err_add_cert; + } + if (!(ctx = X509_STORE_CTX_new())) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "X509_STORE_CTX_new failed : "); + goto err_ctx_new; + } + if (X509_STORE_CTX_init(ctx, store, identityCert, NULL) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "X509_STORE_CTX_init failed : "); + goto err_ctx_init; + } + if (X509_verify_cert(ctx) != 1) + { + const char *msg = X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)); + char *subject = get_certificate_subject_name(identityCert, NULL); + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Certificate not valid: error: %s; subject: %s", msg, subject ? subject : "[not found]"); + ddsrt_free(subject); + goto err_ctx_init; + } + X509_STORE_CTX_free(ctx); + X509_STORE_free(store); + return DDS_SECURITY_VALIDATION_OK; + +err_ctx_init: + X509_STORE_CTX_free(ctx); +err_ctx_new: +err_add_cert: + X509_STORE_free(store); +err_store_new: + return DDS_SECURITY_VALIDATION_FAILED; +} + +AuthenticationAlgoKind_t get_authentication_algo_kind(X509 *cert) +{ + AuthenticationAlgoKind_t kind = AUTH_ALGO_KIND_UNKNOWN; + assert(cert); + EVP_PKEY *pkey = X509_get_pubkey(cert); + if (pkey) + { + switch (EVP_PKEY_id(pkey)) + { + case EVP_PKEY_RSA: + if (EVP_PKEY_bits(pkey) == 2048) + kind = AUTH_ALGO_KIND_RSA_2048; + break; + case EVP_PKEY_EC: + if (EVP_PKEY_bits(pkey) == 256) + kind = AUTH_ALGO_KIND_EC_PRIME256V1; + break; + } + EVP_PKEY_free(pkey); + } + return kind; +} + +AuthenticationChallenge * generate_challenge(DDS_Security_SecurityException *ex) +{ + AuthenticationChallenge *result = ddsrt_malloc(sizeof(*result)); + if (RAND_bytes(result->value, sizeof(result->value)) < 0) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to generate a 256 bit random number "); + ddsrt_free(result); + return NULL; + } + return result; +} + +DDS_Security_ValidationResult_t get_certificate_contents(X509 *cert, unsigned char **data, uint32_t *size, DDS_Security_SecurityException *ex) +{ + BIO *bio = NULL; + char *ptr; + if ((bio = BIO_new(BIO_s_mem())) == NULL) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "BIO_new_mem_buf failed"); + return DDS_SECURITY_VALIDATION_FAILED; + } + if (!PEM_write_bio_X509(bio, cert)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "PEM_write_bio_X509 failed: "); + BIO_free(bio); + return DDS_SECURITY_VALIDATION_FAILED; + } + + size_t sz = (size_t)BIO_get_mem_data(bio, &ptr); + *data = ddsrt_malloc(sz + 1); + memcpy(*data, ptr, sz); + (*data)[sz] = '\0'; + *size = (uint32_t)sz; + BIO_free(bio); + return DDS_SECURITY_VALIDATION_OK; +} + +static DDS_Security_ValidationResult_t get_rsa_dh_parameters(EVP_PKEY **params, DDS_Security_SecurityException *ex) +{ + DH *dh = NULL; + *params = NULL; + if ((*params = EVP_PKEY_new()) == NULL) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to allocate DH generation parameters: "); + return DDS_SECURITY_VALIDATION_FAILED; + } + if ((dh = DH_get_2048_256()) == NULL) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to allocate DH parameter using DH_get_2048_256: "); + EVP_PKEY_free(*params); + return DDS_SECURITY_VALIDATION_FAILED; + } + if (EVP_PKEY_set1_DH(*params, dh) <= 0) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to set DH generation parameters using EVP_PKEY_set1_DH: "); + EVP_PKEY_free(*params); + DH_free(dh); + return DDS_SECURITY_VALIDATION_FAILED; + } + + DH_free(dh); + return DDS_SECURITY_VALIDATION_OK; +} + +static DDS_Security_ValidationResult_t get_ec_dh_parameters(EVP_PKEY **params, DDS_Security_SecurityException *ex) +{ + EVP_PKEY_CTX *pctx = NULL; + if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to allocate DH parameter context: "); + return DDS_SECURITY_VALIDATION_FAILED; + } + if (EVP_PKEY_paramgen_init(pctx) <= 0) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to initialize DH generation context: "); + EVP_PKEY_CTX_free(pctx); + return DDS_SECURITY_VALIDATION_FAILED; + } + if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1) <= 0) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to set DH generation parameter generation method: "); + EVP_PKEY_CTX_free(pctx); + return DDS_SECURITY_VALIDATION_FAILED; + } + if (EVP_PKEY_paramgen(pctx, params) <= 0) + { + char *msg = get_openssl_error_message(); + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to generate DH parameters: "); + ddsrt_free(msg); + EVP_PKEY_CTX_free(pctx); + return DDS_SECURITY_VALIDATION_FAILED; + } + + EVP_PKEY_CTX_free(pctx); + return DDS_SECURITY_VALIDATION_OK; +} + +DDS_Security_ValidationResult_t generate_dh_keys(EVP_PKEY **dhkey, AuthenticationAlgoKind_t authKind, DDS_Security_SecurityException *ex) +{ + EVP_PKEY *params = NULL; + EVP_PKEY_CTX *kctx = NULL; + *dhkey = NULL; + switch (authKind) + { + case AUTH_ALGO_KIND_RSA_2048: + if (get_rsa_dh_parameters(¶ms, ex) != DDS_SECURITY_VALIDATION_OK) + goto failed; + break; + case AUTH_ALGO_KIND_EC_PRIME256V1: + if (get_ec_dh_parameters(¶ms, ex) != DDS_SECURITY_VALIDATION_OK) + goto failed; + break; + default: + assert(0); + goto failed; + } + + if ((kctx = EVP_PKEY_CTX_new(params, NULL)) == NULL) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to allocate DH generation context: "); + goto failed_params; + } + if (EVP_PKEY_keygen_init(kctx) <= 0) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to initialize DH generation context: "); + goto failed_kctx; + } + if (EVP_PKEY_keygen(kctx, dhkey) <= 0) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to generate DH key pair: "); + goto failed_kctx; + } + EVP_PKEY_CTX_free(kctx); + EVP_PKEY_free(params); + return DDS_SECURITY_VALIDATION_OK; + +failed_kctx: + EVP_PKEY_CTX_free(kctx); +failed_params: + EVP_PKEY_free(params); +failed: + return DDS_SECURITY_VALIDATION_FAILED; +} + +static const BIGNUM *dh_get_public_key(DH *dhkey) +{ +#ifdef AUTH_INCLUDE_DH_ACCESSORS + const BIGNUM *pubkey, *privkey; + DH_get0_key(dhkey, &pubkey, &privkey); + return pubkey; +#else + return dhkey->pub_key; +#endif +} + +static int dh_set_public_key(DH *dhkey, BIGNUM *pubkey) +{ +#ifdef AUTH_INCLUDE_DH_ACCESSORS + return DH_set0_key(dhkey, pubkey, NULL); +#else + dhkey->pub_key = pubkey; +#endif + return 1; +} + +static DDS_Security_ValidationResult_t dh_public_key_to_oct_modp(EVP_PKEY *pkey, unsigned char **buffer, uint32_t *length, DDS_Security_SecurityException *ex) +{ + DH *dhkey; + ASN1_INTEGER *asn1int; + *buffer = NULL; + if (!(dhkey = EVP_PKEY_get1_DH(pkey))) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to get DH key from PKEY: "); + return DDS_SECURITY_VALIDATION_FAILED; + } + if (!(asn1int = BN_to_ASN1_INTEGER(dh_get_public_key(dhkey), NULL))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to convert DH key to ASN1 integer: "); + DH_free(dhkey); + return DDS_SECURITY_VALIDATION_FAILED; + } + *length = (uint32_t)i2d_ASN1_INTEGER(asn1int, buffer); + ASN1_INTEGER_free(asn1int); + DH_free(dhkey); + return DDS_SECURITY_VALIDATION_OK; +} + +static DDS_Security_ValidationResult_t dh_public_key_to_oct_ecdh(EVP_PKEY *pkey, unsigned char **buffer, uint32_t *length, DDS_Security_SecurityException *ex) +{ + EC_KEY *eckey; + const EC_GROUP *group; + const EC_POINT *point; + size_t sz; + + if (!(eckey = EVP_PKEY_get1_EC_KEY(pkey))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to get EC key from PKEY: "); + goto failed_key; + } + if (!(point = EC_KEY_get0_public_key(eckey))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to get public key from ECKEY: "); + goto failed; + } + if (!(group = EC_KEY_get0_group(eckey))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to get group from ECKEY: "); + goto failed; + } + if ((sz = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL)) == 0) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to serialize public EC key: "); + goto failed; + } + *buffer = ddsrt_malloc(sz); + if ((*length = (uint32_t)EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, *buffer, sz, NULL)) == 0) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to serialize public EC key: "); + ddsrt_free(*buffer); + goto failed; + } + EC_KEY_free(eckey); + return DDS_SECURITY_VALIDATION_OK; + +failed: + EC_KEY_free(eckey); +failed_key: + return DDS_SECURITY_VALIDATION_FAILED; +} + +DDS_Security_ValidationResult_t dh_public_key_to_oct(EVP_PKEY *pkey, AuthenticationAlgoKind_t algo, unsigned char **buffer, uint32_t *length, DDS_Security_SecurityException *ex) +{ + assert(pkey); + assert(buffer); + assert(length); + switch (algo) + { + case AUTH_ALGO_KIND_RSA_2048: + return dh_public_key_to_oct_modp(pkey, buffer, length, ex); + case AUTH_ALGO_KIND_EC_PRIME256V1: + return dh_public_key_to_oct_ecdh(pkey, buffer, length, ex); + default: + assert(0); + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Invalid key algorithm specified"); + return DDS_SECURITY_VALIDATION_FAILED; + } +} + +static DDS_Security_ValidationResult_t dh_oct_to_public_key_modp(EVP_PKEY **pkey, const unsigned char *keystr, uint32_t size, DDS_Security_SecurityException *ex) +{ + DH *dhkey; + ASN1_INTEGER *asn1int; + BIGNUM *pubkey; + + if (!(*pkey = EVP_PKEY_new())) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to convert octet sequence to ASN1 integer: "); + goto fail_alloc_pkey; + } + if (!(asn1int = d2i_ASN1_INTEGER(NULL, (const unsigned char **)&keystr, size))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to convert octet sequence to ASN1 integer: "); + goto fail_get_asn1int; + } + if (!(pubkey = ASN1_INTEGER_to_BN(asn1int, NULL))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to convert ASN1 integer to BIGNUM: "); + goto fail_get_pubkey; + } + + dhkey = DH_get_2048_256(); + if (dh_set_public_key(dhkey, pubkey) == 0) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to set DH public key: "); + goto fail_get_pubkey; + } + if (EVP_PKEY_set1_DH(*pkey, dhkey) == 0) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to convert DH to PKEY: "); + DH_free(dhkey); + goto fail_get_pubkey; + } + ASN1_INTEGER_free(asn1int); + DH_free(dhkey); + return DDS_SECURITY_VALIDATION_OK; + +fail_get_pubkey: + ASN1_INTEGER_free(asn1int); +fail_get_asn1int: + EVP_PKEY_free(*pkey); +fail_alloc_pkey: + return DDS_SECURITY_VALIDATION_FAILED; +} + +static DDS_Security_ValidationResult_t dh_oct_to_public_key_ecdh(EVP_PKEY **pkey, const unsigned char *keystr, uint32_t size, DDS_Security_SecurityException *ex) +{ + EC_KEY *eckey; + EC_GROUP *group; + EC_POINT *point; + if (!(group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to allocate EC group: "); + goto fail_alloc_group; + } + if (!(point = EC_POINT_new(group))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to allocate EC point: "); + goto fail_alloc_point; + } + if (EC_POINT_oct2point(group, point, keystr, size, NULL) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to deserialize EC public key to EC point: "); + goto fail_oct2point; + } + if (!(eckey = EC_KEY_new())) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to allocate EC KEY: "); + goto fail_alloc_eckey; + } + if (EC_KEY_set_group(eckey, group) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to set EC group: "); + goto fail_eckey_set; + } + if (EC_KEY_set_public_key(eckey, point) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to set EC public key: "); + goto fail_eckey_set; + } + if (!(*pkey = EVP_PKEY_new())) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to allocate EVP key: "); + goto fail_alloc_pkey; + } + if (EVP_PKEY_set1_EC_KEY(*pkey, eckey) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to set EVP key to EC public key: "); + goto fail_pkey_set_eckey; + } + EC_KEY_free(eckey); + EC_POINT_free(point); + EC_GROUP_free(group); + return DDS_SECURITY_VALIDATION_OK; + +fail_pkey_set_eckey: + EVP_PKEY_free(*pkey); +fail_alloc_pkey: +fail_eckey_set: + EC_KEY_free(eckey); +fail_alloc_eckey: +fail_oct2point: + EC_POINT_free(point); +fail_alloc_point: + EC_GROUP_free(group); +fail_alloc_group: + return DDS_SECURITY_VALIDATION_FAILED; +} + +DDS_Security_ValidationResult_t dh_oct_to_public_key(EVP_PKEY **data, AuthenticationAlgoKind_t algo, const unsigned char *str, uint32_t size, DDS_Security_SecurityException *ex) +{ + assert(data); + assert(str); + switch (algo) + { + case AUTH_ALGO_KIND_RSA_2048: + return dh_oct_to_public_key_modp(data, str, size, ex); + case AUTH_ALGO_KIND_EC_PRIME256V1: + return dh_oct_to_public_key_ecdh(data, str, size, ex); + default: + assert(0); + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Invalid key algorithm specified"); + return DDS_SECURITY_VALIDATION_FAILED; + } +} + +char *string_from_data(const unsigned char *data, uint32_t size) +{ + char *str = NULL; + if (size > 0 && data) + { + str = ddsrt_malloc(size + 1); + memcpy(str, data, size); + str[size] = '\0'; + } + return str; +} + +void free_ca_list_contents(X509Seq *ca_list) +{ + unsigned i; + if (ca_list->buffer != NULL && ca_list->length > 0) + { + for (i = 0; i < ca_list->length; ++i) + X509_free(ca_list->buffer[i]); + ddsrt_free(ca_list->buffer); + } + ca_list->buffer = NULL; + ca_list->length = 0; +} + +DDS_Security_ValidationResult_t get_trusted_ca_list(const char *trusted_ca_dir, X509Seq *ca_list, DDS_Security_SecurityException *ex) +{ + ddsrt_dir_handle_t d_descr; + struct ddsrt_dirent d_entry; + struct ddsrt_stat status; + X509 *ca_buf[MAX_TRUSTED_CA]; + unsigned ca_cnt = 0; + char *tca_dir_norm = ddsrt_file_normalize(trusted_ca_dir); + dds_return_t ret = ddsrt_opendir(tca_dir_norm, &d_descr); + ddsrt_free(tca_dir_norm); + if (ret != DDS_RETCODE_OK) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_TRUSTED_CA_DIR_CODE, 0, DDS_SECURITY_ERR_INVALID_TRUSTED_CA_DIR_MESSAGE); + return DDS_SECURITY_VALIDATION_FAILED; + } + + char *fpath, *fname; + X509 *ca; + bool failed = false; + while (!failed && ddsrt_readdir(d_descr, &d_entry) == DDS_RETCODE_OK) + { + ddsrt_asprintf(&fpath, "%s%s%s", trusted_ca_dir, ddsrt_file_sep(), d_entry.d_name); + if (ddsrt_stat(fpath, &status) == DDS_RETCODE_OK + && strcmp(d_entry.d_name, ".") != 0 && strcmp(d_entry.d_name, "..") != 0 + && (fname = ddsrt_file_normalize(fpath)) != NULL) + { + if (ca_cnt >= MAX_TRUSTED_CA) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_TRUSTED_CA_DIR_MAX_EXCEEDED_CODE, 0, DDS_SECURITY_ERR_TRUSTED_CA_DIR_MAX_EXCEEDED_MESSAGE, MAX_TRUSTED_CA); + failed = true; + } + else if (load_X509_certificate_from_file(fname, &ca, ex) == DDS_SECURITY_VALIDATION_OK) + ca_buf[ca_cnt++] = ca; + else + DDS_Security_Exception_reset(ex); + ddsrt_free(fname); + } + ddsrt_free(fpath); + } + ddsrt_closedir(d_descr); + + if (!failed) + { + free_ca_list_contents(ca_list); + if (ca_cnt > 0) + { + ca_list->buffer = ddsrt_malloc(ca_cnt * sizeof(X509 *)); + for (unsigned i = 0; i < ca_cnt; ++i) + ca_list->buffer[i] = ca_buf[i]; + } + ca_list->length = ca_cnt; + } + return failed ? DDS_SECURITY_VALIDATION_FAILED : DDS_SECURITY_VALIDATION_OK; +} + +DDS_Security_ValidationResult_t create_validate_asymmetrical_signature(bool create, EVP_PKEY *pkey, const unsigned char *data, const size_t dataLen, + unsigned char **signature, size_t *signatureLen, DDS_Security_SecurityException *ex) +{ + EVP_MD_CTX *mdctx = NULL; + EVP_PKEY_CTX *kctx = NULL; + if (!(mdctx = EVP_MD_CTX_create())) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to create digest context: "); + return DDS_SECURITY_VALIDATION_FAILED; + } + if ((create ? EVP_DigestSignInit(mdctx, &kctx, EVP_sha256(), NULL, pkey) : EVP_DigestVerifyInit(mdctx, &kctx, EVP_sha256(), NULL, pkey)) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to initialize digest context: "); + goto err; + } + if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA) + { + if (EVP_PKEY_CTX_set_rsa_padding(kctx, RSA_PKCS1_PSS_PADDING) < 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to initialize digest context: "); + goto err; + } + } + if ((create ? EVP_DigestSignUpdate(mdctx, data, dataLen) : EVP_DigestVerifyUpdate(mdctx, data, dataLen)) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to update digest context: "); + goto err; + } + if (create) + { + if (EVP_DigestSignFinal(mdctx, NULL, signatureLen) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to finalize digest context: "); + goto err; + } + *signature = ddsrt_malloc(sizeof(unsigned char) * (*signatureLen)); + } + if ((create ? EVP_DigestSignFinal(mdctx, *signature, signatureLen) : EVP_DigestVerifyFinal(mdctx, *signature, *signatureLen)) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Failed to finalize digest context: "); + if (create) + ddsrt_free(*signature); + goto err; + } + EVP_MD_CTX_destroy(mdctx); + return DDS_SECURITY_VALIDATION_OK; + +err: + EVP_MD_CTX_destroy(mdctx); + return DDS_SECURITY_VALIDATION_FAILED; +} diff --git a/src/security/builtin_plugins/authentication/src/auth_utils.h b/src/security/builtin_plugins/authentication/src/auth_utils.h new file mode 100644 index 0000000..31eb5d9 --- /dev/null +++ b/src/security/builtin_plugins/authentication/src/auth_utils.h @@ -0,0 +1,113 @@ +/* + * 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 AUTH_UTILS_H +#define AUTH_UTILS_H + +#ifdef _WIN32 +/* supposedly WinSock2 must be included before openssl 1.0.2 headers otherwise winsock will be used */ +#include +#endif +#include +#include + +#include "dds/security/dds_security_api.h" +#include "dds/ddsrt/time.h" + +#define DDS_AUTH_PLUGIN_CONTEXT "Authentication" + +typedef enum { + AUTH_ALGO_KIND_UNKNOWN, + AUTH_ALGO_KIND_RSA_2048, + AUTH_ALGO_KIND_EC_PRIME256V1 +} AuthenticationAlgoKind_t; + +typedef enum { + AUTH_CONF_ITEM_PREFIX_UNKNOWN, + AUTH_CONF_ITEM_PREFIX_FILE, + AUTH_CONF_ITEM_PREFIX_DATA, + AUTH_CONF_ITEM_PREFIX_PKCS11 +} AuthConfItemPrefix_t; + + +typedef struct AuthenticationChallenge { + unsigned char value[DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE]; +} AuthenticationChallenge; + +typedef struct { + uint32_t length; + X509 **buffer; +} X509Seq; + +typedef unsigned char HashValue_t[SHA256_DIGEST_LENGTH]; + +/* Return a string that contains an openssl error description + * When a openssl function returns an error this function can be + * used to retrieve a descriptive error string. + * Note that the returned string should be freed. + */ +char * get_openssl_error_message(void); + +/* Return the subject name of contained in a X509 certificate + * Note that the returned string should be freed. + */ +char * get_certificate_subject_name(X509 *cert, DDS_Security_SecurityException *ex); + +/* Return the expiry date of contained in a X509 certificate */ +dds_time_t get_certificate_expiry(const X509 *cert); + +/* Return the subject name of a X509 certificate DER + * encoded. The DER encoded subject name is returned in + * the provided buffer. The length of the allocated + * buffer is returned + * + * return length of allocated buffer or -1 on error + */ +DDS_Security_ValidationResult_t get_subject_name_DER_encoded(const X509 *cert, unsigned char **buffer, size_t *size, DDS_Security_SecurityException *ex); + +/* Load a X509 certificate for the provided data (PEM format) */ +DDS_Security_ValidationResult_t load_X509_certificate_from_data(const char *data, int len, X509 **x509Cert, DDS_Security_SecurityException *ex); + +/* Load a X509 certificate for the provided data (certificate uri) */ +DDS_Security_ValidationResult_t load_X509_certificate(const char *data, X509 **x509Cert, DDS_Security_SecurityException *ex); + +/* Load a X509 certificate for the provided file */ +DDS_Security_ValidationResult_t load_X509_certificate_from_file(const char *filename, X509 **x509Cert, DDS_Security_SecurityException *ex); + +/* Load a Private Key for the provided data (private key uri) */ +DDS_Security_ValidationResult_t load_X509_private_key(const char *data, const char *password, EVP_PKEY **privateKey, DDS_Security_SecurityException *ex); + +/* Validate an identity certificate against the identityCA + * The provided identity certificate is checked if it is + * signed by the identity corresponding to the identityCA. + * + * Note: Currently only a self signed CA is supported + * The function does not yet check a CLR or ocsp + * for expiry of identity certificate. + */ +DDS_Security_ValidationResult_t verify_certificate(X509 *identityCert, X509 *identityCa, DDS_Security_SecurityException *ex); + +DDS_Security_ValidationResult_t check_certificate_expiry(const X509 *cert, DDS_Security_SecurityException *ex); +AuthenticationAlgoKind_t get_authentication_algo_kind(X509 *cert); +AuthenticationChallenge *generate_challenge(DDS_Security_SecurityException *ex); +DDS_Security_ValidationResult_t get_certificate_contents(X509 *cert, unsigned char **data, uint32_t *size, DDS_Security_SecurityException *ex); +DDS_Security_ValidationResult_t generate_dh_keys(EVP_PKEY **dhkey, AuthenticationAlgoKind_t authKind, DDS_Security_SecurityException *ex); +DDS_Security_ValidationResult_t dh_public_key_to_oct(EVP_PKEY *pkey, AuthenticationAlgoKind_t algo, unsigned char **buffer, uint32_t *length, DDS_Security_SecurityException *ex); +DDS_Security_ValidationResult_t dh_oct_to_public_key(EVP_PKEY **data, AuthenticationAlgoKind_t algo, const unsigned char *str, uint32_t size, DDS_Security_SecurityException *ex); +AuthConfItemPrefix_t get_conf_item_type(const char *str, char **data); +void free_ca_list_contents(X509Seq *ca_list); +DDS_Security_ValidationResult_t get_trusted_ca_list(const char* trusted_ca_dir, X509Seq *ca_list, DDS_Security_SecurityException *ex); +char * string_from_data(const unsigned char *data, uint32_t size); +DDS_Security_ValidationResult_t create_validate_asymmetrical_signature(bool create, EVP_PKEY *pkey, const unsigned char *data, const size_t dataLen, + unsigned char **signature, size_t *signatureLen, DDS_Security_SecurityException *ex); + +#endif /* AUTH_UTILS_H */ diff --git a/src/security/builtin_plugins/authentication/src/authentication.c b/src/security/builtin_plugins/authentication/src/authentication.c new file mode 100644 index 0000000..20f2c2c --- /dev/null +++ b/src/security/builtin_plugins/authentication/src/authentication.c @@ -0,0 +1,2277 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/hopscotch.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/dds_security_api_types.h" +#include "dds/security/core/dds_security_timed_cb.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/openssl_support.h" +#include "auth_utils.h" +#include "authentication.h" + +#ifndef EVP_PKEY_id +#define EVP_PKEY_id(k) ((k)->type) +#endif + +#define HANDSHAKE_SIGNATURE_CONTENT_SIZE 6 +#define ADJUSTED_GUID_PREFIX_FLAG 0x80 + +static const char *AUTH_PROTOCOL_CLASS = "DDS:Auth:PKI-DH"; +static const unsigned AUTH_PROTOCOL_VERSION_MAJOR = 1; +static const unsigned AUTH_PROTOCOL_VERSION_MINOR = 0; + +static const char *AUTH_REQUEST_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+AuthReq"; +static const char *AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME = "future_challenge"; + +static const char *PROPERTY_IDENTITY_CA = "dds.sec.auth.identity_ca"; +static const char *PROPERTY_PRIVATE_KEY = "dds.sec.auth.private_key"; +static const char *PROPERTY_PASSWORD = "dds.sec.auth.password"; +static const char *PROPERTY_IDENTITY_CERT = "dds.sec.auth.identity_certificate"; +static const char *PROPERTY_TRUSTED_CA_DIR = "dds.sec.auth.trusted_ca_dir"; + +static const char *PROPERTY_CERT_SUBJECT_NAME = "dds.cert.sn"; +static const char *PROPERTY_CERT_ALGORITHM = "dds.cert.algo"; +static const char *PROPERTY_CA_SUBJECT_NAME = "dds.ca.sn"; +static const char *PROPERTY_CA_ALGORITHM = "dds.ca.aglo"; + +static const char *AUTH_HANDSHAKE_REQUEST_TOKEN_ID = "DDS:Auth:PKI-DH:1.0+Req"; +static const char *AUTH_HANDSHAKE_REPLY_TOKEN_ID = "DDS:Auth:PKI-DH:1.0+Reply"; + +static const char *AUTH_HANDSHAKE_FINAL_TOKEN_ID = "DDS:Auth:PKI-DH:1.0+Final"; + +static const char *AUTH_DSIG_ALGO_RSA_2048_SHA256_IDENT = "RSASSA-PSS-SHA256"; +static const char *AUTH_DSIG_ALGO_ECDSA_SHA256_IDENT = "ECDSA-SHA256"; +static const char *AUTH_KAGREE_ALGO_RSA_2048_SHA256_IDENT = "DH+MODP-2048-256"; +static const char *AUTH_KAGREE_ALGO_ECDH_PRIME256V1_IDENT = "ECDH+prime256v1-CEUM"; + +static const char *ACCESS_PERMISSIONS_CREDENTIAL_TOKEN_ID = "DDS:Access:PermissionsCredential"; +static const char *ACCESS_PROPERTY_PERMISSION_DOCUMENT = "dds.perm.cert"; + +typedef enum +{ + SECURITY_OBJECT_KIND_UNKNOWN, + SECURITY_OBJECT_KIND_LOCAL_IDENTITY, + SECURITY_OBJECT_KIND_REMOTE_IDENTITY, + SECURITY_OBJECT_KIND_IDENTITY_RELATION, + SECURITY_OBJECT_KIND_HANDSHAKE +} SecurityObjectKind_t; + +typedef enum +{ + CREATEDREQUEST, + CREATEDREPLY +} CreatedHandshakeStep_t; + +typedef struct SecurityObject SecurityObject; +typedef void (*SecurityObjectDestructor)(SecurityObject *obj); + +struct SecurityObject +{ + int64_t handle; + SecurityObjectKind_t kind; + SecurityObjectDestructor destructor; +}; + +#ifndef NDEBUG +#define CHECK_OBJECT_KIND(o, k) assert(security_object_valid((SecurityObject *)(o), k)) +#else +#define CHECK_OBJECT_KIND(o, k) +#endif + +#define SECURITY_OBJECT(o) ((SecurityObject *)(o)) +#define SECURITY_OBJECT_HANDLE(o) (SECURITY_OBJECT(o)->handle) +#define IDENTITY_HANDLE(o) ((DDS_Security_IdentityHandle)SECURITY_OBJECT_HANDLE(o)) +#define HANDSHAKE_HANDLE(o) ((DDS_Security_HandshakeHandle)SECURITY_OBJECT_HANDLE(o)) + +#define SECURITY_OBJECT_VALID(o, k) security_object_valid((SecurityObject *)(o), k) + +typedef struct LocalIdentityInfo +{ + SecurityObject _parent; + DDS_Security_DomainId domainId; + DDS_Security_GUID_t candidateGUID; + DDS_Security_GUID_t adjustedGUID; + X509 *identityCert; + X509 *identityCA; + EVP_PKEY *privateKey; + DDS_Security_OctetSeq pdata; + AuthenticationAlgoKind_t dsignAlgoKind; + AuthenticationAlgoKind_t kagreeAlgoKind; + char *permissionsDocument; +} 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; + IdentityRelation *relation; + HashValue_t hash_c1; + HashValue_t hash_c2; + EVP_PKEY *ldh; + EVP_PKEY *rdh; + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + CreatedHandshakeStep_t created_in; +} HandshakeInfo; + +typedef struct dds_security_authentication_impl +{ + dds_security_authentication base; + ddsrt_mutex_t lock; + struct ddsrt_hh *objectHash; + struct ddsrt_hh *remoteGuidHash; + struct dds_security_timed_cb_data *timed_callbacks; + struct dds_security_timed_dispatcher_t *dispatcher; + X509Seq trustedCAList; + bool include_optional; +} dds_security_authentication_impl; + +/* data type for timer dispatcher */ +typedef struct +{ + dds_security_authentication_impl *auth; + DDS_Security_IdentityHandle hdl; +} validity_cb_info; + +static bool security_object_valid(SecurityObject *obj, SecurityObjectKind_t kind) +{ + if (!obj || obj->kind != kind) + 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; +} + +static uint32_t security_object_hash(const void *obj) +{ + const SecurityObject *object = obj; + const uint64_t c = UINT64_C (16292676669999574021); + const uint32_t x = (uint32_t)object->handle; + return (uint32_t)((x * c) >> 32); +} + +static int security_object_equal(const void *ha, const void *hb) +{ + const SecurityObject *la = ha; + const SecurityObject *lb = hb; + return la->handle == lb->handle; +} + +static SecurityObject *security_object_find(const struct ddsrt_hh *hh, int64_t handle) +{ + struct SecurityObject template; + template.handle = handle; + return (SecurityObject *)ddsrt_hh_lookup(hh, &template); +} + +static void security_object_init(SecurityObject *obj, SecurityObjectKind_t kind, SecurityObjectDestructor destructor) +{ + assert(obj); + obj->kind = kind; + obj->handle = (int64_t)(ddsrt_address)obj; + obj->destructor = destructor; +} + +static void security_object_deinit(SecurityObject *obj) +{ + 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 local_identity_info_free(SecurityObject *obj) +{ + LocalIdentityInfo *identity = (LocalIdentityInfo *)obj; + CHECK_OBJECT_KIND(obj, SECURITY_OBJECT_KIND_LOCAL_IDENTITY); + if (identity) + { + if (identity->identityCert) + X509_free(identity->identityCert); + if (identity->identityCA) + X509_free(identity->identityCA); + if (identity->privateKey) + EVP_PKEY_free(identity->privateKey); + ddsrt_free(identity->pdata._buffer); + ddsrt_free(identity->permissionsDocument); + security_object_deinit((SecurityObject *)identity); + ddsrt_free(identity); + } +} + +static LocalIdentityInfo *local_identity_info_new(DDS_Security_DomainId domainId, X509 *identityCert, X509 *identityCa, EVP_PKEY *privateKey, const DDS_Security_GUID_t *candidate_participant_guid, const DDS_Security_GUID_t *adjusted_participant_guid) +{ + LocalIdentityInfo *identity = NULL; + assert(identityCert); + assert(identityCa); + assert(privateKey); + assert(candidate_participant_guid); + assert(adjusted_participant_guid); + assert(sizeof(DDS_Security_IdentityHandle) == 8); + + identity = ddsrt_malloc(sizeof(*identity)); + memset(identity, 0, sizeof(*identity)); + + security_object_init((SecurityObject *)identity, SECURITY_OBJECT_KIND_LOCAL_IDENTITY, local_identity_info_free); + + identity->domainId = domainId; + identity->identityCert = identityCert; + identity->identityCA = identityCa; + identity->privateKey = privateKey; + identity->permissionsDocument = NULL; + identity->dsignAlgoKind = get_authentication_algo_kind(identityCert); + identity->kagreeAlgoKind = AUTH_ALGO_KIND_EC_PRIME256V1; + + memcpy(&identity->candidateGUID, candidate_participant_guid, sizeof(DDS_Security_GUID_t)); + memcpy(&identity->adjustedGUID, adjusted_participant_guid, sizeof(DDS_Security_GUID_t)); + + return identity; +} + +static uint32_t remote_guid_hash(const void *obj) +{ + const RemoteIdentityInfo *identity = obj; + uint32_t tmp[4]; + memcpy(tmp, &identity->guid, sizeof(tmp)); + return (tmp[0] ^ tmp[1] ^ tmp[2] ^ tmp[3]); +} + +static int remote_guid_equal(const void *ha, const void *hb) +{ + const RemoteIdentityInfo *la = ha; + const RemoteIdentityInfo *lb = hb; + return memcmp(&la->guid, &lb->guid, sizeof(la->guid)) == 0; +} + +static RemoteIdentityInfo *find_remote_identity_by_guid(const struct ddsrt_hh *hh, const DDS_Security_GUID_t *guid) +{ + struct RemoteIdentityInfo template; + memcpy(&template.guid, guid, sizeof(*guid)); + return (RemoteIdentityInfo *)ddsrt_hh_lookup(hh, &template); +} + +static void remote_identity_info_free(SecurityObject *obj) +{ + RemoteIdentityInfo *identity = (RemoteIdentityInfo *)obj; + CHECK_OBJECT_KIND(obj, SECURITY_OBJECT_KIND_REMOTE_IDENTITY); + if (identity) + { + if (identity->identityCert) + X509_free(identity->identityCert); + 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 RemoteIdentityInfo *remote_identity_info_new(const DDS_Security_GUID_t *guid, const DDS_Security_IdentityToken *remote_identity_token) +{ + assert(guid); + assert(remote_identity_token); + + RemoteIdentityInfo *identity = ddsrt_malloc(sizeof(*identity)); + memset(identity, 0, sizeof(*identity)); + security_object_init((SecurityObject *)identity, SECURITY_OBJECT_KIND_REMOTE_IDENTITY, remote_identity_info_free); + memcpy(&identity->guid, guid, sizeof(DDS_Security_GUID_t)); + 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 identity_relation_free(SecurityObject *obj) +{ + IdentityRelation *relation = (IdentityRelation *)obj; + CHECK_OBJECT_KIND(obj, SECURITY_OBJECT_KIND_IDENTITY_RELATION); + if (relation) + { + ddsrt_free(relation->lchallenge); + ddsrt_free(relation->rchallenge); + security_object_deinit((SecurityObject *)relation); + ddsrt_free(relation); + } +} + +/* 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. + * The lchallenge is the challenge associated with the local identity and + * may be set when a future challenge is communicated with the auth_request_message_token. + * The rchallenge is the challenge received from the remote identity it may be set when + * an auth_request_message_token is received from the remote identity, + */ +static IdentityRelation *identity_relation_new(LocalIdentityInfo *localIdentity, RemoteIdentityInfo *remoteIdentity, AuthenticationChallenge *lchallenge, AuthenticationChallenge *rchallenge) +{ + IdentityRelation *relation; + assert(localIdentity); + assert(remoteIdentity); + relation = ddsrt_malloc(sizeof(*relation)); + memset(relation, 0, sizeof(*relation)); + security_object_init((SecurityObject *)relation, SECURITY_OBJECT_KIND_IDENTITY_RELATION, identity_relation_free); + relation->_parent.handle = SECURITY_OBJECT_HANDLE(localIdentity); + relation->localIdentity = localIdentity; + relation->remoteIdentity = remoteIdentity; + relation->lchallenge = lchallenge; + relation->rchallenge = rchallenge; + return relation; +} + +static void handshake_info_free(SecurityObject *obj) +{ + CHECK_OBJECT_KIND(obj, SECURITY_OBJECT_KIND_HANDSHAKE); + HandshakeInfo *handshake = (HandshakeInfo *)obj; + if (handshake) + { + if (handshake->ldh) + EVP_PKEY_free(handshake->ldh); + if (handshake->rdh) + EVP_PKEY_free(handshake->rdh); + if (handshake->shared_secret_handle_impl) + { + ddsrt_free(handshake->shared_secret_handle_impl->shared_secret); + ddsrt_free(handshake->shared_secret_handle_impl); + } + security_object_deinit((SecurityObject *)handshake); + ddsrt_free(handshake); + } +} + +static HandshakeInfo *handshake_info_new(LocalIdentityInfo *localIdentity, RemoteIdentityInfo *remoteIdentity, IdentityRelation *relation) +{ + assert(localIdentity); + assert(remoteIdentity); + DDSRT_UNUSED_ARG(localIdentity); + DDSRT_UNUSED_ARG(remoteIdentity); + HandshakeInfo *handshake = ddsrt_malloc(sizeof(*handshake)); + memset(handshake, 0, sizeof(*handshake)); + security_object_init((SecurityObject *)handshake, SECURITY_OBJECT_KIND_HANDSHAKE, handshake_info_free); + handshake->relation = relation; + handshake->shared_secret_handle_impl = NULL; + return handshake; +} + +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; + for (obj = ddsrt_hh_iter_first(auth->objectHash, &it); obj; obj = ddsrt_hh_iter_next(&it)) + { + if (obj->kind == SECURITY_OBJECT_KIND_HANDSHAKE) + { + IdentityRelation *relation = ((HandshakeInfo *)obj)->relation; + assert(relation); + if (SECURITY_OBJECT_HANDLE(relation->localIdentity) == localId && SECURITY_OBJECT_HANDLE(relation->remoteIdentity) == remoteId) + return (HandshakeInfo *)obj; + } + } + return NULL; +} + +static char * get_authentication_class_id(void) +{ + size_t sz = strlen(AUTH_PROTOCOL_CLASS) + 5; + char *classId = ddsrt_malloc(sz); + snprintf(classId, sz, "%s:%1u.%1u", AUTH_PROTOCOL_CLASS, AUTH_PROTOCOL_VERSION_MAJOR, AUTH_PROTOCOL_VERSION_MINOR); + return classId; +} + +static const char *get_authentication_algo(AuthenticationAlgoKind_t kind) +{ + switch (kind) + { + case AUTH_ALGO_KIND_RSA_2048: + return "RSA-2048"; + case AUTH_ALGO_KIND_EC_PRIME256V1: + return "EC-prime256v1"; + default: + assert(0); + return ""; + } +} + +static const char *get_dsign_algo(AuthenticationAlgoKind_t kind) +{ + switch (kind) + { + case AUTH_ALGO_KIND_RSA_2048: + return AUTH_DSIG_ALGO_RSA_2048_SHA256_IDENT; + case AUTH_ALGO_KIND_EC_PRIME256V1: + return AUTH_DSIG_ALGO_ECDSA_SHA256_IDENT; + default: + assert(0); + return ""; + } +} + +static const char *get_kagree_algo(AuthenticationAlgoKind_t kind) +{ + switch (kind) + { + case AUTH_ALGO_KIND_RSA_2048: + return AUTH_KAGREE_ALGO_RSA_2048_SHA256_IDENT; + case AUTH_ALGO_KIND_EC_PRIME256V1: + return AUTH_KAGREE_ALGO_ECDH_PRIME256V1_IDENT; + default: + assert(0); + return ""; + } +} + +static bool str_octseq_equal (const char *str, const DDS_Security_OctetSeq *binstr) +{ + size_t i; + for (i = 0; str[i] && i < binstr->_length; i++) + if ((unsigned char) str[i] != binstr->_buffer[i]) + return false; + /* allow zero-termination in binstr, but disallow anything other than a single \0 */ + return (str[i] == 0 && + (i == binstr->_length || + (i+1 == binstr->_length && binstr->_buffer[i] == 0))); +} + +static AuthenticationAlgoKind_t get_dsign_algo_from_octseq(const DDS_Security_OctetSeq *name) +{ + if (str_octseq_equal(AUTH_DSIG_ALGO_RSA_2048_SHA256_IDENT, name)) + return AUTH_ALGO_KIND_RSA_2048; + if (str_octseq_equal(AUTH_DSIG_ALGO_ECDSA_SHA256_IDENT, name)) + return AUTH_ALGO_KIND_EC_PRIME256V1; + return AUTH_ALGO_KIND_UNKNOWN; +} + +static AuthenticationAlgoKind_t get_kagree_algo_from_octseq(const DDS_Security_OctetSeq *name) +{ + if (str_octseq_equal(AUTH_KAGREE_ALGO_RSA_2048_SHA256_IDENT, name)) + return AUTH_ALGO_KIND_RSA_2048; + if (str_octseq_equal(AUTH_KAGREE_ALGO_ECDH_PRIME256V1_IDENT, name)) + return AUTH_ALGO_KIND_EC_PRIME256V1; + return AUTH_ALGO_KIND_UNKNOWN; +} + +static void free_binary_properties(DDS_Security_BinaryProperty_t *seq, uint32_t length) +{ + assert(seq); + for (uint32_t i = 0; i < length; i++) + { + ddsrt_free(seq[i].name); + ddsrt_free(seq[i].value._buffer); + } + ddsrt_free(seq); +} + +static void get_hash_binary_property_seq(const DDS_Security_BinaryPropertySeq *seq, unsigned char hash[SHA256_DIGEST_LENGTH]) +{ + unsigned char *buffer; + size_t size; + DDS_Security_Serializer serializer = DDS_Security_Serializer_new(4096, 4096); + DDS_Security_Serialize_BinaryPropertySeq(serializer, seq); + DDS_Security_Serializer_buffer(serializer, &buffer, &size); + SHA256(buffer, size, hash); + ddsrt_free(buffer); + DDS_Security_Serializer_free(serializer); +} + +static DDS_Security_ValidationResult_t create_validate_signature_impl(bool create, EVP_PKEY *pkey, const DDS_Security_BinaryProperty_t **bprops, + const uint32_t n_bprops, unsigned char **signature, size_t *signature_len, DDS_Security_SecurityException *ex) +{ + DDS_Security_ValidationResult_t result; + unsigned char *buffer; + size_t size; + DDS_Security_Serializer serializer = DDS_Security_Serializer_new(4096, 4096); + DDS_Security_Serialize_BinaryPropertyArray(serializer, bprops, n_bprops); + DDS_Security_Serializer_buffer(serializer, &buffer, &size); + result = create_validate_asymmetrical_signature(create, pkey, buffer, size, signature, signature_len, ex); + ddsrt_free(buffer); + DDS_Security_Serializer_free(serializer); + return result; +} + +static DDS_Security_ValidationResult_t create_signature(EVP_PKEY *pkey, const DDS_Security_BinaryProperty_t **bprops, + const uint32_t n_bprops, unsigned char **signature, size_t *signature_len, DDS_Security_SecurityException *ex) +{ + return create_validate_signature_impl(true, pkey, bprops, n_bprops, signature, signature_len, ex); +} + +static DDS_Security_ValidationResult_t validate_signature(EVP_PKEY *pkey, const DDS_Security_BinaryProperty_t **bprops, + const uint32_t n_bprops, const unsigned char *signature, size_t signature_len, DDS_Security_SecurityException *ex) +{ + unsigned char *s = (unsigned char *)signature; + size_t s_len = signature_len; + return create_validate_signature_impl(false, pkey, bprops, n_bprops, &s, &s_len, ex); +} + +static DDS_Security_ValidationResult_t compute_hash_value(HashValue_t value, const DDS_Security_BinaryProperty_t **properties, + const uint32_t properties_length, DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(ex); + unsigned char *buffer; + size_t size; + DDS_Security_Serializer serializer = DDS_Security_Serializer_new(4096, 4096); + DDS_Security_Serialize_BinaryPropertyArray(serializer, properties, properties_length); + DDS_Security_Serializer_buffer(serializer, &buffer, &size); + SHA256(buffer, size, value); + ddsrt_free(buffer); + DDS_Security_Serializer_free(serializer); + return DDS_SECURITY_VALIDATION_OK; +} + +static DDS_Security_BinaryProperty_t *hash_value_to_binary_property(const char *name, HashValue_t hash) +{ + DDS_Security_BinaryProperty_t *bp = DDS_Security_BinaryProperty_alloc(); + DDS_Security_BinaryProperty_set_by_value(bp, name, hash, sizeof(HashValue_t)); + return bp; +} + +static void validity_callback(struct dds_security_timed_dispatcher_t *d, dds_security_timed_cb_kind kind, void *listener, void *arg) +{ + DDSRT_UNUSED_ARG(d); + assert(d); + assert(arg); + validity_cb_info *info = arg; + if (kind == DDS_SECURITY_TIMED_CB_KIND_TIMEOUT) + { + assert(listener); + dds_security_authentication_listener *auth_listener = (dds_security_authentication_listener *)listener; + if (auth_listener->on_revoke_identity) + auth_listener->on_revoke_identity((dds_security_authentication *)info->auth, info->hdl); + } + ddsrt_free(arg); +} + +static void add_validity_end_trigger(dds_security_authentication_impl *auth, const DDS_Security_IdentityHandle identity_handle, dds_time_t end) +{ + validity_cb_info *arg = ddsrt_malloc(sizeof(validity_cb_info)); + arg->auth = auth; + arg->hdl = identity_handle; + dds_security_timed_dispatcher_add(auth->timed_callbacks, auth->dispatcher, validity_callback, end, (void *)arg); +} + +static DDS_Security_ValidationResult_t get_adjusted_participant_guid(X509 *cert, const DDS_Security_GUID_t *candidate, DDS_Security_GUID_t *adjusted, DDS_Security_SecurityException *ex) +{ + unsigned char high[SHA256_DIGEST_LENGTH], low[SHA256_DIGEST_LENGTH]; + unsigned char *subject = NULL; + size_t size = 0; + + assert(cert); + assert(candidate); + assert(adjusted); + + if (get_subject_name_DER_encoded(cert, &subject, &size, ex) != DDS_SECURITY_VALIDATION_OK) + return DDS_SECURITY_VALIDATION_FAILED; + + DDS_Security_octet hb = ADJUSTED_GUID_PREFIX_FLAG; + SHA256(subject, size, high); + SHA256(&candidate->prefix[0], sizeof(DDS_Security_GuidPrefix_t), low); + adjusted->entityId = candidate->entityId; + for (int i = 0; i < 6; i++) + { + adjusted->prefix[i] = hb | high[i] >> 1; + hb = (DDS_Security_octet)(high[i] << 7); + } + for (int i = 0; i < 6; i++) + adjusted->prefix[i + 6] = low[i]; + ddsrt_free(subject); + return DDS_SECURITY_VALIDATION_OK; +} +#undef ADJUSTED_GUID_PREFIX_FLAG + +DDS_Security_ValidationResult_t validate_local_identity(dds_security_authentication *instance, DDS_Security_IdentityHandle *local_identity_handle, + DDS_Security_GUID_t *adjusted_participant_guid, const DDS_Security_DomainId domain_id, const DDS_Security_Qos *participant_qos, + const DDS_Security_GUID_t *candidate_participant_guid, DDS_Security_SecurityException *ex) +{ + dds_security_authentication_impl *implementation = (dds_security_authentication_impl *)instance; + LocalIdentityInfo *identity; + char *identityCertPEM, *identityCaPEM, *privateKeyPEM, *password, *trusted_ca_dir; + X509 *identityCert, *identityCA; + EVP_PKEY *privateKey; + dds_time_t certExpiry = DDS_TIME_INVALID; + + if (!instance || !local_identity_handle || !adjusted_participant_guid || !participant_qos || !candidate_participant_guid) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "validate_local_identity: Invalid parameter provided"); + goto err_bad_param; + } + + if (!(identityCertPEM = DDS_Security_Property_get_value(&participant_qos->property.value, PROPERTY_IDENTITY_CERT))) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "validate_local_identity: missing property '%s'", PROPERTY_IDENTITY_CERT); + goto err_no_identity_cert; + } + + if (!(identityCaPEM = DDS_Security_Property_get_value(&participant_qos->property.value, PROPERTY_IDENTITY_CA))) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "validate_local_identity: missing property '%s'", PROPERTY_IDENTITY_CA); + goto err_no_identity_ca; + } + + if (!(privateKeyPEM = DDS_Security_Property_get_value(&participant_qos->property.value, PROPERTY_PRIVATE_KEY))) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "validate_local_identity: missing property '%s'", PROPERTY_PRIVATE_KEY); + goto err_no_private_key; + } + + password = DDS_Security_Property_get_value(&participant_qos->property.value, PROPERTY_PASSWORD); + + trusted_ca_dir = DDS_Security_Property_get_value(&participant_qos->property.value, PROPERTY_TRUSTED_CA_DIR); + if (trusted_ca_dir && strlen(trusted_ca_dir) > 0) + { + if (get_trusted_ca_list(trusted_ca_dir, &(implementation->trustedCAList), ex) != DDS_SECURITY_VALIDATION_OK) + goto err_inv_trusted_ca_dir; + } + + if (load_X509_certificate(identityCaPEM, &identityCA, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_inv_identity_ca; + + /* check for CA if listed in trusted CA files */ + if (implementation->trustedCAList.length > 0) + { + const EVP_MD *digest = EVP_get_digestbyname("sha1"); + uint32_t size; + unsigned char hash_buffer[20], hash_buffer_trusted[20]; + DDS_Security_ValidationResult_t result = DDS_SECURITY_VALIDATION_FAILED; + + X509_digest(identityCA, digest, hash_buffer, &size); + for (unsigned i = 0; i < implementation->trustedCAList.length; ++i) + { + X509_digest(implementation->trustedCAList.buffer[i], digest, hash_buffer_trusted, &size); + if (memcmp(hash_buffer_trusted, hash_buffer, 20) == 0) + { + result = DDS_SECURITY_VALIDATION_OK; + break; + } + } + if (result != DDS_SECURITY_VALIDATION_OK) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CA_NOT_TRUSTED_CODE, DDS_SECURITY_VALIDATION_FAILED, DDS_SECURITY_ERR_CA_NOT_TRUSTED_MESSAGE); + goto err_identity_ca_not_trusted; + } + } + if (load_X509_certificate(identityCertPEM, &identityCert, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_inv_identity_cert; + + if (load_X509_private_key(privateKeyPEM, password, &privateKey, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_inv_private_key; + + if (verify_certificate(identityCert, identityCA, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_verification_failed; + + if ((certExpiry = get_certificate_expiry(identityCert)) == DDS_TIME_INVALID) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Expiry date of the certificate is invalid"); + goto err_verification_failed; + } + + if (get_adjusted_participant_guid(identityCert, candidate_participant_guid, adjusted_participant_guid, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_adj_guid_failed; + + ddsrt_free(password); + ddsrt_free(privateKeyPEM); + ddsrt_free(identityCaPEM); + ddsrt_free(identityCertPEM); + ddsrt_free(trusted_ca_dir); + + identity = local_identity_info_new(domain_id, identityCert, identityCA, privateKey, candidate_participant_guid, adjusted_participant_guid); + *local_identity_handle = IDENTITY_HANDLE(identity); + + if (certExpiry != DDS_NEVER) + add_validity_end_trigger(implementation, *local_identity_handle, certExpiry); + + ddsrt_mutex_lock(&implementation->lock); + (void)ddsrt_hh_add(implementation->objectHash, identity); + ddsrt_mutex_unlock(&implementation->lock); + return DDS_SECURITY_VALIDATION_OK; + +err_adj_guid_failed: +err_verification_failed: + EVP_PKEY_free(privateKey); +err_inv_private_key: + X509_free(identityCert); +err_inv_identity_cert: +err_identity_ca_not_trusted: + X509_free(identityCA); +err_inv_identity_ca: +err_inv_trusted_ca_dir: + ddsrt_free(password); + ddsrt_free(privateKeyPEM); + ddsrt_free(trusted_ca_dir); +err_no_private_key: + ddsrt_free(identityCaPEM); +err_no_identity_ca: + ddsrt_free(identityCertPEM); +err_no_identity_cert: +err_bad_param: + return DDS_SECURITY_VALIDATION_FAILED; +} + +DDS_Security_boolean get_identity_token(dds_security_authentication *instance, DDS_Security_IdentityToken *identity_token, const DDS_Security_IdentityHandle handle, DDS_Security_SecurityException *ex) +{ + dds_security_authentication_impl *impl = (dds_security_authentication_impl *)instance; + SecurityObject *obj; + LocalIdentityInfo *identity; + char *snCert, *snCA; + + if (!instance || !identity_token) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "get_identity_token: Invalid parameter provided"); + goto err_bad_param; + } + memset(identity_token, 0, sizeof(*identity_token)); + + ddsrt_mutex_lock(&impl->lock); + + obj = security_object_find(impl->objectHash, handle); + if (!obj || !security_object_valid(obj, SECURITY_OBJECT_KIND_LOCAL_IDENTITY)) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "get_identity_token: Invalid handle provided"); + goto err_inv_handle; + } + identity = (LocalIdentityInfo *)obj; + if (!(snCert = get_certificate_subject_name(identity->identityCert, ex))) + goto err_sn_cert; + if (!(snCA = get_certificate_subject_name(identity->identityCA, ex))) + goto err_sn_ca; + + identity_token->class_id = get_authentication_class_id(); + identity_token->properties._length = 4; + identity_token->properties._buffer = DDS_Security_PropertySeq_allocbuf(4); + identity_token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_CERT_SUBJECT_NAME); + identity_token->properties._buffer[0].value = snCert; + identity_token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_CERT_ALGORITHM); + identity_token->properties._buffer[1].value = ddsrt_strdup(get_authentication_algo(get_authentication_algo_kind(identity->identityCert))); + identity_token->properties._buffer[2].name = ddsrt_strdup(PROPERTY_CA_SUBJECT_NAME); + identity_token->properties._buffer[2].value = snCA; + identity_token->properties._buffer[3].name = ddsrt_strdup(PROPERTY_CA_ALGORITHM); + identity_token->properties._buffer[3].value = ddsrt_strdup(get_authentication_algo(get_authentication_algo_kind(identity->identityCA))); + + ddsrt_mutex_unlock(&impl->lock); + + return true; + +err_sn_ca: + ddsrt_free(snCert); +err_sn_cert: +err_inv_handle: + ddsrt_mutex_unlock(&impl->lock); +err_bad_param: + return false; +} + +DDS_Security_boolean get_identity_status_token(dds_security_authentication *instance, DDS_Security_IdentityStatusToken *identity_status_token, const DDS_Security_IdentityHandle handle, DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(identity_status_token); + DDSRT_UNUSED_ARG(handle); + DDSRT_UNUSED_ARG(ex); + DDSRT_UNUSED_ARG(instance); + return true; +} + +DDS_Security_boolean set_permissions_credential_and_token(dds_security_authentication *instance, const DDS_Security_IdentityHandle handle, + const DDS_Security_PermissionsCredentialToken *permissions_credential, const DDS_Security_PermissionsToken *permissions_token, DDS_Security_SecurityException *ex) +{ + dds_security_authentication_impl *impl = (dds_security_authentication_impl *)instance; + LocalIdentityInfo *identity; + + if (!instance || handle == DDS_SECURITY_HANDLE_NIL || !permissions_credential || !permissions_token) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "get_identity_token: Invalid parameter provided"); + return false; + } + + if (!permissions_credential->class_id || strcmp(permissions_credential->class_id, ACCESS_PERMISSIONS_CREDENTIAL_TOKEN_ID) != 0) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "get_identity_token: Invalid parameter provided"); + return false; + } + + if (permissions_credential->properties._length == 0 || permissions_credential->properties._buffer[0].name == NULL + || strcmp(permissions_credential->properties._buffer[0].name, ACCESS_PROPERTY_PERMISSION_DOCUMENT) != 0) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "get_identity_token: Invalid parameter provided"); + return false; + } + + ddsrt_mutex_lock(&impl->lock); + identity = (LocalIdentityInfo *)security_object_find(impl->objectHash, handle); + if (!identity || !SECURITY_OBJECT_VALID(identity, SECURITY_OBJECT_KIND_LOCAL_IDENTITY)) + { + ddsrt_mutex_unlock(&impl->lock); + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "get_identity_token: Invalid handle provided"); + return false; + } + identity->permissionsDocument = ddsrt_strdup(permissions_credential->properties._buffer[0].value ? permissions_credential->properties._buffer[0].value : ""); + ddsrt_mutex_unlock(&impl->lock); + + return true; +} + +static DDS_Security_ValidationResult_t validate_remote_identity_token(const LocalIdentityInfo *localIdent, const DDS_Security_IdentityToken *token, DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(localIdent); + if (!token->class_id) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "remote identity token: class_id is empty"); + return DDS_SECURITY_VALIDATION_FAILED; + } + + size_t sz = strlen(AUTH_PROTOCOL_CLASS); + if (strncmp(AUTH_PROTOCOL_CLASS, token->class_id, sz) != 0) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "remote identity token: class_id='%s' not supported", token->class_id); + return DDS_SECURITY_VALIDATION_FAILED; + } + + char *ptr = &token->class_id[sz]; + unsigned major, minor; + char postfix[2]; + DDSRT_WARNING_MSVC_OFF(4996); + if (sscanf(ptr, ":%u.%u%1s", &major, &minor, postfix) != 2) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "remote identity token: class_id has wrong format"); + return DDS_SECURITY_VALIDATION_FAILED; + } + DDSRT_WARNING_MSVC_ON(4996); + + if (major != AUTH_PROTOCOL_VERSION_MAJOR) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "remote identity token: version %u.%u not supported", major, minor); + return DDS_SECURITY_VALIDATION_FAILED; + } + + return DDS_SECURITY_VALIDATION_OK; +} + +static DDS_Security_ValidationResult_t validate_auth_request_token(const DDS_Security_IdentityToken *token, AuthenticationChallenge **challenge, DDS_Security_SecurityException *ex) +{ + uint32_t index; + int found = 0; + assert(token); + if (!token->class_id) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "AuthRequestMessageToken invalid: missing class_id"); + return DDS_SECURITY_VALIDATION_FAILED; + } + if (strncmp(token->class_id, AUTH_REQUEST_TOKEN_CLASS_ID, strlen(AUTH_REQUEST_TOKEN_CLASS_ID)) != 0) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "AuthRequestMessageToken invalid: class_id '%s' is invalid", token->class_id); + return DDS_SECURITY_VALIDATION_FAILED; + } + if (!token->binary_properties._buffer) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "AuthRequestMessageToken invalid: properties are missing"); + return DDS_SECURITY_VALIDATION_FAILED; + } + + for (index = 0; index < token->binary_properties._length; index++) + { + size_t len = strlen(AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + if (token->binary_properties._buffer[index].name && strncmp(token->binary_properties._buffer[index].name, AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME, len) == 0) + { + found = 1; + break; + } + } + if (!found) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "AuthRequestMessageToken invalid: future_challenge not found"); + return DDS_SECURITY_VALIDATION_FAILED; + } + + if (token->binary_properties._buffer[index].value._length != sizeof(AuthenticationChallenge) + || !token->binary_properties._buffer[index].value._buffer) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "AuthRequestMessageToken invalid: future_challenge invalid size"); + return DDS_SECURITY_VALIDATION_FAILED; + } + + if (challenge) + { + *challenge = ddsrt_malloc(sizeof(AuthenticationChallenge)); + memcpy(*challenge, &token->binary_properties._buffer[index].value._buffer[0], sizeof(AuthenticationChallenge)); + } + + return DDS_SECURITY_VALIDATION_OK; +} + +static void fill_auth_request_token(DDS_Security_AuthRequestMessageToken *token, AuthenticationChallenge *challenge) +{ + uint32_t len = sizeof(challenge->value); + DDS_Security_DataHolder_deinit(token); + token->class_id = ddsrt_strdup(AUTH_REQUEST_TOKEN_CLASS_ID); + token->binary_properties._length = 1; + token->binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + token->binary_properties._buffer->name = ddsrt_strdup(AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + 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 validate_remote_identity(dds_security_authentication *instance, DDS_Security_IdentityHandle *remote_identity_handle, + DDS_Security_AuthRequestMessageToken *local_auth_request_token, const DDS_Security_AuthRequestMessageToken *remote_auth_request_token, const DDS_Security_IdentityHandle local_identity_handle, + const DDS_Security_IdentityToken *remote_identity_token, const DDS_Security_GUID_t *remote_participant_guid, DDS_Security_SecurityException *ex) +{ + dds_security_authentication_impl *impl = (dds_security_authentication_impl *)instance; + SecurityObject *obj; + LocalIdentityInfo *localIdent; + RemoteIdentityInfo *remoteIdent; + IdentityRelation *relation; + AuthenticationChallenge *lchallenge = NULL, *rchallenge = NULL; + + if (!instance || !remote_identity_handle || !local_auth_request_token || !remote_identity_token || !remote_participant_guid) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "validate_remote_identity: Invalid parameter provided"); + goto err_bad_param; + } + + ddsrt_mutex_lock(&impl->lock); + obj = security_object_find(impl->objectHash, local_identity_handle); + if (!obj || !security_object_valid(obj, SECURITY_OBJECT_KIND_LOCAL_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; + } + localIdent = (LocalIdentityInfo *)obj; + + if (validate_remote_identity_token(localIdent, remote_identity_token, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_remote_identity_token; + + /* When the remote_auth_request_token is not null, check if it's contents is valid and set the futureChallenge from the data contained in the remote_auth_request_token. */ + if (remote_auth_request_token) + { + if (validate_auth_request_token(remote_auth_request_token, &rchallenge, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_inv_auth_req_token; + } + + if ((lchallenge = generate_challenge(ex)) == NULL) + goto err_alloc_challenge; + + /* The validate_remote_identity will also create a handshake structure which contains the relation between + a local an remote identity. This handshake structure is inserted in the remote identity structure. */ + + /* Check if the remote identity has already been validated by a previous validation request. */ + if (!(remoteIdent = find_remote_identity_by_guid(impl->remoteGuidHash, remote_participant_guid))) + { + remoteIdent = remote_identity_info_new(remote_participant_guid, remote_identity_token); + (void)ddsrt_hh_add(impl->objectHash, remoteIdent); + (void)ddsrt_hh_add(impl->remoteGuidHash, remoteIdent); + relation = identity_relation_new(localIdent, remoteIdent, lchallenge, rchallenge); + (void)ddsrt_hh_add(remoteIdent->linkHash, relation); + } + else + { + /* 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(remoteIdent->remoteIdentityToken, remote_identity_token)) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "validate_remote_identity: remote_identity_token does not match with previously received one"); + goto err_inv_duplicate; + } + + if (!(relation = find_identity_relation(remoteIdent, SECURITY_OBJECT_HANDLE(localIdent)))) + { + relation = identity_relation_new(localIdent, remoteIdent, lchallenge, rchallenge); + int r = ddsrt_hh_add(remoteIdent->linkHash, relation); + assert(r); + (void)r; + } + else + { + if (remote_auth_request_token) + { + assert(rchallenge); + ddsrt_free(relation->rchallenge); + relation->rchallenge = rchallenge; + } + ddsrt_free(lchallenge); + } + } + ddsrt_mutex_unlock(&impl->lock); + + if (!remote_auth_request_token) + fill_auth_request_token(local_auth_request_token, relation->lchallenge); + else + DDS_Security_set_token_nil(local_auth_request_token); + + *remote_identity_handle = IDENTITY_HANDLE(remoteIdent); + return memcmp(&localIdent->adjustedGUID, &remoteIdent->guid, sizeof(DDS_Security_GUID_t)) < 0 ? + DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST : DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE; + +err_inv_duplicate: + ddsrt_free(lchallenge); +err_alloc_challenge: + ddsrt_free(rchallenge); +err_inv_auth_req_token: +err_remote_identity_token: +err_inv_handle: + ddsrt_mutex_unlock(&impl->lock); +err_bad_param: + return DDS_SECURITY_VALIDATION_FAILED; +} + +DDS_Security_ValidationResult_t begin_handshake_request(dds_security_authentication *instance, DDS_Security_HandshakeHandle *handshake_handle, + DDS_Security_HandshakeMessageToken *handshake_message, const DDS_Security_IdentityHandle initiator_identity_handle, const DDS_Security_IdentityHandle replier_identity_handle, + const DDS_Security_OctetSeq *serialized_local_participant_data, DDS_Security_SecurityException *ex) +{ + dds_security_authentication_impl *impl = (dds_security_authentication_impl *)instance; + HandshakeInfo *handshake = NULL; + IdentityRelation *relation = NULL; + SecurityObject *obj; + LocalIdentityInfo *localIdent; + RemoteIdentityInfo *remoteIdent; + EVP_PKEY *dhkey; + unsigned char *certData, *dhPubKeyData = NULL; + uint32_t certDataSize, dhPubKeyDataSize; + uint32_t tokcount = impl->include_optional ? 8 : 7; + int created = 0; + + if (!instance || !handshake_handle || !handshake_message || !serialized_local_participant_data) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "begin_handshake_request: Invalid parameter provided"); + goto err_bad_param; + } + + ddsrt_mutex_lock(&impl->lock); + + obj = security_object_find(impl->objectHash, initiator_identity_handle); + if (!obj || !security_object_valid(obj, SECURITY_OBJECT_KIND_LOCAL_IDENTITY)) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "begin_handshake_request: Invalid initiator_identity_handle provided"); + goto err_inv_handle; + } + localIdent = (LocalIdentityInfo *)obj; + + obj = security_object_find(impl->objectHash, replier_identity_handle); + 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; + } + remoteIdent = (RemoteIdentityInfo *)obj; + + if (get_certificate_contents(localIdent->identityCert, &certData, &certDataSize, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_alloc_cid; + + if (!(handshake = find_handshake(impl, SECURITY_OBJECT_HANDLE(localIdent), SECURITY_OBJECT_HANDLE(remoteIdent)))) + { + relation = find_identity_relation(remoteIdent, SECURITY_OBJECT_HANDLE(localIdent)); + assert(relation); + handshake = handshake_info_new(localIdent, remoteIdent, relation); + handshake->created_in = CREATEDREQUEST; + (void)ddsrt_hh_add(impl->objectHash, handshake); + created = 1; + } + else + { + relation = handshake->relation; + assert(relation); + } + + if (!handshake->ldh) + { + if (generate_dh_keys(&dhkey, localIdent->kagreeAlgoKind, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_gen_dh_keys; + handshake->ldh = dhkey; + } + + if (dh_public_key_to_oct(handshake->ldh, localIdent->kagreeAlgoKind, &dhPubKeyData, &dhPubKeyDataSize, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_get_public_key; + + if (localIdent->pdata._length == 0) + DDS_Security_OctetSeq_copy(&localIdent->pdata, serialized_local_participant_data); + + DDS_Security_BinaryProperty_t *tokens = DDS_Security_BinaryPropertySeq_allocbuf(tokcount); + uint32_t tokidx = 0; + + DDS_Security_BinaryProperty_set_by_ref(&tokens[tokidx++], "c.id", certData, certDataSize); + DDS_Security_BinaryProperty_set_by_string(&tokens[tokidx++], "c.perm", localIdent->permissionsDocument ? localIdent->permissionsDocument : ""); + DDS_Security_BinaryProperty_set_by_value(&tokens[tokidx++], "c.pdata", serialized_local_participant_data->_buffer, serialized_local_participant_data->_length); + DDS_Security_BinaryProperty_set_by_string(&tokens[tokidx++], "c.dsign_algo", get_dsign_algo(localIdent->dsignAlgoKind)); + DDS_Security_BinaryProperty_set_by_string(&tokens[tokidx++], "c.kagree_algo", get_kagree_algo(localIdent->kagreeAlgoKind)); + + /* Todo: including hash_c1 is optional (conform spec); add a configuration option to leave it out */ + { + DDS_Security_BinaryPropertySeq bseq = { ._length = 5, ._buffer = tokens }; + get_hash_binary_property_seq(&bseq, handshake->hash_c1); + if (impl->include_optional) + DDS_Security_BinaryProperty_set_by_value(&tokens[tokidx++], "hash_c1", handshake->hash_c1, sizeof(HashValue_t)); + } + + /* Set the DH public key associated with the local participant in dh1 property */ + assert(dhPubKeyData); + assert(dhPubKeyDataSize < 1200); + DDS_Security_BinaryProperty_set_by_ref(&tokens[tokidx++], "dh1", dhPubKeyData, dhPubKeyDataSize); + + /* Set the challenge in challenge1 property */ + DDS_Security_BinaryProperty_set_by_value(&tokens[tokidx++], "challenge1", relation->lchallenge->value, sizeof(AuthenticationChallenge)); + + (void)ddsrt_hh_add(impl->objectHash, handshake); + + ddsrt_mutex_unlock(&impl->lock); + + assert(tokcount == tokidx); + + handshake_message->class_id = ddsrt_strdup(AUTH_HANDSHAKE_REQUEST_TOKEN_ID); + handshake_message->properties._length = 0; + handshake_message->properties._buffer = NULL; + handshake_message->binary_properties._length = tokidx; + handshake_message->binary_properties._buffer = tokens; + *handshake_handle = HANDSHAKE_HANDLE(handshake); + + return DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE; + +err_get_public_key: +err_gen_dh_keys: + if (created) + { + (void)ddsrt_hh_remove(impl->objectHash, handshake); + security_object_free((SecurityObject *)handshake); + } +err_alloc_cid: + ddsrt_free(certData); +err_inv_handle: + ddsrt_mutex_unlock(&impl->lock); +err_bad_param: + return DDS_SECURITY_VALIDATION_FAILED; +} + +static DDS_Security_ValidationResult_t validate_pdata(const DDS_Security_OctetSeq *seq, X509 *cert, DDS_Security_SecurityException *ex) +{ + DDS_Security_ParticipantBuiltinTopicData *pdata; + DDS_Security_GUID_t cguid, aguid; + DDS_Security_Deserializer deserializer = DDS_Security_Deserializer_new(seq->_buffer, seq->_length); + if (!deserializer) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "begin_handshake_reply: c.pdata invalid encoding"); + goto failed_deser; + } + + pdata = DDS_Security_ParticipantBuiltinTopicData_alloc(); + if (!DDS_Security_Deserialize_ParticipantBuiltinTopicData(deserializer, pdata, ex)) + goto failed; + + memset(&cguid, 0, sizeof(DDS_Security_GUID_t)); + if (get_adjusted_participant_guid(cert, &cguid, &aguid, ex) != DDS_SECURITY_VALIDATION_OK) + goto failed; + + DDS_Security_BuiltinTopicKey_t key; + DDS_Security_BuiltinTopicKeyBE(key, pdata->key); + if (memcmp(key, aguid.prefix, 6) != 0) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "begin_handshake_reply: c.pdata contains incorrect participant guid"); + goto failed; + } + DDS_Security_ParticipantBuiltinTopicData_free(pdata); + DDS_Security_Deserializer_free(deserializer); + return DDS_SECURITY_VALIDATION_OK; + +failed: + DDS_Security_ParticipantBuiltinTopicData_free(pdata); + DDS_Security_Deserializer_free(deserializer); +failed_deser: + return DDS_SECURITY_VALIDATION_FAILED; +} + +enum handshake_token_type +{ + HS_TOKEN_REQ, + HS_TOKEN_REPLY, + HS_TOKEN_FINAL +}; + +static DDS_Security_ValidationResult_t set_exception (DDS_Security_SecurityException *ex, const char *fmt, ...) + ddsrt_attribute_format ((printf, 2, 3)) ddsrt_attribute_warn_unused_result; + +static DDS_Security_ValidationResult_t set_exception (DDS_Security_SecurityException *ex, const char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + DDS_Security_Exception_vset (ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, fmt, ap); + va_end (ap); + return DDS_SECURITY_VALIDATION_FAILED; +} + +static const DDS_Security_BinaryProperty_t *find_required_binprop (const DDS_Security_HandshakeMessageToken *token, const char *name, DDS_Security_SecurityException *ex) +{ + DDS_Security_ValidationResult_t result; + const DDS_Security_BinaryProperty_t *prop = DDS_Security_DataHolder_find_binary_property (token, name); + if (prop == NULL) + { + result = set_exception (ex, "process_handshake: HandshakeMessageToken property %s missing", name); + (void) result; + return NULL; + } + else if (prop->value._length > INT_MAX) + { + result = set_exception (ex, "process_handshake: HandshakeMessageToken property %s has unsupported size (%"PRIu32" bytes)", name, prop->value._length); + (void) result; + return NULL; + } + return prop; +} + +static const DDS_Security_BinaryProperty_t *find_required_nonempty_binprop (const DDS_Security_HandshakeMessageToken *token, const char *name, DDS_Security_SecurityException *ex) +{ + DDS_Security_ValidationResult_t result; + const DDS_Security_BinaryProperty_t *prop = find_required_binprop (token, name, ex); + if (prop != NULL && (prop->value._length == 0 || prop->value._buffer == NULL)) + { + // FIXME: _buffer == NULL check must go, that should've been guaranteed before + result = set_exception (ex, "process_handshake: HandshakeMessageToken property %s is empty", name); + (void) result; + return NULL; + } + return prop; +} + +static const DDS_Security_BinaryProperty_t *find_required_binprop_exactsize (const DDS_Security_HandshakeMessageToken *token, const char *name, size_t size, DDS_Security_SecurityException *ex) +{ + DDS_Security_ValidationResult_t result; + const DDS_Security_BinaryProperty_t *prop = find_required_binprop (token, name, ex); + if (prop != NULL && prop->value._length != size) + { + result = set_exception (ex, "process_handshake: HandshakeMessageToken property %s has wrong size (%"PRIu32" while expecting %"PRIuSIZE")", name, prop->value._length, size); + (void) result; + return NULL; + } + return prop; +} + +static X509 *load_X509_certificate_from_binprop (const DDS_Security_BinaryProperty_t *prop, X509 *own_ca, const X509Seq *trusted_ca_list, DDS_Security_SecurityException *ex) +{ + X509 *cert; + + if (load_X509_certificate_from_data ((char *) prop->value._buffer, (int) prop->value._length, &cert, ex) != DDS_SECURITY_VALIDATION_OK) + return NULL; + + DDS_Security_ValidationResult_t result = DDS_SECURITY_VALIDATION_FAILED; + if (trusted_ca_list->length == 0) + result = verify_certificate (cert, own_ca, ex); + else + { + DDS_Security_Exception_clean (ex); + for (unsigned i = 0; i < trusted_ca_list->length; ++i) + { + DDS_Security_Exception_reset (ex); + if ((result = verify_certificate (cert, trusted_ca_list->buffer[i], ex)) == DDS_SECURITY_VALIDATION_OK) + break; + } + } + if (result != DDS_SECURITY_VALIDATION_OK || check_certificate_expiry (cert, ex) != DDS_SECURITY_VALIDATION_OK) + { + X509_free (cert); + return NULL; + } + return cert; +} + +static DDS_Security_BinaryProperty_t * +create_dhkey_property(const char *name, EVP_PKEY *pkey, AuthenticationAlgoKind_t kagreeAlgoKind, DDS_Security_SecurityException *ex) +{ + DDS_Security_BinaryProperty_t *prop; + unsigned char *data; + uint32_t len; + + if (dh_public_key_to_oct(pkey, kagreeAlgoKind, &data, &len, ex) != DDS_SECURITY_VALIDATION_OK) + return NULL; + + prop = DDS_Security_BinaryProperty_alloc(); + DDS_Security_BinaryProperty_set_by_ref(prop, name, data, len); + return prop; +} + +static DDS_Security_ValidationResult_t validate_handshake_token_impl (const DDS_Security_HandshakeMessageToken *token, enum handshake_token_type token_type, + HandshakeInfo *handshake, X509Seq *trusted_ca_list, const DDS_Security_BinaryProperty_t *dh1_ref, const DDS_Security_BinaryProperty_t *dh2_ref, DDS_Security_SecurityException *ex) +{ + IdentityRelation * const relation = handshake->relation; + X509 *identityCert = NULL; + const DDS_Security_BinaryProperty_t *c_pdata = NULL; + AuthenticationAlgoKind_t dsignAlgoKind = AUTH_ALGO_KIND_UNKNOWN, kagreeAlgoKind = AUTH_ALGO_KIND_UNKNOWN; + const DDS_Security_BinaryProperty_t *dh1 = NULL, *dh2 = NULL; + const DDS_Security_BinaryProperty_t *hash_c1 = NULL, *hash_c2 = NULL; + const DDS_Security_BinaryProperty_t *challenge1 = NULL, *challenge2 = NULL; + const DDS_Security_BinaryProperty_t *signature = NULL; + const char *token_class_id = NULL; + + assert (relation); + assert (dh1_ref != NULL || token_type == HS_TOKEN_REQ); + assert (dh2_ref != NULL || token_type == HS_TOKEN_REQ || token_type == HS_TOKEN_REPLY); + + switch (token_type) + { + case HS_TOKEN_REQ: token_class_id = AUTH_HANDSHAKE_REQUEST_TOKEN_ID; break; + case HS_TOKEN_REPLY: token_class_id = AUTH_HANDSHAKE_REPLY_TOKEN_ID; break; + case HS_TOKEN_FINAL: token_class_id = AUTH_HANDSHAKE_FINAL_TOKEN_ID; break; + } + assert (token_class_id); + + if (!token->class_id || strncmp (token_class_id, token->class_id, strlen (token_class_id)) != 0) + return set_exception (ex, "process_handshake: HandshakeMessageToken incorrect class_id: %s (expected %s)", token->class_id ? token->class_id : "NULL", token_class_id); + + if (token_type == HS_TOKEN_REQ || token_type == HS_TOKEN_REPLY) + { + const DDS_Security_BinaryProperty_t *c_id, *c_perm, *c_dsign_algo, *c_kagree_algo; + + if ((c_id = find_required_nonempty_binprop (token, "c.id", ex)) == NULL) + return DDS_SECURITY_VALIDATION_FAILED; + if ((identityCert = load_X509_certificate_from_binprop (c_id, relation->localIdentity->identityCA, trusted_ca_list, ex)) == NULL) + return DDS_SECURITY_VALIDATION_FAILED; + + /* TODO: check if an identity certificate was already associated with the remote identity and when that is the case both should be the same */ + if (relation->remoteIdentity->identityCert) + X509_free (relation->remoteIdentity->identityCert); + relation->remoteIdentity->identityCert = identityCert; + + if ((c_perm = find_required_binprop (token, "c.perm", ex)) == NULL) + return DDS_SECURITY_VALIDATION_FAILED; + if (c_perm->value._length > 0) + { + ddsrt_free (relation->remoteIdentity->permissionsDocument); + relation->remoteIdentity->permissionsDocument = string_from_data (c_perm->value._buffer, c_perm->value._length); + } + + if ((c_pdata = find_required_binprop (token, "c.pdata", ex)) == NULL) + return DDS_SECURITY_VALIDATION_FAILED; + if (validate_pdata (&c_pdata->value, identityCert, ex) != DDS_SECURITY_VALIDATION_OK) + return DDS_SECURITY_VALIDATION_FAILED; + + if ((c_dsign_algo = find_required_nonempty_binprop (token, "c.dsign_algo", ex)) == NULL) + return DDS_SECURITY_VALIDATION_FAILED; + if ((dsignAlgoKind = get_dsign_algo_from_octseq (&c_dsign_algo->value)) == AUTH_ALGO_KIND_UNKNOWN) + return set_exception (ex, "process_handshake: HandshakeMessageToken property c.dsign_algo not supported"); + + if ((c_kagree_algo = find_required_nonempty_binprop (token, "c.kagree_algo", ex)) == NULL) + return DDS_SECURITY_VALIDATION_FAILED; + if ((kagreeAlgoKind = get_kagree_algo_from_octseq (&c_kagree_algo->value)) == AUTH_ALGO_KIND_UNKNOWN) + return set_exception (ex, "process_handshake: HandshakeMessageToken property c.kagree_algo not supported"); + + /* calculate the hash value and set in handshake hash_c1 (req) or hash_c2 (reply) */ + const DDS_Security_BinaryProperty_t *binary_properties[] = { c_id, c_perm, c_pdata, c_dsign_algo, c_kagree_algo }; + (void) compute_hash_value ((token_type == HS_TOKEN_REQ) ? handshake->hash_c1 : handshake->hash_c2, binary_properties, 5, NULL); + } + + if (token_type == HS_TOKEN_REQ) + { + EVP_PKEY *pdhkey_req = NULL; + + if ((dh1 = find_required_nonempty_binprop (token, "dh1", ex)) == NULL) + return DDS_SECURITY_VALIDATION_FAILED; + if (dh_oct_to_public_key (&pdhkey_req, kagreeAlgoKind, dh1->value._buffer, dh1->value._length, ex) != DDS_SECURITY_VALIDATION_OK) + return DDS_SECURITY_VALIDATION_FAILED; + if (handshake->rdh) + EVP_PKEY_free (handshake->rdh); + handshake->rdh = pdhkey_req; + } + else + { + dh1 = DDS_Security_DataHolder_find_binary_property (token, "dh1"); + if (dh1 && !DDS_Security_BinaryProperty_equal(dh1_ref, dh1)) + return set_exception (ex, "process_handshake: %s token property dh1 not correct", (token_type == HS_TOKEN_REPLY) ? "Reply" : "Final"); + dh1 = dh1_ref; + } + + if ((challenge1 = find_required_binprop_exactsize (token, "challenge1", sizeof (AuthenticationChallenge), ex)) == NULL) + return DDS_SECURITY_VALIDATION_FAILED; + + if (token_type == HS_TOKEN_REPLY || token_type == HS_TOKEN_FINAL) + { + if ((challenge2 = find_required_binprop_exactsize (token, "challenge2", sizeof (AuthenticationChallenge), ex)) == NULL) + return DDS_SECURITY_VALIDATION_FAILED; + if ((signature = find_required_nonempty_binprop (token, "signature", ex)) == NULL) + return DDS_SECURITY_VALIDATION_FAILED; + + if (token_type == HS_TOKEN_REPLY) + { + EVP_PKEY *pdhkey_reply = NULL; + + if ((dh2 = find_required_nonempty_binprop (token, "dh2", ex)) == NULL) + return DDS_SECURITY_VALIDATION_FAILED; + if (dh_oct_to_public_key (&pdhkey_reply, kagreeAlgoKind, dh2->value._buffer, dh2->value._length, ex) != DDS_SECURITY_VALIDATION_OK) + return DDS_SECURITY_VALIDATION_FAILED; + if (handshake->rdh) + EVP_PKEY_free (handshake->rdh); + handshake->rdh = pdhkey_reply; + } + else + { + dh2 = DDS_Security_DataHolder_find_binary_property (token, "dh2"); + if (dh2 && !DDS_Security_BinaryProperty_equal(dh2_ref, dh2)) + return set_exception (ex, "process_handshake: Final token property dh2 not correct"); + dh2 = dh2_ref; + } + } + + /* When validate_remote_identity was provided with a remote_auth_request_token then the future_challenge in + the remote identity was set and the challenge(1|2) property of the handshake_(request|reply|final)_token + should be the same as the future_challenge stored in the remote identity. */ + const DDS_Security_BinaryProperty_t *rc = (token_type == HS_TOKEN_REPLY) ? challenge2 : challenge1; + if (relation->rchallenge) + { + if (memcmp (relation->rchallenge->value, rc->value._buffer, sizeof (AuthenticationChallenge)) != 0) + return set_exception (ex, "process_handshake: HandshakeMessageToken property challenge%d does not match future_challenge", (token_type == HS_TOKEN_REPLY) ? 2 : 1); + } + else if (token_type != HS_TOKEN_FINAL) + { + relation->rchallenge = ddsrt_memdup (rc->value._buffer, sizeof (AuthenticationChallenge)); + } + + /* From DDS Security spec: inclusion of the hash_c1 property is optional. Its only purpose is to + facilitate troubleshoot interoperability problems. */ + if ((hash_c1 = DDS_Security_DataHolder_find_binary_property (token, "hash_c1"))) + { + /* hash_c1 should be set during req or reply token validation */ + assert (handshake->hash_c1 != NULL); + if (hash_c1->value._length != sizeof (HashValue_t) || memcmp (hash_c1->value._buffer, handshake->hash_c1, sizeof (HashValue_t)) != 0) + return set_exception (ex, "process_handshake: HandshakeMessageToken property hash_c1 invalid"); + } + + if (token_type == HS_TOKEN_REPLY || token_type == HS_TOKEN_FINAL) + { + /* hash_c2 should be set during reply token validation */ + assert (handshake->hash_c2 != NULL); + + /* From DDS Security spec: inclusion of the hash_c2 property is optional. Its only purpose is to + facilitate troubleshoot interoperability problems. */ + if ((hash_c2 = DDS_Security_DataHolder_find_binary_property (token, "hash_c2"))) + { + if (hash_c2->value._length != sizeof (HashValue_t) || memcmp (hash_c2->value._buffer, handshake->hash_c2, sizeof (HashValue_t)) != 0) + return set_exception (ex, "process_handshake: HandshakeMessageToken property hash_c2 invalid"); + } + if (relation->lchallenge == NULL) + return set_exception (ex, "process_handshake: No future challenge exists for this token"); + const DDS_Security_BinaryProperty_t *lc = (token_type == HS_TOKEN_REPLY) ? challenge1 : challenge2; + if (memcmp (relation->lchallenge->value, lc->value._buffer, sizeof (AuthenticationChallenge)) != 0) + return set_exception (ex, "process_handshake: HandshakeMessageToken property challenge1 does not match future_challenge"); + } + + if (token_type == HS_TOKEN_REQ || token_type == HS_TOKEN_REPLY) + { + assert (dsignAlgoKind != AUTH_ALGO_KIND_UNKNOWN); + assert (kagreeAlgoKind != AUTH_ALGO_KIND_UNKNOWN); + assert (c_pdata != NULL); + + relation->remoteIdentity->dsignAlgoKind = dsignAlgoKind; + relation->remoteIdentity->kagreeAlgoKind = kagreeAlgoKind; + DDS_Security_OctetSeq_copy (&relation->remoteIdentity->pdata, &c_pdata->value); + } + + if (token_type == HS_TOKEN_REPLY || token_type == HS_TOKEN_FINAL) + { + EVP_PKEY *public_key; + if ((public_key = X509_get_pubkey (relation->remoteIdentity->identityCert)) == NULL) + return set_exception (ex, "X509_get_pubkey failed"); + + DDS_Security_BinaryProperty_t hash_c1_val = { + .name = "hash_c1", .value = { ._length = sizeof (handshake->hash_c1), ._buffer = handshake->hash_c1 } + }; + DDS_Security_BinaryProperty_t hash_c2_val = { + .name = "hash_c2", .value = { ._length = sizeof (handshake->hash_c2), ._buffer = handshake->hash_c2 } + }; + DDS_Security_ValidationResult_t result; + if (token_type == HS_TOKEN_REPLY) + result = validate_signature (public_key, (const DDS_Security_BinaryProperty_t *[]) { + &hash_c2_val, challenge2, dh2, challenge1, dh1, &hash_c1_val }, 6, signature->value._buffer, signature->value._length, ex); + else + result = validate_signature (public_key, (const DDS_Security_BinaryProperty_t *[]) { + &hash_c1_val, challenge1, dh1, challenge2, dh2, &hash_c2_val }, 6, signature->value._buffer, signature->value._length, ex); + EVP_PKEY_free (public_key); + + if (result != DDS_SECURITY_VALIDATION_OK) + return result; + } + + return DDS_SECURITY_VALIDATION_OK; +} + +static DDS_Security_ValidationResult_t validate_handshake_token(const DDS_Security_HandshakeMessageToken *token, enum handshake_token_type token_type, HandshakeInfo *handshake, + X509Seq *trusted_ca_list, const DDS_Security_BinaryProperty_t *dh1_ref, const DDS_Security_BinaryProperty_t *dh2_ref, DDS_Security_SecurityException *ex) +{ + const DDS_Security_ValidationResult_t ret = validate_handshake_token_impl (token, token_type, handshake, trusted_ca_list, dh1_ref, dh2_ref, ex); + + if (ret != DDS_SECURITY_VALIDATION_OK) + { + if (token_type == HS_TOKEN_REQ || token_type == HS_TOKEN_REPLY) + { + IdentityRelation *relation = handshake->relation; + + if (relation->remoteIdentity->identityCert) + { + X509_free (relation->remoteIdentity->identityCert); + relation->remoteIdentity->identityCert = NULL; + } + + if (handshake->rdh) + { + EVP_PKEY_free (handshake->rdh); + handshake->rdh = NULL; + } + } + } + + return ret; +} + +DDS_Security_ValidationResult_t begin_handshake_reply(dds_security_authentication *instance, DDS_Security_HandshakeHandle *handshake_handle, + DDS_Security_HandshakeMessageToken *handshake_message_out, const DDS_Security_HandshakeMessageToken *handshake_message_in, + const DDS_Security_IdentityHandle initiator_identity_handle, const DDS_Security_IdentityHandle replier_identity_handle, + const DDS_Security_OctetSeq *serialized_local_participant_data, DDS_Security_SecurityException *ex) +{ + dds_security_authentication_impl *impl = (dds_security_authentication_impl *)instance; + HandshakeInfo *handshake = NULL; + IdentityRelation *relation = NULL; + SecurityObject *obj; + LocalIdentityInfo *localIdent; + RemoteIdentityInfo *remoteIdent; + EVP_PKEY *dhkeyLocal = NULL; + unsigned char *certData, *dhPubKeyData; + uint32_t certDataSize, dhPubKeyDataSize; + uint32_t tokcount = impl->include_optional ? 12 : 9; + int created = 0; + + if (!instance || !handshake_handle || !handshake_message_out || !handshake_message_in || !serialized_local_participant_data) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "begin_handshake_reply: Invalid parameter provided"); + goto err_bad_param; + } + + if (serialized_local_participant_data->_length == 0 || serialized_local_participant_data->_buffer == NULL) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "begin_handshake_reply: Invalid parameter provided"); + goto err_bad_param; + } + + ddsrt_mutex_lock(&impl->lock); + + obj = security_object_find(impl->objectHash, replier_identity_handle); + if (!obj || !security_object_valid(obj, SECURITY_OBJECT_KIND_LOCAL_IDENTITY)) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "begin_handshake_reply: Invalid replier_identity_handle provided"); + goto err_inv_handle; + } + localIdent = (LocalIdentityInfo *)obj; + + obj = security_object_find(impl->objectHash, initiator_identity_handle); + 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; + } + remoteIdent = (RemoteIdentityInfo *)obj; + if (!(handshake = find_handshake(impl, SECURITY_OBJECT_HANDLE(localIdent), SECURITY_OBJECT_HANDLE(remoteIdent)))) + { + relation = find_identity_relation(remoteIdent, SECURITY_OBJECT_HANDLE(localIdent)); + assert(relation); + handshake = handshake_info_new(localIdent, remoteIdent, relation); + handshake->created_in = CREATEDREPLY; + (void)ddsrt_hh_add(impl->objectHash, handshake); + created = 1; + } + else + { + relation = handshake->relation; + assert(relation); + } + + if (validate_handshake_token(handshake_message_in, HS_TOKEN_REQ, handshake, &(impl->trustedCAList), NULL, NULL, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_inv_token; + if (get_certificate_contents(localIdent->identityCert, &certData, &certDataSize, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_alloc_cid; + + if (!handshake->ldh) + { + if (generate_dh_keys(&dhkeyLocal, remoteIdent->kagreeAlgoKind, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_gen_dh_keys; + + handshake->ldh = dhkeyLocal; + EVP_PKEY_copy_parameters(handshake->rdh, handshake->ldh); + } + + if (dh_public_key_to_oct(handshake->ldh, remoteIdent->kagreeAlgoKind, &dhPubKeyData, &dhPubKeyDataSize, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_get_public_key; + + if (localIdent->pdata._length == 0) + DDS_Security_OctetSeq_copy(&localIdent->pdata, serialized_local_participant_data); + + DDS_Security_BinaryProperty_t *tokens = DDS_Security_BinaryPropertySeq_allocbuf(tokcount); + uint32_t tokidx = 0; + + /* Store the Identity Certificate associated with the local identify in c.id property */ + DDS_Security_BinaryProperty_set_by_ref(&tokens[tokidx++], "c.id", certData, certDataSize); + certData = NULL; + DDS_Security_BinaryProperty_set_by_string(&tokens[tokidx++], "c.perm", localIdent->permissionsDocument ? localIdent->permissionsDocument : ""); + DDS_Security_BinaryProperty_set_by_value(&tokens[tokidx++], "c.pdata", serialized_local_participant_data->_buffer, serialized_local_participant_data->_length); + DDS_Security_BinaryProperty_set_by_string(&tokens[tokidx++], "c.dsign_algo", get_dsign_algo(localIdent->dsignAlgoKind)); + DDS_Security_BinaryProperty_set_by_string(&tokens[tokidx++], "c.kagree_algo", get_kagree_algo(remoteIdent->kagreeAlgoKind)); + + /* Calculate the hash_c2 */ + DDS_Security_BinaryPropertySeq bseq = { ._length = 5, ._buffer = tokens }; + get_hash_binary_property_seq(&bseq, handshake->hash_c2); + + /* Set the DH public key associated with the local participant in dh2 property */ + DDS_Security_BinaryProperty_t *dh2 = &tokens[tokidx++]; + DDS_Security_BinaryProperty_set_by_ref(dh2, "dh2", dhPubKeyData, dhPubKeyDataSize); + + /* Find the dh1 property from the received request token */ + const DDS_Security_BinaryProperty_t *dh1 = DDS_Security_DataHolder_find_binary_property(handshake_message_in, "dh1"); + assert(dh1); + + assert(relation->rchallenge); + DDS_Security_BinaryProperty_t *challenge1 = &tokens[tokidx++]; + DDS_Security_BinaryProperty_set_by_value(challenge1, "challenge1", relation->rchallenge->value, sizeof(AuthenticationChallenge)); + assert(relation->lchallenge); + DDS_Security_BinaryProperty_t *challenge2 = &tokens[tokidx++]; + DDS_Security_BinaryProperty_set_by_value(challenge2, "challenge2", relation->lchallenge->value, sizeof(AuthenticationChallenge)); + + /* THe dh1 and hash_c1 and hash_c2 are optional */ + if (impl->include_optional) + { + DDS_Security_BinaryProperty_set_by_value(&tokens[tokidx++], "dh1", dh1->value._buffer, dh1->value._length); + DDS_Security_BinaryProperty_set_by_value(&tokens[tokidx++], "hash_c2", handshake->hash_c2, sizeof(HashValue_t)); + DDS_Security_BinaryProperty_set_by_value(&tokens[tokidx++], "hash_c1", handshake->hash_c1, sizeof(HashValue_t)); + } + + /* Calculate the signature */ + { + unsigned char *sign; + size_t signlen; + DDS_Security_BinaryProperty_t *hash_c1_val = hash_value_to_binary_property("hash_c1", handshake->hash_c1); + DDS_Security_BinaryProperty_t *hash_c2_val = hash_value_to_binary_property("hash_c2", handshake->hash_c2); + const DDS_Security_BinaryProperty_t *binary_properties[HANDSHAKE_SIGNATURE_CONTENT_SIZE] = { hash_c2_val, challenge2, dh2, challenge1, dh1, hash_c1_val }; + DDS_Security_ValidationResult_t 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); + if (result != DDS_SECURITY_VALIDATION_OK) + goto err_signature; + DDS_Security_BinaryProperty_set_by_ref(&tokens[tokidx++], "signature", sign, (uint32_t)signlen); + } + + assert(tokidx == tokcount); + + (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 = tokidx; + handshake_message_out->binary_properties._buffer = tokens; + + ddsrt_mutex_unlock(&impl->lock); + + *handshake_handle = HANDSHAKE_HANDLE(handshake); + return DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE; + +err_signature: + free_binary_properties(tokens, tokcount); +err_get_public_key: +err_gen_dh_keys: + ddsrt_free(certData); +err_alloc_cid: +err_inv_token: + if (created) + { + (void)ddsrt_hh_remove(impl->objectHash, handshake); + security_object_free((SecurityObject *)handshake); + } +err_inv_handle: + ddsrt_mutex_unlock(&impl->lock); +err_bad_param: + return DDS_SECURITY_VALIDATION_FAILED; +} + +static bool generate_shared_secret(const HandshakeInfo *handshake, unsigned char **shared_secret, DDS_Security_long *length, DDS_Security_SecurityException *ex) +{ + EVP_PKEY_CTX *ctx; + size_t skeylen; + unsigned char *secret = NULL; + *shared_secret = NULL; + + if (!(ctx = EVP_PKEY_CTX_new(handshake->ldh, NULL /* no engine */))) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "process_handshake: Shared secret failed to create context: "); + goto fail_ctx_new; + } + + if (EVP_PKEY_derive_init(ctx) <= 0) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "process_handshake: Shared secret failed to initialize context: "); + goto fail_derive; + } + if (EVP_PKEY_derive_set_peer(ctx, handshake->rdh) <= 0) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "process_handshake: Shared secret failed to set peer key: "); + goto fail_derive; + } + + /* Determine buffer length */ + if (EVP_PKEY_derive(ctx, NULL, &skeylen) <= 0) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "process_handshake: Shared secret failed to determine key length: "); + goto fail_derive; + } + + secret = ddsrt_malloc(skeylen); + if (EVP_PKEY_derive(ctx, secret, &skeylen) <= 0) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "process_handshake: Could not compute the shared secret: "); + goto fail_derive; + } + + *shared_secret = ddsrt_malloc(SHA256_DIGEST_LENGTH); + *length = SHA256_DIGEST_LENGTH; + SHA256(secret, skeylen, *shared_secret); + ddsrt_free(secret); + EVP_PKEY_CTX_free(ctx); + return true; + +fail_derive: + ddsrt_free(secret); + EVP_PKEY_CTX_free(ctx); +fail_ctx_new: + return false; +} + +DDS_Security_ValidationResult_t process_handshake(dds_security_authentication *instance, DDS_Security_HandshakeMessageToken *handshake_message_out, + const DDS_Security_HandshakeMessageToken *handshake_message_in, const DDS_Security_HandshakeHandle handshake_handle, DDS_Security_SecurityException *ex) +{ + DDS_Security_ValidationResult_t hs_result = DDS_SECURITY_VALIDATION_OK; + dds_security_authentication_impl *impl = (dds_security_authentication_impl *)instance; + HandshakeInfo *handshake = NULL; + IdentityRelation *relation = NULL; + SecurityObject *obj; + DDS_Security_BinaryProperty_t *dh1_gen = NULL, *dh2_gen = NULL; + const uint32_t tsz = impl->include_optional ? 7 : 3; + DDS_Security_octet *challenge1_ref_for_shared_secret, *challenge2_ref_for_shared_secret; + + /* validate provided arguments */ + if (!instance || !handshake_handle || !handshake_message_out || !handshake_message_in) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "process_handshake: Invalid parameter provided"); + goto err_bad_param; + } + + memset(handshake_message_out, 0, sizeof(DDS_Security_HandshakeMessageToken)); + + ddsrt_mutex_lock(&impl->lock); + 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, "process_handshake: Invalid replier_identity_handle provided"); + goto err_inv_handle; + } + handshake = (HandshakeInfo *)obj; + relation = handshake->relation; + assert(relation); + + /* check if the handle created by a handshake_request or handshake_reply */ + switch (handshake->created_in) + { + case CREATEDREQUEST: + if ((dh1_gen = create_dhkey_property("dh1", handshake->ldh, relation->localIdentity->kagreeAlgoKind, ex)) == NULL) + goto err_inv_token; + + /* The source of the handshake_handle is a begin_handshake_request function. So, handshake_message_in is from a remote begin_handshake_reply function */ + /* Verify Message Token contents according to Spec 9.3.2.5.2 (Reply Message) */ + if (validate_handshake_token(handshake_message_in, HS_TOKEN_REPLY, handshake, &(impl->trustedCAList), dh1_gen, NULL, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_inv_token; + + EVP_PKEY_copy_parameters(handshake->rdh, handshake->ldh); + + /* Find the dh1 property from the received request token */ + const DDS_Security_BinaryProperty_t *dh2 = DDS_Security_DataHolder_find_binary_property(handshake_message_in, "dh2"); + assert(dh2); + + DDS_Security_BinaryProperty_t *tokens = DDS_Security_BinaryPropertySeq_allocbuf(tsz); + uint32_t idx = 0; + + assert(relation->lchallenge); + DDS_Security_BinaryProperty_t *challenge1 = &tokens[idx++]; + DDS_Security_BinaryProperty_set_by_value(challenge1, "challenge1", relation->lchallenge->value, sizeof(AuthenticationChallenge)); + assert(relation->rchallenge); + DDS_Security_BinaryProperty_t *challenge2 = &tokens[idx++]; + DDS_Security_BinaryProperty_set_by_value(challenge2, "challenge2", relation->rchallenge->value, sizeof(AuthenticationChallenge)); + + if (impl->include_optional) + { + DDS_Security_BinaryProperty_set_by_value(&tokens[idx++], "dh1", dh1_gen->value._buffer, dh1_gen->value._length); + DDS_Security_BinaryProperty_set_by_value(&tokens[idx++], "dh2", dh2->value._buffer, dh2->value._length); + DDS_Security_BinaryProperty_set_by_value(&tokens[idx++], "hash_c2", handshake->hash_c2, sizeof(HashValue_t)); + DDS_Security_BinaryProperty_set_by_value(&tokens[idx++], "hash_c1", handshake->hash_c1, sizeof(HashValue_t)); + } + + /* Calculate the signature */ + { + unsigned char *sign; + size_t signlen; + DDS_Security_BinaryProperty_t *hash_c1_val = hash_value_to_binary_property("hash_c1", handshake->hash_c1); + DDS_Security_BinaryProperty_t *hash_c2_val = hash_value_to_binary_property("hash_c2", handshake->hash_c2); + const DDS_Security_BinaryProperty_t *binary_properties[HANDSHAKE_SIGNATURE_CONTENT_SIZE] = { hash_c1_val, challenge1, dh1_gen, challenge2, dh2, hash_c2_val }; + DDS_Security_ValidationResult_t result = create_signature(relation->localIdentity->privateKey, binary_properties, HANDSHAKE_SIGNATURE_CONTENT_SIZE, &sign, &signlen, ex); + DDS_Security_BinaryProperty_free(hash_c1_val); + DDS_Security_BinaryProperty_free(hash_c2_val); + if (result != DDS_SECURITY_VALIDATION_OK) + goto err_signature; + DDS_Security_BinaryProperty_set_by_ref(&tokens[idx++], "signature", sign, (uint32_t)signlen); + } + + handshake_message_out->class_id = ddsrt_strdup(AUTH_HANDSHAKE_FINAL_TOKEN_ID); + handshake_message_out->binary_properties._length = tsz; + handshake_message_out->binary_properties._buffer = tokens; + challenge1_ref_for_shared_secret = (DDS_Security_octet *)(handshake->relation->lchallenge); + challenge2_ref_for_shared_secret = (DDS_Security_octet *)(handshake->relation->rchallenge); + hs_result = DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE; + break; + + case CREATEDREPLY: + if ((dh1_gen = create_dhkey_property("dh1", handshake->rdh, relation->remoteIdentity->kagreeAlgoKind, ex)) == NULL) + goto err_inv_token; + if ((dh2_gen = create_dhkey_property("dh2", handshake->ldh, relation->remoteIdentity->kagreeAlgoKind, ex)) == NULL) + goto err_inv_token; + + /* The source of the handshake_handle is a begin_handshake_reply function So, handshake_message_in is from a remote process_handshake function */ + /* Verify Message Token contents according to Spec 9.3.2.5.3 (Final Message) */ + if (validate_handshake_token(handshake_message_in, HS_TOKEN_FINAL, handshake, NULL, dh1_gen, dh2_gen, ex) != DDS_SECURITY_VALIDATION_OK) + 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); + hs_result = DDS_SECURITY_VALIDATION_OK; + break; + + default: + ddsrt_mutex_unlock(&impl->lock); + goto err_bad_param; + } + + { + DDS_Security_long shared_secret_length; + unsigned char *shared_secret; + if (!generate_shared_secret(handshake, &shared_secret, &shared_secret_length, ex)) + goto err_openssl; + handshake->shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + handshake->shared_secret_handle_impl->shared_secret = shared_secret; + handshake->shared_secret_handle_impl->shared_secret_size = shared_secret_length; + memcpy(handshake->shared_secret_handle_impl->challenge1, challenge1_ref_for_shared_secret, DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE); + memcpy(handshake->shared_secret_handle_impl->challenge2, challenge2_ref_for_shared_secret, DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE); + } + + { + /* setup expiry listener */ + dds_time_t cert_exp = get_certificate_expiry(handshake->relation->remoteIdentity->identityCert); + if (cert_exp == DDS_TIME_INVALID) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "Expiry date of the certificate is invalid"); + goto err_invalid_expiry; + } + else if (cert_exp != DDS_NEVER) + add_validity_end_trigger(impl, IDENTITY_HANDLE(handshake->relation->remoteIdentity), cert_exp); + } + ddsrt_mutex_unlock(&impl->lock); + + DDS_Security_BinaryProperty_free(dh1_gen); + DDS_Security_BinaryProperty_free(dh2_gen); + + return hs_result; + +err_invalid_expiry: + ddsrt_free(handshake->shared_secret_handle_impl->shared_secret); + ddsrt_free(handshake->shared_secret_handle_impl); + handshake->shared_secret_handle_impl = NULL; +err_openssl: +err_signature: + if (handshake_message_out->class_id) + DDS_Security_DataHolder_deinit(handshake_message_out); +err_inv_token: + DDS_Security_BinaryProperty_free(dh1_gen); + DDS_Security_BinaryProperty_free(dh2_gen); +err_inv_handle: + ddsrt_mutex_unlock(&impl->lock); +err_bad_param: + return DDS_SECURITY_VALIDATION_FAILED; +} + +DDS_Security_SharedSecretHandle get_shared_secret(dds_security_authentication *instance, const DDS_Security_HandshakeHandle handshake_handle, DDS_Security_SecurityException *ex) +{ + dds_security_authentication_impl *impl = (dds_security_authentication_impl *)instance; + SecurityObject *obj; + + if (!instance || !handshake_handle) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "return_handshake_handle: Invalid parameter provided"); + goto err_bad_param; + } + ddsrt_mutex_lock(&impl->lock); + 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)(ddsrt_address)((HandshakeInfo *)obj)->shared_secret_handle_impl; + +err_invalid_handle: + ddsrt_mutex_unlock(&impl->lock); +err_bad_param: + return DDS_SECURITY_HANDLE_NIL; +} + +DDS_Security_boolean get_authenticated_peer_credential_token(dds_security_authentication *instance, DDS_Security_AuthenticatedPeerCredentialToken *peer_credential_token, + const DDS_Security_HandshakeHandle handshake_handle, DDS_Security_SecurityException *ex) +{ + dds_security_authentication_impl *impl = (dds_security_authentication_impl *)instance; + HandshakeInfo *handshake = NULL; + X509 *identity_cert; + char *permissions_doc; + unsigned char *cert_data; + uint32_t cert_data_size; + + if (!instance || !handshake_handle || !peer_credential_token) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + + ddsrt_mutex_lock(&impl->lock); + + 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, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + goto err_inv_handle; + } + + if (!(identity_cert = handshake->relation->remoteIdentity->identityCert)) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_OPERATION_NOT_PERMITTED_CODE, 0, DDS_SECURITY_ERR_OPERATION_NOT_PERMITTED_MESSAGE); + goto err_missing_attr; + } + + if (!(permissions_doc = handshake->relation->remoteIdentity->permissionsDocument)) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_MISSING_REMOTE_PERMISSIONS_DOCUMENT_CODE, 0, DDS_SECURITY_ERR_MISSING_REMOTE_PERMISSIONS_DOCUMENT_MESSAGE); + goto err_missing_attr; + } + + if (get_certificate_contents(identity_cert, &cert_data, &cert_data_size, ex) != DDS_SECURITY_VALIDATION_OK) + goto err_alloc_cid; + + memset(peer_credential_token, 0, sizeof(*peer_credential_token)); + peer_credential_token->class_id = get_authentication_class_id(); + peer_credential_token->properties._length = 2; + peer_credential_token->properties._buffer = DDS_Security_PropertySeq_allocbuf(peer_credential_token->properties._length); + peer_credential_token->properties._buffer[0].name = ddsrt_strdup("c.id"); + peer_credential_token->properties._buffer[0].value = (char *)cert_data; + peer_credential_token->properties._buffer[0].propagate = false; + peer_credential_token->properties._buffer[1].name = ddsrt_strdup("c.perm"); + peer_credential_token->properties._buffer[1].value = ddsrt_strdup(permissions_doc); + peer_credential_token->properties._buffer[1].propagate = false; + ddsrt_mutex_unlock(&impl->lock); + return true; + +err_alloc_cid: +err_missing_attr: +err_inv_handle: + ddsrt_mutex_unlock(&impl->lock); + return false; +} + +DDS_Security_boolean set_listener(dds_security_authentication *instance, const dds_security_authentication_listener *listener, DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(ex); + dds_security_authentication_impl *auth = (dds_security_authentication_impl *)instance; + if (listener) + dds_security_timed_dispatcher_enable(auth->timed_callbacks, auth->dispatcher, (void *)listener); + else + dds_security_timed_dispatcher_disable(auth->timed_callbacks, auth->dispatcher); + return true; +} + +DDS_Security_boolean return_identity_token(dds_security_authentication *instance, const DDS_Security_IdentityToken *token, DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(token); + DDSRT_UNUSED_ARG(ex); + DDSRT_UNUSED_ARG(instance); + return true; +} + +DDS_Security_boolean return_identity_status_token(dds_security_authentication *instance, const DDS_Security_IdentityStatusToken *token, DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(token); + DDSRT_UNUSED_ARG(ex); + DDSRT_UNUSED_ARG(instance); + return true; +} + +DDS_Security_boolean return_authenticated_peer_credential_token(dds_security_authentication *instance, const DDS_Security_AuthenticatedPeerCredentialToken *peer_credential_token, DDS_Security_SecurityException *ex) +{ + if (!instance || !peer_credential_token) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_PARAMETER_CODE, 0, DDS_SECURITY_ERR_INVALID_PARAMETER_MESSAGE); + return false; + } + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)peer_credential_token); + return true; +} + +DDS_Security_boolean return_handshake_handle(dds_security_authentication *instance, const DDS_Security_HandshakeHandle handshake_handle, DDS_Security_SecurityException *ex) +{ + dds_security_authentication_impl *impl = (dds_security_authentication_impl *)instance; + + if (!instance || !handshake_handle) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "return_handshake_handle: Invalid parameter provided"); + goto err_bad_param; + } + + ddsrt_mutex_lock(&impl->lock); + SecurityObject *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; + } + HandshakeInfo *handshake = (HandshakeInfo *)obj; + assert(handshake->relation); + (void)ddsrt_hh_remove(impl->objectHash, obj); + security_object_free((SecurityObject *)handshake); + ddsrt_mutex_unlock(&impl->lock); + return true; + +err_invalid_handle: + ddsrt_mutex_unlock(&impl->lock); +err_bad_param: + return false; +} + +static void invalidate_local_related_objects(dds_security_authentication_impl *impl, LocalIdentityInfo *localIdent) +{ + struct ddsrt_hh_iter it; + SecurityObject *obj; + + 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; + HandshakeInfo *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); + } + IdentityRelation *relation = find_identity_relation(remoteIdent, SECURITY_OBJECT_HANDLE(localIdent)); + if (relation) + remove_identity_relation(remoteIdent, relation); + } + } +} + +static void invalidate_remote_related_objects(dds_security_authentication_impl *impl, RemoteIdentityInfo *remoteIdentity) +{ + struct ddsrt_hh_iter it; + for (IdentityRelation *relation = ddsrt_hh_iter_first(remoteIdentity->linkHash, &it); relation != NULL; relation = ddsrt_hh_iter_next(&it)) + { + HandshakeInfo *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); + } +} + +DDS_Security_boolean return_identity_handle(dds_security_authentication *instance, const DDS_Security_IdentityHandle identity_handle, DDS_Security_SecurityException *ex) +{ + dds_security_authentication_impl *impl = (dds_security_authentication_impl *)instance; + SecurityObject *obj; + LocalIdentityInfo *localIdent; + RemoteIdentityInfo *remoteIdent; + + if (!instance || !identity_handle) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "return_identity_handle: Invalid parameter provided"); + goto err_bad_param; + } + + /* Currently the implementation of the handle does not provide information about the kind of handle. In this case a valid handle could refer to a LocalIdentityObject or a RemoteIdentityObject */ + ddsrt_mutex_lock(&impl->lock); + if (!(obj = security_object_find(impl->objectHash, identity_handle))) + { + DDS_Security_Exception_set(ex, DDS_AUTH_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, "return_identity_handle: Invalid handle provided"); + goto failed; + } + switch (obj->kind) + { + case SECURITY_OBJECT_KIND_LOCAL_IDENTITY: + 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_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"); + goto failed; + } + ddsrt_mutex_unlock(&impl->lock); + return true; + +failed: + ddsrt_mutex_unlock(&impl->lock); +err_bad_param: + return false; +} + +DDS_Security_boolean return_sharedsecret_handle(dds_security_authentication *instance, const DDS_Security_SharedSecretHandle sharedsecret_handle, DDS_Security_SecurityException *ex) +{ + DDSRT_UNUSED_ARG(sharedsecret_handle); + DDSRT_UNUSED_ARG(ex); + DDSRT_UNUSED_ARG(instance); + return true; +} + +int32_t init_authentication(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + DDSRT_UNUSED_ARG(argument); + dds_security_authentication_impl *authentication; + + authentication = (dds_security_authentication_impl *)ddsrt_malloc(sizeof(dds_security_authentication_impl)); + memset(authentication, 0, sizeof(dds_security_authentication_impl)); + authentication->base.gv = gv; + authentication->timed_callbacks = dds_security_timed_cb_new(); + authentication->dispatcher = dds_security_timed_dispatcher_new(authentication->timed_callbacks); + + 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.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.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_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); + memset(&authentication->trustedCAList, 0, sizeof(X509Seq)); + if (gv) + authentication->include_optional = gv->handshake_include_optional; + else + authentication->include_optional = true; + + dds_openssl_init (); + *context = authentication; + return 0; +} + +int32_t finalize_authentication(void *instance) +{ + dds_security_authentication_impl *authentication = instance; + if (authentication) + { + ddsrt_mutex_lock(&authentication->lock); + dds_security_timed_dispatcher_free(authentication->timed_callbacks, authentication->dispatcher); + dds_security_timed_cb_free(authentication->timed_callbacks); + if (authentication->remoteGuidHash) + ddsrt_hh_free(authentication->remoteGuidHash); + if (authentication->objectHash) + { + struct ddsrt_hh_iter it; + for (SecurityObject *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); + } + return 0; +} diff --git a/src/security/builtin_plugins/authentication/src/authentication.h b/src/security/builtin_plugins/authentication/src/authentication.h new file mode 100644 index 0000000..900d1eb --- /dev/null +++ b/src/security/builtin_plugins/authentication/src/authentication.h @@ -0,0 +1,50 @@ +/* + * 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 SECURITY_BUILTIN_PLUGINS_AUTHENTICATION_H_ +#define SECURITY_BUILTIN_PLUGINS_AUTHENTICATION_H_ + +#include "dds/ddsrt/atomics.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/export.h" + +SECURITY_EXPORT int32_t init_authentication(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int32_t finalize_authentication(void *context); + +DDS_Security_ValidationResult_t validate_local_identity(dds_security_authentication *instance, DDS_Security_IdentityHandle *local_identity_handle, DDS_Security_GUID_t *adjusted_participant_guid, + const DDS_Security_DomainId domain_id, const DDS_Security_Qos *participant_qos, const DDS_Security_GUID_t *candidate_participant_guid, DDS_Security_SecurityException *ex); +DDS_Security_boolean get_identity_token(dds_security_authentication *instance, DDS_Security_IdentityToken *identity_token, const DDS_Security_IdentityHandle handle, DDS_Security_SecurityException *ex); +DDS_Security_boolean set_permissions_credential_and_token(dds_security_authentication *instance, const DDS_Security_IdentityHandle handle, const DDS_Security_PermissionsCredentialToken *permissions_credential, + const DDS_Security_PermissionsToken *permissions_token, DDS_Security_SecurityException *ex); +DDS_Security_ValidationResult_t validate_remote_identity(dds_security_authentication *instance, DDS_Security_IdentityHandle *remote_identity_handle, DDS_Security_AuthRequestMessageToken *local_auth_request_token, + const DDS_Security_AuthRequestMessageToken *remote_auth_request_token, const DDS_Security_IdentityHandle local_identity_handle, const DDS_Security_IdentityToken *remote_identity_token, + const DDS_Security_GUID_t *remote_participant_guid, DDS_Security_SecurityException *ex); +DDS_Security_ValidationResult_t begin_handshake_request(dds_security_authentication *instance, DDS_Security_HandshakeHandle *handshake_handle, DDS_Security_HandshakeMessageToken *handshake_message, + const DDS_Security_IdentityHandle initiator_identity_handle, const DDS_Security_IdentityHandle replier_identity_handle, const DDS_Security_OctetSeq *serialized_local_participant_data, DDS_Security_SecurityException *ex); +DDS_Security_ValidationResult_t begin_handshake_reply(dds_security_authentication *instance, DDS_Security_HandshakeHandle *handshake_handle, DDS_Security_HandshakeMessageToken *handshake_message_out, + const DDS_Security_HandshakeMessageToken *handshake_message_in, const DDS_Security_IdentityHandle initiator_identity_handle, const DDS_Security_IdentityHandle replier_identity_handle, + const DDS_Security_OctetSeq *serialized_local_participant_data, DDS_Security_SecurityException *ex); +DDS_Security_ValidationResult_t process_handshake(dds_security_authentication *instance, DDS_Security_HandshakeMessageToken *handshake_message_out, const DDS_Security_HandshakeMessageToken *handshake_message_in, + const DDS_Security_HandshakeHandle handshake_handle, DDS_Security_SecurityException *ex); +DDS_Security_SharedSecretHandle get_shared_secret(dds_security_authentication *instance, const DDS_Security_HandshakeHandle handshake_handle, DDS_Security_SecurityException *ex); +DDS_Security_boolean get_authenticated_peer_credential_token(dds_security_authentication *instance, DDS_Security_AuthenticatedPeerCredentialToken *peer_credential_token, + const DDS_Security_HandshakeHandle handshake_handle, DDS_Security_SecurityException *ex); +DDS_Security_boolean get_identity_status_token(dds_security_authentication *instance, DDS_Security_IdentityStatusToken *identity_status_token, const DDS_Security_IdentityHandle handle, DDS_Security_SecurityException *ex); +DDS_Security_boolean set_listener(dds_security_authentication *instance, const dds_security_authentication_listener *listener, DDS_Security_SecurityException *ex); +DDS_Security_boolean return_identity_token(dds_security_authentication *instance, const DDS_Security_IdentityToken *token, DDS_Security_SecurityException *ex); +DDS_Security_boolean return_identity_status_token(dds_security_authentication *instance, const DDS_Security_IdentityStatusToken *token, DDS_Security_SecurityException *ex); +DDS_Security_boolean return_authenticated_peer_credential_token(dds_security_authentication *instance, const DDS_Security_AuthenticatedPeerCredentialToken *peer_credential_token, DDS_Security_SecurityException *ex); +DDS_Security_boolean return_handshake_handle(dds_security_authentication *instance, const DDS_Security_HandshakeHandle handshake_handle, DDS_Security_SecurityException *ex); +DDS_Security_boolean return_identity_handle(dds_security_authentication *instance, const DDS_Security_IdentityHandle identity_handle, DDS_Security_SecurityException *ex); +DDS_Security_boolean return_sharedsecret_handle(dds_security_authentication *instance, const DDS_Security_SharedSecretHandle sharedsecret_handle, DDS_Security_SecurityException *ex); + +#endif /* SECURITY_BUILTIN_PLUGINS_AUTHENTICATION_H_ */ diff --git a/src/security/builtin_plugins/cryptographic/CMakeLists.txt b/src/security/builtin_plugins/cryptographic/CMakeLists.txt new file mode 100644 index 0000000..7fac1df --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/CMakeLists.txt @@ -0,0 +1,56 @@ +# +# Copyright(c) 2006 to 2019 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +include (GenerateExportHeader) + +PREPEND(srcs_cryptographic "${CMAKE_CURRENT_LIST_DIR}/src" + crypto_cipher.c + crypto_key_exchange + crypto_key_factory.c + crypto_objects.c + crypto_transform.c + crypto_utils.c + cryptography.c +) + +add_library(dds_security_crypto SHARED "") + +generate_export_header( + dds_security_crypto + BASE_NAME SECURITY + EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/include/dds/security/export.h" +) + +target_link_libraries(dds_security_crypto PRIVATE security_openssl) +target_link_libraries(dds_security_crypto PUBLIC ddsc) +target_link_libraries(dds_security_crypto PUBLIC OpenSSL::SSL) +if(CMAKE_GENERATOR MATCHES "Visual Studio") + set_target_properties(dds_security_crypto PROPERTIES LINK_FLAGS "/ignore:4099") +endif() +target_sources(dds_security_crypto PRIVATE ${srcs_cryptographic}) + +target_include_directories(dds_security_crypto + PUBLIC + "$>" + "$>" + "$>" + "$>" + "$" + "$" +) + +install( + TARGETS dds_security_crypto + EXPORT "${PROJECT_NAME}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" COMPONENT lib + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT lib +) diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_cipher.c b/src/security/builtin_plugins/cryptographic/src/crypto_cipher.c new file mode 100644 index 0000000..a870699 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_cipher.c @@ -0,0 +1,258 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/types.h" +#include "dds/security/openssl_support.h" +#include "crypto_defs.h" +#include "crypto_utils.h" +#include "crypto_cipher.h" + +bool crypto_cipher_encrypt_data( + const crypto_session_key_t *session_key, + uint32_t key_size, + const unsigned char *iv, + const unsigned char *data, + uint32_t data_len, + const unsigned char *aad, + uint32_t aad_len, + unsigned char *encrypted, + uint32_t *encrypted_len, + crypto_hmac_t *tag, + DDS_Security_SecurityException *ex) +{ + EVP_CIPHER_CTX *ctx; + int len = 0; + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_CIPHER_CTX_new failed: "); + goto fail_ctx_new; + } + + /* initialize the cipher and set to AES GCM */ + if (key_size == 128) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptInit_ex to set aes_128_gcm failed: "); + goto fail_encrypt; + } + } + else if (key_size == 256) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptInit_ex to set aes_256_gcm failed: "); + goto fail_encrypt; + } + } + else + { + assert(0); + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptInit_ex invalid key size: %u", key_size); + goto fail_encrypt; + } + + /* Initialise key and IV */ + if (!EVP_EncryptInit_ex(ctx, NULL, NULL, session_key->data, iv)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptInit_ex failed: "); + goto fail_encrypt; + } + + if (aad) + { + if (aad_len > INT_MAX) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptUpdate to update aad failed: aad_len exceeds INT_MAX"); + goto fail_encrypt; + } + + /* Provide any AAD data */ + if (!EVP_EncryptUpdate(ctx, NULL, &len, aad, (int) aad_len)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptUpdate to update aad failed: %s"); + goto fail_encrypt; + } + } + + if (data) + { + if (data_len > INT_MAX) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptUpdate to update data failed: data_len exceeds INT_MAX"); + goto fail_encrypt; + } + + /* encrypt the message */ + if (!EVP_EncryptUpdate(ctx, encrypted, &len, data, (int) data_len)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptUpdate update data failed: "); + goto fail_encrypt; + } + assert (len >= 0); /* conform openssl spec */ + *encrypted_len = (uint32_t) len; + } + + /* finalize the encryption */ + if (data) + { + if (!EVP_EncryptFinal_ex(ctx, encrypted + len, &len)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptFinal_ex to finalize encryption failed: "); + goto fail_encrypt; + } + assert (len >= 0); /* conform openssl spec */ + *encrypted_len += (uint32_t) len; + } + else + { + unsigned char temp[32]; + if (!EVP_EncryptFinal_ex(ctx, temp, &len)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_EncryptFinal_ex to finalize aad failed: "); + goto fail_encrypt; + } + } + + /* get the tag */ + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, CRYPTO_HMAC_SIZE, tag->data)) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_CIPHER_CTX_ctrl to get the tag failed: "); + goto fail_encrypt; + } + + EVP_CIPHER_CTX_free(ctx); + return true; + +fail_encrypt: + EVP_CIPHER_CTX_free(ctx); +fail_ctx_new: + return false; +} + +bool crypto_cipher_decrypt_data( + const remote_session_info *session, + const unsigned char *iv, + const unsigned char *encrypted, + uint32_t encrypted_len, + const unsigned char *aad, + uint32_t aad_len, + unsigned char *data, + uint32_t *data_len, + crypto_hmac_t *tag, + DDS_Security_SecurityException *ex) +{ + EVP_CIPHER_CTX *ctx; + int len = 0; + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_CIPHER_CTX_new failed: "); + goto fail_ctx_new; + } + + /* initialize the cipher and set to AES GCM */ + if (session->key_size == 128) + { + if (EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_DecryptInit_ex to set aes_128_gcm failed: "); + goto fail_decrypt; + } + } + else if (session->key_size == 256) + { + if (EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) != 1) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_DecryptInit_ex to set aes_256_gcm failed: "); + goto fail_decrypt; + } + } + else + { + assert(0); + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "Internal key_size is not correct: %u", session->key_size); + goto fail_decrypt; + } + + /* Initialise key and IV */ + if (EVP_DecryptInit_ex(ctx, NULL, NULL, session->key.data, iv) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_DecryptInit_ex to set aes_256_gcm failed: %s"); + goto fail_decrypt; + } + + if (aad) + { + assert (aad_len <= INT32_MAX); + /* Provide any AAD data for signature */ + if (EVP_DecryptUpdate(ctx, NULL, &len, aad, (int) aad_len) != 1) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_DecryptUpdate to update aad failed: "); + goto fail_decrypt; + } + } + + /* Set expected tag value. */ + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, CRYPTO_HMAC_SIZE, tag->data) != 1) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_CIPHER_CTX_ctrl to get tag failed: "); + goto fail_decrypt; + } + + if (data) + { + /* decrypt the message */ + if (EVP_DecryptUpdate(ctx, data, &len, encrypted, (int) encrypted_len) != 1) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_DecryptUpdate update data failed: "); + goto fail_decrypt; + } + assert (len >= 0); + *data_len = (uint32_t)len; + } + + if (data) + { + if (EVP_DecryptFinal_ex(ctx, data + len, &len) != 1) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_DecryptFinal_ex to finalize decryption failed: "); + goto fail_decrypt; + } + assert (len >= 0); + *data_len += (uint32_t)len; + } + else + { + unsigned char temp[32]; + if (EVP_DecryptFinal_ex(ctx, temp, &len) != 1) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "EVP_DecryptFinal_ex to finalize signature check failed: "); + goto fail_decrypt; + } + } + + EVP_CIPHER_CTX_free(ctx); + return true; + +fail_decrypt: + EVP_CIPHER_CTX_free(ctx); +fail_ctx_new: + return false; +} diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_cipher.h b/src/security/builtin_plugins/cryptographic/src/crypto_cipher.h new file mode 100644 index 0000000..eb365b9 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_cipher.h @@ -0,0 +1,99 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTO_CIPHER_H +#define CRYPTO_CIPHER_H + +#include "dds/ddsrt/types.h" +#include "crypto_objects.h" + +/** + * @brief Encodes the provide data using the provided key + * + * This function encodes the provide data using the provided key, key_size + * and initialization_vector. It also computes the common_mac from the provided data. + * The data parameter contains the data that has to encoded. The aad parameter contains + * the data that is not encoded but is used in the computation of the common_mac + * On return the encrypted parameter contains the encoded data and the tag parameter + * the common mac. + * This function will be used either to encode the provided data in that case the + * data parameter should be set to the data to be encoded and the aad parameter should + * be NULL. Also the encrypted parameter should be set and contain a buffer large enough + * to contain the encoded data. + * This function is also used to only computer the common_mac. In that case the + * data parameter should be NULL and the aad parameter should point to the data on + * which the common_mac has to be computed. The encryped parameter is not relevant + * in this case. + * + * @param[in] session_key The session key used to encode the provided data + * @param[in] key_size The size of the session key (128 or 256 bit) + * @param[in] iv The init vector used by the encoding + * @param[in] data The data to be encoded + * @param[in] data_len The size of the data to be encoded + * @param[in] aad The additional data not be encoded but only used in the computation of the mac + * @param[in] aad_len The size of the additional data + * @param[in,out] encrypted The buffer to hold on return the encoded data + * @param[in,out] encrypted_len The size of the encrypted data buffer + * @param[in,out] tag Contains on return the mac value calculated over the provided data + * @param[in,out] ex Security exception (optional) + */ +bool crypto_cipher_encrypt_data( + const crypto_session_key_t *session_key, + uint32_t key_size, + const unsigned char *iv, + const unsigned char *data, + uint32_t data_len, + const unsigned char *aad, + uint32_t aad_len, + unsigned char *encrypted, + uint32_t *encrypted_len, + crypto_hmac_t *tag, + DDS_Security_SecurityException *ex); + +/** + * @brief Decodes the provided data using the session key and key_size + * + * This function decodes the provided data using the session key and key_size provided + * by by the session parameter. The iv parameter contains the initialization_vector used + * by the decode operation which is the concatination of received session_id and init_vector_suffix. + * The function checks if the common_mac (tag parameter) is corresponds with the provided data. + * This function will be used either to decode the provided data in that case the + * encrypted parameter should be set to the data to be decoded and the aad parameter should + * be NULL. Also the data parameter should be set and contain a buffer large enough + * to contain the decoded data. + * This function is also used to only verify the common_mac. In that case the + * data and the encrypted parameter should be NULL and the aad parameter should point to + * the data for which the common_mac has to be verified. + * + * @param[in] session Contains the session key and key size used of the decoding + * @param[in] iv The init vector used by the decoding + * @param[in] encrypted The encoded data + * @param[in] encrypted_len The size of the encoded data + * @param[in] aad The not encoded data used in the verification of the provided mac + * @param[in] aad_len The size of the additional data + * @param[in,out] data The buffer to hold on return the decoded data + * @param[in,out] data_len The size of the decoded data buffer + * @param[in,out] tag The mac value which has to be verified + * @param[in,out] ex Security exception (optional) + */ +bool crypto_cipher_decrypt_data( + const remote_session_info *session, + const unsigned char *iv, + const unsigned char *encrypted, + uint32_t encrypted_len, + const unsigned char *aad, + uint32_t aad_len, + unsigned char *data, + uint32_t *data_len, + crypto_hmac_t *tag, + DDS_Security_SecurityException *ex); + +#endif /* CRYPTO_CIPHER_H */ diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_defs.h b/src/security/builtin_plugins/cryptographic/src/crypto_defs.h new file mode 100644 index 0000000..0d2a983 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_defs.h @@ -0,0 +1,122 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTO_DEFS_H +#define CRYPTO_DEFS_H + +#include "dds/security/core/dds_security_types.h" +#include "dds/security/dds_security_api.h" + + +#define DDS_CRYPTO_PLUGIN_CONTEXT "Cryptographic" + +#define CRYPTO_HMAC_SIZE 16 +#define CRYPTO_KEY_SIZE_128 16 +#define CRYPTO_KEY_SIZE_256 32 +#define CRYPTO_KEY_SIZE_MAX CRYPTO_KEY_SIZE_256 + +#define CRYPTO_SESSION_ID_SIZE 4 +#define CRYPTO_INIT_VECTOR_SUFFIX_SIZE 8 +#define CRYPTO_CIPHER_BLOCK_SIZE 16 + +typedef enum SecureSubmsgKind_t +{ + SMID_SEC_BODY_KIND = 0x30, + SMID_SEC_PREFIX_KIND = 0x31, + SMID_SEC_POSTFIX_KIND = 0x32, + SMID_SRTPS_PREFIX_KIND = 0x33, + SMID_SRTPS_POSTFIX_KIND = 0x34, + SMID_SRTPS_INFO_SRC_KIND = 0x0c +} SecureSubmsgKind_t; + +typedef struct crypto_session_key_t +{ + unsigned char data[CRYPTO_KEY_SIZE_MAX]; +} crypto_session_key_t; + +typedef struct crypto_hmac_t +{ + unsigned char data[CRYPTO_HMAC_SIZE]; +} crypto_hmac_t; + +typedef enum RTPS_Message_Type +{ + /** The Constant PAD. */ + RTPS_Message_Type_PAD = 0x01, + + /** The Constant ACKNACK. */ + RTPS_Message_Type_ACKNACK = 0x06, + + /** The Constant HEARTBEAT. */ + RTPS_Message_Type_HEARTBEAT = 0x07, + + /** The Constant GAP. */ + RTPS_Message_Type_GAP = 0x08, + + /** The Constant INFO_TS. */ + RTPS_Message_Type_INFO_TS = 0x09, + + /** The Constant INFO_SRC. */ + RTPS_Message_Type_INFO_SRC = 0x0c, + + /** The Constant INFO_REPLY_IP4. */ + RTPS_Message_Type_INFO_REPLY_IP4 = 0x0d, + + /** The Constant INFO_DST. */ + RTPS_Message_Type_INFO_DST = 0x0e, + + /** The Constant INFO_REPLY. */ + RTPS_Message_Type_INFO_REPLY = 0x0f, + + /** The Constant NACK_FRAG. */ + RTPS_Message_Type_NACK_FRAG = 0x12, + + /** The Constant HEARTBEAT_FRAG. */ + RTPS_Message_Type_HEARTBEAT_FRAG = 0x13, + + /** The Constant DATA. */ + RTPS_Message_Type_DATA = 0x15, + + /** The Constant DATA_FRAG. */ + RTPS_Message_Type_DATA_FRAG = 0x16, + + /** The Constant MSG_LENGTH. */ + RTPS_Message_Type_MSG_LEN = 0x81, + + /** The Constant MSG_ENTITY_ID. */ + RTPS_Message_Type_MSG_ENTITY_ID = 0x82, + + /** The Constant INFO_LASTHB. */ + RTPS_Message_Type_INFO_LASTHB = 0x83, + + /** The Constant SEC_PREFIX. */ + RTPS_Message_Type_SEC_BODY = 0x30, + + /** The Constant SEC_PREFIX. */ + RTPS_Message_Type_SEC_PREFIX = 0x31, + + /** The Constant SEC_POSTFIX. */ + RTPS_Message_Type_SEC_POSTFIX = 0x32, + + /** The Constant SRTPS_PREFIX. */ + RTPS_Message_Type_SRTPS_PREFIX = 0x33, + + /** The Constant SRTPS_POSTFIX. */ + RTPS_Message_Type_SRTPS_POSTFIX = 0x34 +} RTPS_Message_Type; + +struct receiver_specific_mac +{ + DDS_Security_CryptoTransformKeyId receiver_mac_key_id; + crypto_hmac_t receiver_mac; +}; + +#endif /* CRYPTO_DEFS_H */ diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.c b/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.c new file mode 100644 index 0000000..7cadb64 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.c @@ -0,0 +1,586 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/dds_security_serialize.h" +#include "crypto_defs.h" +#include "crypto_utils.h" +#include "cryptography.h" +#include "crypto_key_exchange.h" +#include "crypto_key_factory.h" + +static const char *CRYPTO_TOKEN_CLASS_ID = "DDS:Crypto:AES_GCM_GMAC"; +static const char *CRYPTO_TOKEN_PROPERTY_NAME = "dds.cryp.keymat"; + +/** + * Implementation structure for storing encapsulated members of the instance + * while giving only the interface definition to user + */ + +typedef struct dds_security_crypto_key_exchange_impl +{ + dds_security_crypto_key_exchange base; + const dds_security_cryptography *crypto; +} dds_security_crypto_key_exchange_impl; + +static bool check_crypto_tokens(const DDS_Security_DataHolderSeq *tokens) +{ + bool status = true; + uint32_t i; + + if (tokens->_length == 0 || tokens->_buffer == NULL) + status = false; + + for (i = 0; status && (i < tokens->_length); i++) + { + status = (tokens->_buffer[i].class_id != NULL) && + (strcmp(CRYPTO_TOKEN_CLASS_ID, tokens->_buffer[i].class_id) == 0) && + (tokens->_buffer[i].binary_properties._length == 1) && + (tokens->_buffer[i].binary_properties._buffer != NULL) && + (tokens->_buffer[i].binary_properties._buffer[0].name != NULL) && + (strcmp(CRYPTO_TOKEN_PROPERTY_NAME, tokens->_buffer[i].binary_properties._buffer[0].name) == 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._length > 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._buffer != NULL); + } + + return status; +} + +static bool check_not_data_empty(const DDS_Security_OctetSeq *seq) +{ + uint32_t i; + + for (i = 0; i < seq->_length; i++) + { + if (seq->_buffer[i] != 0) + return true; + } + return false; +} + +static bool check_crypto_keymaterial( + const dds_security_crypto_key_exchange_impl *impl, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat, + const int64_t handle) +{ + bool status = false; + uint32_t transform_kind = CRYPTO_TRANSFORM_KIND(keymat->transformation_kind); + + if (transform_kind != CRYPTO_TRANSFORMATION_KIND_NONE) + { + if (transform_kind <= CRYPTO_TRANSFORMATION_KIND_AES256_GCM) + { + uint32_t key_sz = CRYPTO_KEY_SIZE_BYTES(transform_kind); + status = (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; +} + +// serialized_key_material +// { +// uint32_t transformation_kind +// uint32_t master_salt_len +// uint8_t[SALT_SIZE] master_salt +// uint32_t sender_key_id +// uint32_t master_sender_key_len +// uint8_t[KEY_SIZE] master_sender_key +// uint32_t receiver_specific_key_id +// uint32_t master_receiver_specific_key_len +// uint8_t[KEY_SIZE] master_receiver_specific_key +// } +static void +serialize_master_key_material( + const master_key_material *keymat, + uint8_t **buffer, + uint32_t *length) +{ + uint32_t *sd; + size_t i = 0; + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(keymat->transformation_kind); + size_t sz = 6 * sizeof (uint32_t) + 2 * key_bytes; + if (keymat->receiver_specific_key_id) + sz += key_bytes; + *buffer = ddsrt_malloc(sz); + *length = (uint32_t)sz; + sd = (uint32_t *)(*buffer); + + sd[i++] = ddsrt_toBE4u(keymat->transformation_kind); + sd[i++] = ddsrt_toBE4u(key_bytes); + memcpy(&sd[i], keymat->master_salt, key_bytes); + i += key_bytes / sizeof (uint32_t); + sd[i++] = ddsrt_toBE4u(keymat->sender_key_id); + sd[i++] = ddsrt_toBE4u(key_bytes); + memcpy(&sd[i], keymat->master_sender_key, key_bytes); + i += key_bytes / sizeof (uint32_t); + sd[i++] = ddsrt_toBE4u(keymat->receiver_specific_key_id); + if (keymat->receiver_specific_key_id) + { + sd[i++] = ddsrt_toBE4u(key_bytes); + memcpy(&sd[i], keymat->master_receiver_specific_key, key_bytes); + } + else + { + sd[i++] = ddsrt_toBE4u(0); + } +} + + +/** + * Function implementations + */ +static DDS_Security_boolean +create_local_participant_crypto_tokens( + dds_security_crypto_key_exchange *instance, + DDS_Security_ParticipantCryptoTokenSeq *tokens, + const DDS_Security_ParticipantCryptoHandle local_id, + const DDS_Security_ParticipantCryptoHandle remote_id, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_exchange_impl *impl = (dds_security_crypto_key_exchange_impl *)instance; + dds_security_crypto_key_factory *factory; + participant_key_material *pp_key_material; + uint8_t *buffer; + uint32_t length; + + if (!instance || !tokens || local_id == 0 || remote_id == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "create_local_participant_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_invalid_arg; + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + if (!crypto_factory_get_participant_crypto_tokens(factory, local_id, remote_id, &pp_key_material, NULL, NULL, ex)) + goto fail_invalid_arg; + serialize_master_key_material(pp_key_material->local_P2P_key_material, &buffer, &length); + CRYPTO_OBJECT_RELEASE(pp_key_material); + + tokens->_buffer = DDS_Security_DataHolderSeq_allocbuf(1); + tokens->_length = tokens->_maximum = 1; + tokens->_buffer[0].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + tokens->_buffer[0].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + tokens->_buffer[0].binary_properties._length = tokens->_buffer[0].binary_properties._maximum = 1; + tokens->_buffer[0].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + tokens->_buffer[0].binary_properties._buffer[0].value._length = + tokens->_buffer[0].binary_properties._buffer[0].value._maximum = length; + tokens->_buffer[0].binary_properties._buffer[0].value._buffer = buffer; + 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, + const DDS_Security_ParticipantCryptoHandle local_id, + const DDS_Security_ParticipantCryptoHandle remote_id, + const DDS_Security_ParticipantCryptoTokenSeq *tokens, + DDS_Security_SecurityException *ex) +{ + DDS_Security_boolean result = false; + dds_security_crypto_key_exchange_impl *impl = (dds_security_crypto_key_exchange_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_KeyMaterial_AES_GCM_GMAC remote_key_mat; + const DDS_Security_OctetSeq *tdata; + DDS_Security_Deserializer deserializer; + + if (!instance || !tokens || local_id == 0 || remote_id == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "set_remote_participant_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + if (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, + "set_remote_participant_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + tdata = &tokens->_buffer[0].binary_properties._buffer[0].value; + + deserializer = DDS_Security_Deserializer_new(tdata->_buffer, tdata->_length); + if (!deserializer) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, + "set_remote_participant_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); + result = false; + } + else if (!DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC(deserializer, &remote_key_mat)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, + "set_remote_participant_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); + result = false; + } + else if (!check_crypto_keymaterial(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); + result = false; + } + else + { + factory = cryptography_get_crypto_key_factory(impl->crypto); + result = crypto_factory_set_participant_crypto_tokens(factory, local_id, remote_id, &remote_key_mat, ex); + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&remote_key_mat); + } + + DDS_Security_Deserializer_free(deserializer); + + return result; +} + +static DDS_Security_boolean +create_local_datawriter_crypto_tokens( + dds_security_crypto_key_exchange *instance, + DDS_Security_DatawriterCryptoTokenSeq *tokens, + const DDS_Security_DatawriterCryptoHandle local_writer_handle, + const DDS_Security_DatareaderCryptoHandle remote_reader_handle, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_exchange_impl *impl = (dds_security_crypto_key_exchange_impl *)instance; + dds_security_crypto_key_factory *factory; + master_key_material *key_mat[2]; + uint32_t num_key_mat = 2; + uint32_t i; + + if (!instance || !tokens || local_writer_handle == DDS_SECURITY_HANDLE_NIL || remote_reader_handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "create_local_datawriter_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + if (!crypto_factory_get_datawriter_crypto_tokens(factory, local_writer_handle, remote_reader_handle, key_mat, &num_key_mat, ex)) + return false; + + tokens->_length = tokens->_maximum = num_key_mat; + tokens->_buffer = (num_key_mat > 0) ? DDS_Security_DataHolderSeq_allocbuf(num_key_mat) : NULL; + + for (i = 0; i < num_key_mat; i++) + { + uint8_t *buffer; + uint32_t length; + + serialize_master_key_material(key_mat[i], &buffer, &length); + + tokens->_buffer[i].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + tokens->_buffer[i].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + tokens->_buffer[i].binary_properties._length = tokens->_buffer[0].binary_properties._maximum = 1; + tokens->_buffer[i].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + tokens->_buffer[i].binary_properties._buffer[0].value._length = + tokens->_buffer[i].binary_properties._buffer[0].value._maximum = length; + tokens->_buffer[i].binary_properties._buffer[0].value._buffer = buffer; + tokens->_buffer[i].binary_properties._buffer[0].propagate = true; + CRYPTO_OBJECT_RELEASE(key_mat[i]); + } + + return true; +} + +static DDS_Security_boolean +set_remote_datawriter_crypto_tokens( + dds_security_crypto_key_exchange *instance, + const DDS_Security_DatareaderCryptoHandle local_reader_handle, + const DDS_Security_DatawriterCryptoHandle remote_writer_handle, + const DDS_Security_DatawriterCryptoTokenSeq *tokens, + DDS_Security_SecurityException *ex) +{ + DDS_Security_boolean result = true; + dds_security_crypto_key_exchange_impl *impl = (dds_security_crypto_key_exchange_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_KeyMaterial_AES_GCM_GMAC remote_key_mat[2]; + uint32_t i; + + if (!instance || !tokens || local_reader_handle == DDS_SECURITY_HANDLE_NIL || remote_writer_handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "set_remote_datawriter_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + if (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, + "set_remote_datawriter_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + if (tokens->_length > 2) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "set_remote_datawriter_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + for (i = 0; result && (i < tokens->_length); i++) + { + const DDS_Security_OctetSeq *tdata = &tokens->_buffer[i].binary_properties._buffer[0].value; + DDS_Security_Deserializer deserializer = DDS_Security_Deserializer_new(tdata->_buffer, tdata->_length); + if (!deserializer) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, + "set_remote_datawriter_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); + result = false; + } + else if (!DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC(deserializer, &remote_key_mat[i])) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, + "set_remote_datawriter_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); + result = false; + } + else if (!check_crypto_keymaterial(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); + result = false; + } + DDS_Security_Deserializer_free(deserializer); + } + + if (result) + { + factory = cryptography_get_crypto_key_factory(impl->crypto); + result = crypto_factory_set_datawriter_crypto_tokens(factory, local_reader_handle, remote_writer_handle, remote_key_mat, tokens->_length, ex); + } + + for (i = 0; i < tokens->_length; i++) + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&remote_key_mat[i]); + + return result; +} + +static DDS_Security_boolean +create_local_datareader_crypto_tokens( + dds_security_crypto_key_exchange *instance, + DDS_Security_DatareaderCryptoTokenSeq *tokens, + const DDS_Security_DatareaderCryptoHandle local_reader_handle, + const DDS_Security_DatawriterCryptoHandle remote_writer_handle, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_exchange_impl *impl = (dds_security_crypto_key_exchange_impl *)instance; + dds_security_crypto_key_factory *factory; + master_key_material *key_mat = NULL; + uint8_t *buffer; + uint32_t length; + + if (!instance || !tokens || local_reader_handle == DDS_SECURITY_HANDLE_NIL || remote_writer_handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "create_local_datareader_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + if (!crypto_factory_get_datareader_crypto_tokens(factory, local_reader_handle, remote_writer_handle, &key_mat, ex)) + return false; + + if (key_mat != NULL) + { /* there may be no keymaterial according to configuration */ + + serialize_master_key_material(key_mat, &buffer, &length); + + tokens->_buffer = DDS_Security_DataHolderSeq_allocbuf(1); + tokens->_length = tokens->_maximum = 1; + + tokens->_buffer[0].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + tokens->_buffer[0].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + tokens->_buffer[0].binary_properties._length = tokens->_buffer[0].binary_properties._maximum = 1; + tokens->_buffer[0].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + tokens->_buffer[0].binary_properties._buffer[0].value._length = + tokens->_buffer[0].binary_properties._buffer[0].value._maximum = length; + tokens->_buffer[0].binary_properties._buffer[0].value._buffer = buffer; + tokens->_buffer[0].binary_properties._buffer[0].propagate = true; + + CRYPTO_OBJECT_RELEASE(key_mat); + } + else + { + tokens->_buffer = NULL; + tokens->_length = 0; + tokens->_maximum = 0; + } + + return true; +} + +static DDS_Security_boolean +set_remote_datareader_crypto_tokens( + dds_security_crypto_key_exchange *instance, + const DDS_Security_DatawriterCryptoHandle local_writer_handle, + const DDS_Security_DatareaderCryptoHandle remote_reader_handle, + const DDS_Security_DatareaderCryptoTokenSeq *tokens, + DDS_Security_SecurityException *ex) +{ + DDS_Security_boolean result = false; + dds_security_crypto_key_exchange_impl *impl = (dds_security_crypto_key_exchange_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_KeyMaterial_AES_GCM_GMAC remote_key_mat; + const DDS_Security_OctetSeq *tdata; + DDS_Security_Deserializer deserializer; + + if (!instance || !tokens || local_writer_handle == DDS_SECURITY_HANDLE_NIL || remote_reader_handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "set_remote_datareader_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + if (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, + "set_remote_datareader_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + tdata = &tokens->_buffer[0].binary_properties._buffer[0].value; + + deserializer = DDS_Security_Deserializer_new(tdata->_buffer, tdata->_length); + if (!deserializer) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, + "set_remote_datareader_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); + result = false; + } + else if (!DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC(deserializer, &remote_key_mat)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_CODE, 0, + "set_remote_datareader_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_TOKEN_MESSAGE); + result = false; + } + else if (!check_crypto_keymaterial(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); + result = false; + } + else + { + factory = cryptography_get_crypto_key_factory(impl->crypto); + result = crypto_factory_set_datareader_crypto_tokens(factory, local_writer_handle, remote_reader_handle, &remote_key_mat, ex); + } + + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&remote_key_mat); + + DDS_Security_Deserializer_free(deserializer); + + return result; +} + +static DDS_Security_boolean +return_crypto_tokens( + dds_security_crypto_key_exchange *instance, + DDS_Security_CryptoTokenSeq *tokens, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_exchange_impl *impl = (dds_security_crypto_key_exchange_impl *)instance; + + if (!impl || !tokens) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "return_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_invalid_arg; + } + + if (!check_crypto_tokens(tokens)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "set_remote_participant_crypto_tokens: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_invalid_arg; + } + + DDS_Security_CryptoTokenSeq_freebuf(tokens); + memset(tokens, 0, sizeof(*tokens)); + return true; + +fail_invalid_arg: + return false; +} + +dds_security_crypto_key_exchange * +dds_security_crypto_key_exchange__alloc( + const dds_security_cryptography *crypto) +{ + dds_security_crypto_key_exchange_impl *instance = ddsrt_malloc(sizeof(*instance)); + instance->crypto = crypto; + instance->base.create_local_participant_crypto_tokens = &create_local_participant_crypto_tokens; + instance->base.set_remote_participant_crypto_tokens = &set_remote_participant_crypto_tokens; + instance->base.create_local_datawriter_crypto_tokens = &create_local_datawriter_crypto_tokens; + instance->base.set_remote_datawriter_crypto_tokens = &set_remote_datawriter_crypto_tokens; + instance->base.create_local_datareader_crypto_tokens = &create_local_datareader_crypto_tokens; + instance->base.set_remote_datareader_crypto_tokens = &set_remote_datareader_crypto_tokens; + instance->base.return_crypto_tokens = &return_crypto_tokens; + return (dds_security_crypto_key_exchange *)instance; +} + +void dds_security_crypto_key_exchange__dealloc( + dds_security_crypto_key_exchange *instance) +{ + ddsrt_free(instance); +} diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.h b/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.h new file mode 100644 index 0000000..c1852b3 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_key_exchange.h @@ -0,0 +1,27 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTO_KEY_EXCHANGE_H +#define CRYPTO_KEY_EXCHANGE_H + +#include "dds/security/dds_security_api.h" + +/** + * @brief Allocation function for implementer structure (with internal variables) transparently. + */ +dds_security_crypto_key_exchange * +dds_security_crypto_key_exchange__alloc( + const dds_security_cryptography *crypto); + +void dds_security_crypto_key_exchange__dealloc( + dds_security_crypto_key_exchange *instance); + +#endif /* CRYPTO_KEY_EXCHANGE_H */ diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.c b/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.c new file mode 100644 index 0000000..7a04865 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.c @@ -0,0 +1,2054 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include + +#include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsi/q_gc.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "crypto_defs.h" +#include "crypto_utils.h" +#include "crypto_cipher.h" +#include "crypto_key_factory.h" +#include "crypto_objects.h" + +/** + * Implementation structure for storing encapsulated members of the instance + * while giving only the interface definition to user + */ + +#define KXKEYCOOKIE "key exchange key" +#define KXKEYCOOKIE_SIZE (sizeof(KXKEYCOOKIE) - 1) +#define KXSALTCOOKIE "keyexchange salt" +#define KXSALTCOOKIE_SIZE (sizeof(KXSALTCOOKIE) - 1) + +typedef struct dds_security_crypto_key_factory_impl +{ + dds_security_crypto_key_factory base; + const dds_security_cryptography *crypto; + ddsrt_mutex_t lock; + struct CryptoObjectTable *crypto_objects; /* table for storing CryptoHandle - ParticipantKeyMaterial pairs */ + ddsrt_atomic_uint32_t next_key_id; +} dds_security_crypto_key_factory_impl; + +static void +crypto_token_copy( + master_key_material *dst, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *src) +{ + DDS_Security_CryptoTransformKind_Enum src_transform_kind = CRYPTO_TRANSFORM_KIND(src->transformation_kind); + + if (CRYPTO_TRANSFORM_HAS_KEYS(dst->transformation_kind)) + { + ddsrt_free(dst->master_salt); + ddsrt_free(dst->master_sender_key); + ddsrt_free(dst->master_receiver_specific_key); + } + if (CRYPTO_TRANSFORM_HAS_KEYS(src_transform_kind)) + { + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(src_transform_kind); + dst->master_salt = ddsrt_calloc(1, key_bytes); + dst->master_sender_key = ddsrt_calloc(1, key_bytes); + dst->master_receiver_specific_key = ddsrt_calloc(1, key_bytes); + memcpy(dst->master_salt, src->master_salt._buffer, key_bytes); + dst->sender_key_id = CRYPTO_TRANSFORM_ID(src->sender_key_id); + memcpy(dst->master_sender_key, src->master_sender_key._buffer, key_bytes); + dst->receiver_specific_key_id = CRYPTO_TRANSFORM_ID(src->receiver_specific_key_id); + if (dst->receiver_specific_key_id) + memcpy(dst->master_receiver_specific_key, src->master_receiver_specific_key._buffer, key_bytes); + } + dst->transformation_kind = src_transform_kind; +}; + +/* Compute KeyMaterial_AES_GCM_GMAC as described in DDS Security spec v1.1 section 9.5.2.1.2 (table 67 and table 68) */ +static bool +calculate_kx_keys( + const DDS_Security_SharedSecretHandle shared_secret, + master_key_material *kx_key_material, + DDS_Security_SecurityException *ex) +{ + bool result = false; + const DDS_Security_octet *challenge1, *challenge2, *shared_secret_key; + unsigned char *kx_master_salt, *kx_master_sender_key; + size_t shared_secret_size = get_secret_size_from_secret_handle(shared_secret); + unsigned char hash[SHA256_DIGEST_LENGTH]; + size_t concatenated_bytes1_size = DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE * 2 + KXSALTCOOKIE_SIZE; + size_t concatenated_bytes2_size = DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE * 2 + KXKEYCOOKIE_SIZE; + DDS_Security_octet *concatenated_bytes1, *concatenated_bytes2; + + memset(ex, 0, sizeof(*ex)); + + if (shared_secret_size > UINT32_MAX) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, 0, "shared_secret_size > UINT32_MAX"); + goto fail_kx; + } + concatenated_bytes1 = ddsrt_malloc(concatenated_bytes1_size); + concatenated_bytes2 = ddsrt_malloc(concatenated_bytes2_size); + challenge1 = get_challenge1_from_secret_handle(shared_secret); + challenge2 = get_challenge2_from_secret_handle(shared_secret); + shared_secret_key = get_secret_from_secret_handle(shared_secret); + + /* master_salt */ + memcpy(concatenated_bytes1, challenge1, DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE); + memcpy(concatenated_bytes1 + DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE, KXSALTCOOKIE, KXSALTCOOKIE_SIZE); + memcpy(concatenated_bytes1 + DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE + KXSALTCOOKIE_SIZE, challenge2, DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE); + + SHA256(concatenated_bytes1, concatenated_bytes1_size, hash); + if (!(kx_master_salt = crypto_hmac256(hash, SHA256_DIGEST_LENGTH, shared_secret_key, (uint32_t) shared_secret_size, ex))) + goto fail_kx_salt; + + /* master_sender_key */ + memcpy(concatenated_bytes2, challenge2, DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE); + memcpy(concatenated_bytes2 + DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE, KXKEYCOOKIE, KXKEYCOOKIE_SIZE); + memcpy(concatenated_bytes2 + DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE + KXKEYCOOKIE_SIZE, challenge1, DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE); + + SHA256(concatenated_bytes2, concatenated_bytes2_size, hash); + if (!(kx_master_sender_key = crypto_hmac256(hash, SHA256_DIGEST_LENGTH, shared_secret_key, (uint32_t) shared_secret_size, ex))) + goto fail_kx_key; + + assert (kx_key_material->transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES256_GCM); /* set in crypto_participant_key_material_new */ + memcpy(kx_key_material->master_salt, kx_master_salt, CRYPTO_KEY_SIZE_256); + kx_key_material->sender_key_id = 0; + memcpy(kx_key_material->master_sender_key, kx_master_sender_key, CRYPTO_KEY_SIZE_256); + kx_key_material->receiver_specific_key_id = 0; + + memset (kx_master_sender_key, 0, CRYPTO_KEY_SIZE_256); + ddsrt_free(kx_master_sender_key); + result = true; + +fail_kx_key: + memset (kx_master_salt, 0, CRYPTO_KEY_SIZE_256); + ddsrt_free(kx_master_salt); +fail_kx_salt: + ddsrt_free(concatenated_bytes2); + ddsrt_free(concatenated_bytes1); +fail_kx: + return result; +} + +static uint32_t +generate_key( + dds_security_crypto_key_factory_impl *implementation, + master_key_material *key_material, + DDS_Security_SecurityException *ex) +{ + assert (key_material->transformation_kind != CRYPTO_TRANSFORMATION_KIND_NONE); + if (RAND_bytes(key_material->master_salt, (int)CRYPTO_KEY_SIZE_BYTES(key_material->transformation_kind)) < 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_CODE, 0, + DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_MESSAGE); + return DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_CODE; + } + if (RAND_bytes(key_material->master_sender_key, (int)CRYPTO_KEY_SIZE_BYTES(key_material->transformation_kind)) < 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_CODE, 0, + DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_MESSAGE); + return DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_CODE; + } + key_material->sender_key_id = ddsrt_atomic_inc32_ov(&implementation->next_key_id); + return DDS_SECURITY_ERR_OK_CODE; +} + +static DDS_Security_ProtectionKind +attribute_to_rtps_protection_kind( + const DDS_Security_ParticipantSecurityAttributes *attributes) +{ + DDS_Security_ProtectionKind kind = DDS_SECURITY_PROTECTION_KIND_NONE; + assert(attributes); + if (attributes->is_rtps_protected) + { + if (attributes->plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED) + { + if (attributes->plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED) + kind = DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION; + else + kind = DDS_SECURITY_PROTECTION_KIND_ENCRYPT; + } + else + { + if (attributes->plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED) + kind = DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION; + else + kind = DDS_SECURITY_PROTECTION_KIND_SIGN; + } + } + + return kind; +} + +static DDS_Security_ProtectionKind +attribute_to_meta_protection_kind( + const DDS_Security_EndpointSecurityAttributes *attributes) +{ + DDS_Security_ProtectionKind kind = DDS_SECURITY_PROTECTION_KIND_NONE; + assert(attributes); + if (attributes->is_submessage_protected) + { + if (attributes->plugin_endpoint_attributes & DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED) + { + if (attributes->plugin_endpoint_attributes & DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED) + kind = DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION; + else + kind = DDS_SECURITY_PROTECTION_KIND_ENCRYPT; + } + else + { + if (attributes->plugin_endpoint_attributes & DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED) + kind = DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION; + else + kind = DDS_SECURITY_PROTECTION_KIND_SIGN; + } + } + + return kind; +} + +static DDS_Security_BasicProtectionKind +attribute_to_data_protection_kind( + const DDS_Security_EndpointSecurityAttributes *attributes) +{ + DDS_Security_BasicProtectionKind kind = DDS_SECURITY_BASICPROTECTION_KIND_NONE; + assert(attributes); + if (attributes->is_payload_protected) + { + if (attributes->plugin_endpoint_attributes & DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED) + kind = DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT; + else + kind = DDS_SECURITY_BASICPROTECTION_KIND_SIGN; + } + return kind; +} + +static void +remove_remote_writer_relation( + dds_security_crypto_key_factory_impl *implementation, + remote_datawriter_crypto *rmt_wr) +{ + remote_participant_crypto *rmt_pp; + + DDSRT_UNUSED_ARG(implementation); + + assert(rmt_wr); + rmt_pp = rmt_wr->participant; + assert(rmt_pp); + + if (rmt_wr->writer2reader_key_material[0]) + crypto_remove_endpoint_relation(rmt_pp, (CryptoObject *)rmt_wr->local_reader, rmt_wr->writer2reader_key_material[0]->sender_key_id); +} + +static void +remove_remote_reader_relation( + dds_security_crypto_key_factory_impl *implementation, + remote_datareader_crypto *rmt_rd) +{ + remote_participant_crypto *rmt_pp; + + DDSRT_UNUSED_ARG(implementation); + + assert(rmt_rd); + rmt_pp = rmt_rd->participant; + assert(rmt_pp); + + if (rmt_rd->reader2writer_key_material) + crypto_remove_endpoint_relation(rmt_pp, (CryptoObject *)rmt_rd->local_writer, rmt_rd->reader2writer_key_material->sender_key_id); +} + +/** + * Function implementations + */ + +static DDS_Security_ParticipantCryptoHandle +register_local_participant( + dds_security_crypto_key_factory *instance, + const DDS_Security_IdentityHandle participant_identity, + const DDS_Security_PermissionsHandle participant_permissions, + const DDS_Security_PropertySeq *participant_properties, + const DDS_Security_ParticipantSecurityAttributes *participant_security_attributes, + DDS_Security_SecurityException *ex) +{ + local_participant_crypto *participant_crypto; + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + + if ((participant_identity == DDS_SECURITY_HANDLE_NIL) || + (participant_permissions == DDS_SECURITY_HANDLE_NIL)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, + DDS_SECURITY_ERR_IDENTITY_EMPTY_MESSAGE); + goto err_invalid_argument; + } + + /*init objects */ + participant_crypto = crypto_local_participant_crypto__new(participant_identity); + participant_crypto->rtps_protection_kind = attribute_to_rtps_protection_kind(participant_security_attributes); + participant_crypto->key_material = crypto_master_key_material_new( + DDS_Security_protectionkind2transformationkind(participant_properties, participant_crypto->rtps_protection_kind)); + + /* No need to create session material if there is no protection for RTPS */ + if (participant_crypto->key_material->transformation_kind != CRYPTO_TRANSFORMATION_KIND_NONE) + { + if (generate_key(implementation, participant_crypto->key_material, ex) != DDS_SECURITY_ERR_OK_CODE) + goto err_random_generation; + participant_crypto->session = crypto_session_key_material_new(participant_crypto->key_material); + } + + crypto_object_table_insert(implementation->crypto_objects, (CryptoObject *)participant_crypto); + CRYPTO_OBJECT_RELEASE(participant_crypto); + + return PARTICIPANT_CRYPTO_HANDLE(participant_crypto); + + /* error cases*/ +err_random_generation: + CRYPTO_OBJECT_RELEASE(participant_crypto); +err_invalid_argument: + return DDS_SECURITY_HANDLE_NIL; +} + +struct resolve_remote_part_arg +{ + DDS_Security_IdentityHandle ident; + remote_participant_crypto *pprmte; +}; + +static int +resolve_remote_participant_by_id( + CryptoObject *obj, + void *arg) +{ + struct resolve_remote_part_arg *info = arg; + + remote_participant_crypto *pprmte; + if (obj->kind == CRYPTO_OBJECT_KIND_REMOTE_CRYPTO) + { + pprmte = (remote_participant_crypto *)obj; + if (pprmte->identity_handle == info->ident) + { + info->pprmte = (remote_participant_crypto *)CRYPTO_OBJECT_KEEP(pprmte); + return 0; + } + } + + return 1; +} + +static DDS_Security_ParticipantCryptoHandle +register_matched_remote_participant( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle local_participant_crypto_handle, + const DDS_Security_IdentityHandle remote_participant_identity, + const DDS_Security_PermissionsHandle remote_participant_permissions, + const DDS_Security_SharedSecretHandle shared_secret, + DDS_Security_SecurityException *ex) +{ + /* declarations */ + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + remote_participant_crypto *rmt_pp_crypto; + local_participant_crypto *loc_pp_crypto; + DDS_Security_SecurityException exception; + participant_key_material *key_material; + + if (local_participant_crypto_handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_PARTICIPANT_CRYPTO_HANDLE_EMPTY_CODE, 0, + DDS_SECURITY_ERR_PARTICIPANT_CRYPTO_HANDLE_EMPTY_MESSAGE); + goto err_invalid_argument; + } + else if (remote_participant_identity == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE, 0, + DDS_SECURITY_ERR_IDENTITY_EMPTY_MESSAGE); + goto err_invalid_argument; + } + else if (remote_participant_permissions == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_PERMISSION_HANDLE_EMPTY_CODE, 0, + DDS_SECURITY_ERR_PERMISSION_HANDLE_EMPTY_MESSAGE); + goto err_invalid_argument; + } + + /* Check if local_participant_crypto_handle exists in the map */ + + loc_pp_crypto = (local_participant_crypto *)crypto_object_table_find(implementation->crypto_objects, local_participant_crypto_handle); + if (loc_pp_crypto == NULL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_argument; + } + + /* find or create remote participant crypto structure */ + { + struct resolve_remote_part_arg arg = {remote_participant_identity, NULL}; + crypto_object_table_walk(implementation->crypto_objects, resolve_remote_participant_by_id, &arg); + if (arg.pprmte) + { + rmt_pp_crypto = arg.pprmte; + } + else + { + rmt_pp_crypto = crypto_remote_participant_crypto__new(remote_participant_identity); + crypto_object_table_insert(implementation->crypto_objects, (CryptoObject *)rmt_pp_crypto); + } + } + + key_material = crypto_remote_participant_lookup_keymat(rmt_pp_crypto, PARTICIPANT_CRYPTO_HANDLE(loc_pp_crypto)); + if (!key_material) + { + key_material = crypto_participant_key_material_new(loc_pp_crypto, rmt_pp_crypto); + + /* set remote participant keymaterial with local keymaterial values */ + crypto_master_key_material_set(key_material->local_P2P_key_material, loc_pp_crypto->key_material); + + if (!calculate_kx_keys(shared_secret, key_material->P2P_kx_key_material, &exception)) + goto fail_calc_key; + + key_material->P2P_writer_session = crypto_session_key_material_new(key_material->P2P_kx_key_material); + key_material->P2P_reader_session = crypto_session_key_material_new(key_material->P2P_kx_key_material); + + /* if we do not have OriginAuthentication, receiver specific info remains empty/NULL */ + if ((loc_pp_crypto->rtps_protection_kind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION) || + (loc_pp_crypto->rtps_protection_kind == DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION)) + { + if (RAND_bytes(key_material->local_P2P_key_material->master_receiver_specific_key, (int)CRYPTO_KEY_SIZE_BYTES(key_material->local_P2P_key_material->transformation_kind)) < 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_CODE, 0, + DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_MESSAGE); + goto err_random_generation; + } + key_material->local_P2P_key_material->receiver_specific_key_id = ddsrt_atomic_inc32_ov(&implementation->next_key_id); + } + rmt_pp_crypto->session = (session_key_material *)CRYPTO_OBJECT_KEEP(loc_pp_crypto->session); + + crypto_local_participant_add_keymat(loc_pp_crypto, key_material); + crypto_remote_participant_add_keymat(rmt_pp_crypto, key_material); + } + + rmt_pp_crypto->rtps_protection_kind = loc_pp_crypto->rtps_protection_kind; /* Same as local */ + + CRYPTO_OBJECT_RELEASE(key_material); + CRYPTO_OBJECT_RELEASE(rmt_pp_crypto); + CRYPTO_OBJECT_RELEASE(loc_pp_crypto); + + return PARTICIPANT_CRYPTO_HANDLE(rmt_pp_crypto); + +/* error cases*/ +err_random_generation: +fail_calc_key: + CRYPTO_OBJECT_RELEASE(key_material); + CRYPTO_OBJECT_RELEASE(rmt_pp_crypto); + CRYPTO_OBJECT_RELEASE(loc_pp_crypto); +err_invalid_argument: + return DDS_SECURITY_HANDLE_NIL; +} + +static DDS_Security_DatawriterCryptoHandle +register_local_datawriter( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle participant_crypto_handle, + const DDS_Security_PropertySeq *datawriter_properties, + const DDS_Security_EndpointSecurityAttributes *datawriter_security_attributes, + DDS_Security_SecurityException *ex) +{ + local_participant_crypto *participant_crypto; + local_datawriter_crypto *writer_crypto; + bool is_builtin = false; + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + DDS_Security_ProtectionKind metadata_protection; + DDS_Security_BasicProtectionKind data_protection; + + if (participant_crypto_handle == DDS_SECURITY_HANDLE_NIL) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + participant_crypto = (local_participant_crypto *)crypto_object_table_find(implementation->crypto_objects, participant_crypto_handle); + if (!participant_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + if (datawriter_properties != NULL && datawriter_properties->_length > 0) + { + const DDS_Security_Property_t *property = DDS_Security_PropertySeq_find_property( + datawriter_properties, "dds.sec.builtin_endpoint_name"); + if (property != NULL && strcmp(property->value, "BuiltinParticipantVolatileMessageSecureWriter") == 0) + is_builtin = true; + } + + data_protection = attribute_to_data_protection_kind(datawriter_security_attributes); + metadata_protection = attribute_to_meta_protection_kind(datawriter_security_attributes); + + writer_crypto = crypto_local_datawriter_crypto__new(participant_crypto, metadata_protection, data_protection); + writer_crypto->is_builtin_participant_volatile_message_secure_writer = is_builtin; + + if (!is_builtin) + { + if (writer_crypto->metadata_protectionKind != DDS_SECURITY_PROTECTION_KIND_NONE) + { + writer_crypto->writer_key_material_message = crypto_master_key_material_new( + DDS_Security_protectionkind2transformationkind(datawriter_properties, metadata_protection)); + if (generate_key(implementation, writer_crypto->writer_key_material_message, ex) != DDS_SECURITY_ERR_OK_CODE) + goto err_random_generation; + writer_crypto->writer_session_message = crypto_session_key_material_new(writer_crypto->writer_key_material_message); + } + + if (writer_crypto->data_protectionKind != DDS_SECURITY_BASICPROTECTION_KIND_NONE) + { + writer_crypto->writer_key_material_payload = crypto_master_key_material_new( + DDS_Security_basicprotectionkind2transformationkind(datawriter_properties, data_protection)); + if (generate_key(implementation, writer_crypto->writer_key_material_payload, ex) != DDS_SECURITY_ERR_OK_CODE) + goto err_random_generation; + writer_crypto->writer_session_payload = crypto_session_key_material_new(writer_crypto->writer_key_material_payload); + } + } + + crypto_object_table_insert(implementation->crypto_objects, (CryptoObject *)writer_crypto); + CRYPTO_OBJECT_RELEASE(participant_crypto); + CRYPTO_OBJECT_RELEASE(writer_crypto); + + return writer_crypto->_parent.handle; + +err_random_generation: + CRYPTO_OBJECT_RELEASE(participant_crypto); + CRYPTO_OBJECT_RELEASE(writer_crypto); +err_invalid_parameter: + return DDS_SECURITY_HANDLE_NIL; +} + +static DDS_Security_DatareaderCryptoHandle +register_matched_remote_datareader( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatawriterCryptoHandle local_datawriter_crypto_handle, + const DDS_Security_ParticipantCryptoHandle remote_participant_crypto_handle, + const DDS_Security_SharedSecretHandle shared_secret, + const DDS_Security_boolean relay_only, DDS_Security_SecurityException *ex) +{ + remote_datareader_crypto *reader_crypto; + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + local_datawriter_crypto *local_writer; + remote_participant_crypto *remote_participant; + DDS_Security_ProtectionKind metadata_protectionKind; + DDS_Security_BasicProtectionKind data_protectionKind; + + DDSRT_UNUSED_ARG(shared_secret); + DDSRT_UNUSED_ARG(relay_only); + + if ((remote_participant_crypto_handle == DDS_SECURITY_HANDLE_NIL) || + (local_datawriter_crypto_handle == DDS_SECURITY_HANDLE_NIL)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + remote_participant = (remote_participant_crypto *)crypto_object_table_find(implementation->crypto_objects, remote_participant_crypto_handle); + if (!remote_participant) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + local_writer = (local_datawriter_crypto *)crypto_object_table_find(implementation->crypto_objects, local_datawriter_crypto_handle); + if (!local_writer) + { + CRYPTO_OBJECT_RELEASE(remote_participant); + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + data_protectionKind = local_writer->data_protectionKind; + metadata_protectionKind = local_writer->metadata_protectionKind; + + reader_crypto = crypto_remote_datareader_crypto__new(remote_participant, metadata_protectionKind, data_protectionKind, local_writer); + + /* check if the writer is BuiltinParticipantVolatileMessageSecureWriter */ + if (local_writer->is_builtin_participant_volatile_message_secure_writer) + { + participant_key_material *key_material = crypto_remote_participant_lookup_keymat(remote_participant, CRYPTO_OBJECT_HANDLE(local_writer->participant)); + assert(key_material); + + reader_crypto->reader2writer_key_material = (master_key_material *)CRYPTO_OBJECT_KEEP(key_material->P2P_kx_key_material); + reader_crypto->writer2reader_key_material_message = (master_key_material *)CRYPTO_OBJECT_KEEP(key_material->P2P_kx_key_material); + reader_crypto->writer_session = (session_key_material *)CRYPTO_OBJECT_KEEP(key_material->P2P_writer_session); + reader_crypto->is_builtin_participant_volatile_message_secure_reader = true; + CRYPTO_OBJECT_RELEASE(key_material); + } + else + { + if (local_writer->writer_key_material_message) + { + reader_crypto->writer2reader_key_material_message = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_NONE); + crypto_master_key_material_set(reader_crypto->writer2reader_key_material_message, local_writer->writer_key_material_message); + if ((metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION) || + (metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION)) + { + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(reader_crypto->writer2reader_key_material_message->transformation_kind); + if (RAND_bytes(reader_crypto->writer2reader_key_material_message->master_receiver_specific_key, (int)key_bytes) < 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_CODE, 0, + DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_MESSAGE); + goto err_random_generation; + } + reader_crypto->writer2reader_key_material_message->receiver_specific_key_id = ddsrt_atomic_inc32_ov(&implementation->next_key_id); + } + reader_crypto->writer_session = (session_key_material *)CRYPTO_OBJECT_KEEP(local_writer->writer_session_message); + } + + if (local_writer->writer_key_material_payload) + { + reader_crypto->writer2reader_key_material_payload = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_NONE); + crypto_master_key_material_set(reader_crypto->writer2reader_key_material_payload, local_writer->writer_key_material_payload); + } + } + + crypto_object_table_insert(implementation->crypto_objects, (CryptoObject *)reader_crypto); + CRYPTO_OBJECT_RELEASE(remote_participant); + CRYPTO_OBJECT_RELEASE(local_writer); + CRYPTO_OBJECT_RELEASE(reader_crypto); + + return DATAREADER_CRYPTO_HANDLE(reader_crypto); + +err_random_generation: + CRYPTO_OBJECT_RELEASE(reader_crypto); + CRYPTO_OBJECT_RELEASE(remote_participant); + CRYPTO_OBJECT_RELEASE(local_writer); +err_invalid_parameter: + return DDS_SECURITY_HANDLE_NIL; +} + +static DDS_Security_DatareaderCryptoHandle +register_local_datareader( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle participant_crypto_handle, + const DDS_Security_PropertySeq *datareader_properties, + const DDS_Security_EndpointSecurityAttributes *datareader_security_attributes, + DDS_Security_SecurityException *ex) +{ + local_participant_crypto *participant_crypto; + local_datareader_crypto *reader_crypto; + bool is_builtin = false; + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + DDS_Security_ProtectionKind metadata_protection; + DDS_Security_BasicProtectionKind data_protection; + + if (!instance || (participant_crypto_handle == DDS_SECURITY_HANDLE_NIL)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + participant_crypto = (local_participant_crypto *)crypto_object_table_find(implementation->crypto_objects, participant_crypto_handle); + if (!participant_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + if (datareader_properties != NULL && datareader_properties->_length > 0) + { + const DDS_Security_Property_t *property = DDS_Security_PropertySeq_find_property( + datareader_properties, "dds.sec.builtin_endpoint_name"); + if (property != NULL && strcmp(property->value, "BuiltinParticipantVolatileMessageSecureReader") == 0) + is_builtin = true; + } + + data_protection = attribute_to_data_protection_kind(datareader_security_attributes); + metadata_protection = attribute_to_meta_protection_kind(datareader_security_attributes); + + reader_crypto = crypto_local_datareader_crypto__new(participant_crypto, metadata_protection, data_protection); + reader_crypto->is_builtin_participant_volatile_message_secure_reader = is_builtin; + + if (!is_builtin) + { + if (reader_crypto->metadata_protectionKind != DDS_SECURITY_PROTECTION_KIND_NONE) + { + reader_crypto->reader_key_material = crypto_master_key_material_new( + DDS_Security_protectionkind2transformationkind(datareader_properties, metadata_protection)); + if (generate_key(implementation, reader_crypto->reader_key_material, ex) != DDS_SECURITY_ERR_OK_CODE) + goto err_random_generation; + reader_crypto->reader_session = crypto_session_key_material_new(reader_crypto->reader_key_material); + } + } + else + { + participant_crypto->builtin_reader = reader_crypto; + + } + + crypto_object_table_insert(implementation->crypto_objects, (CryptoObject *)reader_crypto); + CRYPTO_OBJECT_RELEASE(participant_crypto); + CRYPTO_OBJECT_RELEASE(reader_crypto); + + return DATAREADER_CRYPTO_HANDLE(reader_crypto); + +err_random_generation: + CRYPTO_OBJECT_RELEASE(participant_crypto); + CRYPTO_OBJECT_RELEASE(reader_crypto); +err_invalid_parameter: + return DDS_SECURITY_HANDLE_NIL; +} + +static DDS_Security_DatawriterCryptoHandle +register_matched_remote_datawriter( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatareaderCryptoHandle local_datareader_crypto_handle, + const DDS_Security_ParticipantCryptoHandle remote_participant_crypto_handle, + const DDS_Security_SharedSecretHandle shared_secret, + DDS_Security_SecurityException *ex) +{ + remote_datawriter_crypto *writer_crypto; + dds_security_crypto_key_factory_impl *implementation = + (dds_security_crypto_key_factory_impl *)instance; + local_datareader_crypto *local_reader; + remote_participant_crypto *remote_participant; + + DDSRT_UNUSED_ARG(shared_secret); + + if ((remote_participant_crypto_handle == DDS_SECURITY_HANDLE_NIL) || + (local_datareader_crypto_handle == DDS_SECURITY_HANDLE_NIL)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + remote_participant = (remote_participant_crypto *)crypto_object_table_find(implementation->crypto_objects, remote_participant_crypto_handle); + if (!remote_participant) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + local_reader = (local_datareader_crypto *)crypto_object_table_find(implementation->crypto_objects, local_datareader_crypto_handle); + if (!local_reader) + { + CRYPTO_OBJECT_RELEASE(remote_participant); + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_invalid_parameter; + } + + writer_crypto = crypto_remote_datawriter_crypto__new(remote_participant, local_reader->metadata_protectionKind, local_reader->data_protectionKind, local_reader); + + /* check if the writer is BuiltinParticipantVolatileMessageSecureWriter */ + if (local_reader->is_builtin_participant_volatile_message_secure_reader) + { + participant_key_material *key_material = crypto_remote_participant_lookup_keymat(remote_participant, CRYPTO_OBJECT_HANDLE(local_reader->participant)); + assert(key_material); + + writer_crypto->reader2writer_key_material = (master_key_material *)CRYPTO_OBJECT_KEEP(key_material->P2P_kx_key_material); + writer_crypto->writer2reader_key_material[0] = (master_key_material *)CRYPTO_OBJECT_KEEP(key_material->P2P_kx_key_material); + writer_crypto->writer2reader_key_material[1] = (master_key_material *)CRYPTO_OBJECT_KEEP(key_material->P2P_kx_key_material); + writer_crypto->reader_session = (session_key_material *)CRYPTO_OBJECT_KEEP(key_material->P2P_reader_session); + writer_crypto->is_builtin_participant_volatile_message_secure_writer = true; + + key_relation * relation = crypto_key_relation_new(DDS_SECURITY_DATAWRITER_SUBMESSAGE, 0, (CryptoObject *)local_reader, (CryptoObject *)writer_crypto, NULL); + + crypto_insert_endpoint_relation(remote_participant, relation); + CRYPTO_OBJECT_RELEASE(relation); + CRYPTO_OBJECT_RELEASE(key_material); + } + else if (local_reader->metadata_protectionKind != DDS_SECURITY_PROTECTION_KIND_NONE) + { + writer_crypto->reader2writer_key_material = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_NONE); + crypto_master_key_material_set(writer_crypto->reader2writer_key_material, local_reader->reader_key_material); + + if (local_reader->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION + || local_reader->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION) + { + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(writer_crypto->reader2writer_key_material->transformation_kind); + if (RAND_bytes(writer_crypto->reader2writer_key_material->master_receiver_specific_key, (int)key_bytes) < 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_CODE, 0, + DDS_SECURITY_ERR_CANNOT_GENERATE_RANDOM_MESSAGE); + goto err_random_generation; + } + writer_crypto->reader2writer_key_material->receiver_specific_key_id = ddsrt_atomic_inc32_ov(&implementation->next_key_id); + writer_crypto->reader_session = (session_key_material *)CRYPTO_OBJECT_KEEP(local_reader->reader_session); + } + } + crypto_object_table_insert(implementation->crypto_objects, (CryptoObject *)writer_crypto); + CRYPTO_OBJECT_RELEASE(remote_participant); + CRYPTO_OBJECT_RELEASE(local_reader); + CRYPTO_OBJECT_RELEASE(writer_crypto); + + return DATAREADER_CRYPTO_HANDLE(writer_crypto); + +err_random_generation: + CRYPTO_OBJECT_RELEASE(writer_crypto); + CRYPTO_OBJECT_RELEASE(remote_participant); + CRYPTO_OBJECT_RELEASE(local_reader); +err_invalid_parameter: + return DDS_SECURITY_HANDLE_NIL; +} + +static DDS_Security_boolean +unregister_participant( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle participant_crypto_handle, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + DDS_Security_boolean result = false; + CryptoObject *obj; + local_participant_crypto *loc_pp_crypto; + remote_participant_crypto *rmt_pp_crypto; + participant_key_material *keymat; + DDS_Security_ParticipantCryptoHandle *handles = NULL; + size_t num, i; + + if ((obj = crypto_object_table_find(implementation->crypto_objects, participant_crypto_handle)) != NULL) + { + switch (obj->kind) + { + case CRYPTO_OBJECT_KIND_LOCAL_CRYPTO: + { + loc_pp_crypto = (local_participant_crypto *)obj; + + num = crypto_local_participnant_get_matching(loc_pp_crypto, &handles); + for (i = 0; i < num; i++) + { + if ((keymat = crypto_local_participant_remove_keymat(loc_pp_crypto, handles[i])) != NULL) + CRYPTO_OBJECT_RELEASE(keymat); + + if ((rmt_pp_crypto = (remote_participant_crypto *)crypto_object_table_find(implementation->crypto_objects, handles[i])) != NULL) + { + ddsrt_mutex_lock(&rmt_pp_crypto->lock); + if ((keymat = crypto_remote_participant_remove_keymat_locked(rmt_pp_crypto, participant_crypto_handle)) != NULL) + { + if (keymat->remote_key_material && keymat->remote_key_material->receiver_specific_key_id != 0) + crypto_remove_specific_key_relation_locked(rmt_pp_crypto, keymat->remote_key_material->receiver_specific_key_id); + CRYPTO_OBJECT_RELEASE(keymat); + } + ddsrt_mutex_unlock(&rmt_pp_crypto->lock); + CRYPTO_OBJECT_RELEASE(rmt_pp_crypto); + } + } + ddsrt_free(handles); + crypto_object_table_remove_object(implementation->crypto_objects, obj); + result = true; + } + break; + case CRYPTO_OBJECT_KIND_REMOTE_CRYPTO: + { + rmt_pp_crypto = (remote_participant_crypto *)obj; + + num = crypto_remote_participnant_get_matching(rmt_pp_crypto, &handles); + for (i = 0; i < num; i++) + { + ddsrt_mutex_lock(&rmt_pp_crypto->lock); + if ((keymat = crypto_remote_participant_remove_keymat_locked(rmt_pp_crypto, handles[i])) != NULL) + { + if (keymat->remote_key_material && keymat->remote_key_material->receiver_specific_key_id != 0) + crypto_remove_specific_key_relation_locked(rmt_pp_crypto, keymat->remote_key_material->receiver_specific_key_id); + CRYPTO_OBJECT_RELEASE(keymat); + } + ddsrt_mutex_unlock(&rmt_pp_crypto->lock); + + if ((loc_pp_crypto = (local_participant_crypto *)crypto_object_table_find(implementation->crypto_objects, handles[i])) != NULL) + { + if ((keymat = crypto_local_participant_remove_keymat(loc_pp_crypto, participant_crypto_handle)) != NULL) + CRYPTO_OBJECT_RELEASE(keymat); + CRYPTO_OBJECT_RELEASE(loc_pp_crypto); + } + } + ddsrt_free(handles); + crypto_object_table_remove_object(implementation->crypto_objects, obj); + result = true; + } + break; + default: + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + } + break; + } + CRYPTO_OBJECT_RELEASE(obj); + } + else + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + + return result; +} + +static DDS_Security_boolean +unregister_datawriter( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatawriterCryptoHandle datawriter_crypto_handle, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + DDS_Security_boolean result = false; + CryptoObject *obj; + + /* check if the handle is applicable*/ + if ((obj = crypto_object_table_find(implementation->crypto_objects, datawriter_crypto_handle)) != NULL) + { + switch (obj->kind) + { + case CRYPTO_OBJECT_KIND_LOCAL_WRITER_CRYPTO: + crypto_object_table_remove_object(implementation->crypto_objects, obj); + result = true; + break; + case CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO: + { + remote_datawriter_crypto *rmt_wr = (remote_datawriter_crypto *)obj; + remove_remote_writer_relation(implementation, rmt_wr); + if (rmt_wr->writer2reader_key_material[0] && rmt_wr->writer2reader_key_material[0]->receiver_specific_key_id != 0) + crypto_remove_specific_key_relation(rmt_wr->participant, rmt_wr->writer2reader_key_material[0]->receiver_specific_key_id); + crypto_object_table_remove_object(implementation->crypto_objects, obj); + result = true; + } + break; + default: + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + break; + } + CRYPTO_OBJECT_RELEASE(obj); + } + else + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + + return result; +} + +static DDS_Security_boolean +unregister_datareader( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatareaderCryptoHandle datareader_crypto_handle, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + DDS_Security_boolean result = false; + CryptoObject *obj; + + /* check if the handle is applicable*/ + if ((obj = crypto_object_table_find(implementation->crypto_objects, datareader_crypto_handle)) != NULL) + { + switch (obj->kind) + { + case CRYPTO_OBJECT_KIND_LOCAL_READER_CRYPTO: + crypto_object_table_remove_object(implementation->crypto_objects, obj); + result = true; + break; + case CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO: + { + remote_datareader_crypto *rmt_rd = (remote_datareader_crypto *)obj; + remove_remote_reader_relation(implementation, rmt_rd); + if (rmt_rd->reader2writer_key_material && rmt_rd->reader2writer_key_material->receiver_specific_key_id != 0) + crypto_remove_specific_key_relation(rmt_rd->participant, rmt_rd->reader2writer_key_material->receiver_specific_key_id); + crypto_object_table_remove_object(implementation->crypto_objects, obj); + result = true; + } + break; + default: + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + break; + } + CRYPTO_OBJECT_RELEASE(obj); + } + else + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + + return result; +} + +dds_security_crypto_key_factory * +dds_security_crypto_key_factory__alloc( + const dds_security_cryptography *crypto) +{ + dds_security_crypto_key_factory_impl *instance = ddsrt_malloc(sizeof(*instance)); + + ddsrt_mutex_init(&instance->lock); + + instance->crypto = crypto; + instance->base.register_local_participant = ®ister_local_participant; + instance->base.register_matched_remote_participant = ®ister_matched_remote_participant; + instance->base.register_local_datawriter = ®ister_local_datawriter; + instance->base.register_matched_remote_datareader = ®ister_matched_remote_datareader; + instance->base.register_local_datareader = ®ister_local_datareader; + instance->base.register_matched_remote_datawriter = ®ister_matched_remote_datawriter; + instance->base.unregister_participant = &unregister_participant; + instance->base.unregister_datawriter = &unregister_datawriter; + instance->base.unregister_datareader = &unregister_datareader; + + /* init implementation specific members */ + instance->crypto_objects = crypto_object_table_new(NULL, NULL, NULL); + + ddsrt_atomic_st32 (&instance->next_key_id, 1); + + return (dds_security_crypto_key_factory *)instance; +} + +void dds_security_crypto_key_factory__dealloc(dds_security_crypto_key_factory *instance) +{ + dds_security_crypto_key_factory_impl *implementation = (dds_security_crypto_key_factory_impl *)instance; + ddsrt_mutex_destroy (&implementation->lock); + crypto_object_table_free(implementation->crypto_objects); + ddsrt_free(implementation); +} + + +bool +crypto_factory_get_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, + DDS_Security_ParticipantCryptoHandle local_id, + DDS_Security_ParticipantCryptoHandle remote_id, + participant_key_material **pp_key_material, + master_key_material **remote_key_matarial, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + assert (pp_key_material != NULL); + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_participant_crypto *remote_crypto = (remote_participant_crypto *)crypto_object_table_find(impl->crypto_objects, remote_id); + bool result = false; + + if (!remote_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_remote; + } + else if (!CRYPTO_OBJECT_VALID(remote_crypto, CRYPTO_OBJECT_KIND_REMOTE_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_remote; + } + + ddsrt_mutex_lock(&remote_crypto->lock); + if (!(*pp_key_material = (participant_key_material *)crypto_remote_participant_lookup_keymat_locked(remote_crypto, local_id))) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + ddsrt_mutex_unlock(&remote_crypto->lock); + goto err_remote; + } + if (remote_key_matarial != NULL) + *remote_key_matarial = (*pp_key_material)->remote_key_material; + if (protection_kind != NULL) + *protection_kind = remote_crypto->rtps_protection_kind; + ddsrt_mutex_unlock(&remote_crypto->lock); + result = true; + +err_remote: + CRYPTO_OBJECT_RELEASE(remote_crypto); +err_no_remote: + return result; +} + +static void gc_remote_key_material (struct gcreq *gcreq) +{ + CRYPTO_OBJECT_RELEASE (gcreq->arg); + gcreq_free (gcreq); +} + +bool +crypto_factory_set_participant_crypto_tokens( + const dds_security_crypto_key_factory *factory, + const DDS_Security_ParticipantCryptoHandle local_id, + const DDS_Security_ParticipantCryptoHandle remote_id, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *remote_key_mat, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_participant_crypto *remote_crypto; + participant_key_material *key_material; + bool result = false; + + remote_crypto = (remote_participant_crypto *)crypto_object_table_find(impl->crypto_objects, remote_id); + if (!remote_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_remote; + } + else if (!CRYPTO_OBJECT_VALID(remote_crypto, CRYPTO_OBJECT_KIND_REMOTE_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + + ddsrt_mutex_lock(&remote_crypto->lock); + key_material = crypto_remote_participant_lookup_keymat_locked(remote_crypto, local_id); + if (key_material) + { + /* Because setting crypto tokens is not done very often, we're not using an + atomic pointer (which makes the code less readable) and do not introduce an + additional lock for the remote key material. Instead it is protected by the + remote_participant_crypto lock. For cleaning up the old remote key + material, the garbage collector is used so that any pointer to the remote + key material can be safely used until thread state sleep. */ + master_key_material *remote_key_mat_old = key_material->remote_key_material; + master_key_material *remote_key_mat_new = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_NONE); + crypto_token_copy(remote_key_mat_new, remote_key_mat); + key_material->remote_key_material = remote_key_mat_new; + + if (remote_key_mat_old != NULL) + { + struct gcreq *gcreq = gcreq_new(impl->crypto->gv->gcreq_queue, gc_remote_key_material); + gcreq->arg = remote_key_mat_old; + gcreq_enqueue(gcreq); + } + + uint32_t specific_key = key_material->remote_key_material->receiver_specific_key_id; + if (specific_key != 0) + { + key_relation *relation = crypto_find_specific_key_relation_locked(remote_crypto, specific_key); + if (!relation) + { + local_participant_crypto *local_crypto = (local_participant_crypto *)crypto_object_table_find(impl->crypto_objects, local_id); + relation = crypto_key_relation_new(0, specific_key, CRYPTO_OBJECT(local_crypto), CRYPTO_OBJECT(remote_crypto), key_material->remote_key_material); + crypto_insert_specific_key_relation_locked(remote_crypto, relation); + CRYPTO_OBJECT_RELEASE(local_crypto); + } + CRYPTO_OBJECT_RELEASE(relation); + } + ddsrt_mutex_unlock(&remote_crypto->lock); + CRYPTO_OBJECT_RELEASE(key_material); + } + else + { + ddsrt_mutex_unlock(&remote_crypto->lock); + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + result = true; + +err_inv_remote: + CRYPTO_OBJECT_RELEASE(remote_crypto); +err_no_remote: + return result; +} + +bool +crypto_factory_get_datawriter_crypto_tokens( + const dds_security_crypto_key_factory *factory, + DDS_Security_DatawriterCryptoHandle local_writer_handle, + DDS_Security_DatareaderCryptoHandle remote_reader_handle, + master_key_material **key_mat, + uint32_t *num_key_mat, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_datareader_crypto *remote_reader_crypto; + uint32_t index = 0; + bool result = false; + + assert(factory); + assert(local_writer_handle != DDS_SECURITY_HANDLE_NIL); + assert(remote_reader_handle != DDS_SECURITY_HANDLE_NIL); + assert(key_mat); + assert(num_key_mat); + assert((*num_key_mat) == 2); + + remote_reader_crypto = (remote_datareader_crypto *)crypto_object_table_find(impl->crypto_objects, remote_reader_handle); + if (!remote_reader_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_remote; + } + else if (!CRYPTO_OBJECT_VALID(remote_reader_crypto, CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + + if (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); + goto err_inv_remote; + } + + if (remote_reader_crypto->writer2reader_key_material_message) + key_mat[index++] = (master_key_material *)CRYPTO_OBJECT_KEEP(remote_reader_crypto->writer2reader_key_material_message); + + if (remote_reader_crypto->writer2reader_key_material_payload) + key_mat[index++] = (master_key_material *)CRYPTO_OBJECT_KEEP(remote_reader_crypto->writer2reader_key_material_payload); + + *num_key_mat = index; + result = true; + +err_inv_remote: + CRYPTO_OBJECT_RELEASE(remote_reader_crypto); +err_no_remote: + return result; +} + +bool +crypto_factory_set_datawriter_crypto_tokens( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle local_reader_handle, + const DDS_Security_DatareaderCryptoHandle remote_writer_handle, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *key_mat, + const uint32_t num_key_mat, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + bool result = false; + remote_datawriter_crypto *remote_writer_crypto; + local_datareader_crypto *local_reader_crypto; + master_key_material *writer_master_key[2] = {NULL, NULL}; + key_relation *relation; + uint32_t key_id, i; + + assert (num_key_mat > 0); + + remote_writer_crypto = (remote_datawriter_crypto *)crypto_object_table_find(impl->crypto_objects, remote_writer_handle); + if (!remote_writer_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_remote; + } + else if (!CRYPTO_OBJECT_VALID(remote_writer_crypto, CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + + local_reader_crypto = (local_datareader_crypto *)crypto_object_table_find(impl->crypto_objects, local_reader_handle); + if (!local_reader_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_local; + } + else if (!CRYPTO_OBJECT_VALID(local_reader_crypto, CRYPTO_OBJECT_KIND_LOCAL_READER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_local; + } + + if (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); + goto err_inv_local; + } + + for (i = 0; i < num_key_mat; i++) + { + writer_master_key[i] = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_NONE); + crypto_token_copy(writer_master_key[i], &key_mat[i]); + } + + remove_remote_writer_relation(impl, remote_writer_crypto); + CRYPTO_OBJECT_RELEASE(remote_writer_crypto->writer2reader_key_material[0]); + CRYPTO_OBJECT_RELEASE(remote_writer_crypto->writer2reader_key_material[1]); + + remote_writer_crypto->writer2reader_key_material[0] = writer_master_key[0]; + if (writer_master_key[1]) + remote_writer_crypto->writer2reader_key_material[1] = writer_master_key[1]; + else + remote_writer_crypto->writer2reader_key_material[1] = (master_key_material *)CRYPTO_OBJECT_KEEP(writer_master_key[0]); + + key_id = remote_writer_crypto->writer2reader_key_material[0]->sender_key_id; + + relation = crypto_key_relation_new(DDS_SECURITY_DATAWRITER_SUBMESSAGE, key_id, (CryptoObject *)local_reader_crypto, (CryptoObject *)remote_writer_crypto, NULL); + crypto_insert_endpoint_relation(remote_writer_crypto->participant, relation); + CRYPTO_OBJECT_RELEASE(relation); + + uint32_t specific_key = remote_writer_crypto->writer2reader_key_material[0]->receiver_specific_key_id; + if (specific_key != 0) + { + relation = crypto_find_specific_key_relation(remote_writer_crypto->participant, specific_key); + if (!relation) + { + relation = crypto_key_relation_new(0, specific_key, CRYPTO_OBJECT(local_reader_crypto), CRYPTO_OBJECT(remote_writer_crypto), remote_writer_crypto->writer2reader_key_material[0]); + crypto_insert_specific_key_relation(remote_writer_crypto->participant, relation); + } + CRYPTO_OBJECT_RELEASE(relation); + } + + result = true; + +err_inv_local: + CRYPTO_OBJECT_RELEASE(local_reader_crypto); +err_inv_remote: + CRYPTO_OBJECT_RELEASE(remote_writer_crypto); +err_no_remote: + return result; +} + +bool +crypto_factory_get_datareader_crypto_tokens( + const dds_security_crypto_key_factory *factory, + DDS_Security_DatawriterCryptoHandle local_reader_handle, + DDS_Security_DatareaderCryptoHandle remote_writer_handle, + master_key_material **key_mat, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_datawriter_crypto *remote_writer_crypto; + bool result = false; + + assert(factory); + assert(local_reader_handle != DDS_SECURITY_HANDLE_NIL); + assert(remote_writer_handle != DDS_SECURITY_HANDLE_NIL); + assert(key_mat); + + remote_writer_crypto = (remote_datawriter_crypto *)crypto_object_table_find(impl->crypto_objects, remote_writer_handle); + if (!remote_writer_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_remote; + } + else if (!CRYPTO_OBJECT_VALID(remote_writer_crypto, CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + + if (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); + goto err_inv_remote; + } + + if (remote_writer_crypto->reader2writer_key_material) + *key_mat = (master_key_material *)CRYPTO_OBJECT_KEEP(remote_writer_crypto->reader2writer_key_material); + else + *key_mat = NULL; /* there is no key material to return, because of no encryption for submessages in AccessControl */ + result = true; + +err_inv_remote: + CRYPTO_OBJECT_RELEASE(remote_writer_crypto); +err_no_remote: + return result; +} + +bool +crypto_factory_set_datareader_crypto_tokens( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle local_writer_handle, + const DDS_Security_DatareaderCryptoHandle remote_reader_handle, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *key_mat, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + bool result = false; + remote_datareader_crypto *remote_reader_crypto; + local_datawriter_crypto *local_writer_crypto; + key_relation *relation; + uint32_t key_id; + + remote_reader_crypto = (remote_datareader_crypto *)crypto_object_table_find(impl->crypto_objects, remote_reader_handle); + if (!remote_reader_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + else if (!CRYPTO_OBJECT_VALID(remote_reader_crypto, CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + + local_writer_crypto = (local_datawriter_crypto *)crypto_object_table_find(impl->crypto_objects, local_writer_handle); + if (!local_writer_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_local; + } + else if (!CRYPTO_OBJECT_VALID(local_writer_crypto, CRYPTO_OBJECT_KIND_LOCAL_WRITER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_local; + } + + if (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); + goto err_inv_local; + } + + remove_remote_reader_relation(impl, remote_reader_crypto); + CRYPTO_OBJECT_RELEASE(remote_reader_crypto->reader2writer_key_material); + + remote_reader_crypto->reader2writer_key_material = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_NONE); + crypto_token_copy(remote_reader_crypto->reader2writer_key_material, key_mat); + + key_id = remote_reader_crypto->reader2writer_key_material->sender_key_id; + + relation = crypto_key_relation_new(DDS_SECURITY_DATAREADER_SUBMESSAGE, key_id, (CryptoObject *)local_writer_crypto, (CryptoObject *)remote_reader_crypto, NULL); + crypto_insert_endpoint_relation(remote_reader_crypto->participant, relation); + CRYPTO_OBJECT_RELEASE(relation); + + uint32_t specific_key = remote_reader_crypto->reader2writer_key_material->receiver_specific_key_id; + if (specific_key != 0) + { + relation = crypto_find_specific_key_relation(remote_reader_crypto->participant, specific_key); + if (!relation) + { + relation = crypto_key_relation_new(0, specific_key, CRYPTO_OBJECT(local_writer_crypto), CRYPTO_OBJECT(remote_reader_crypto), remote_reader_crypto->reader2writer_key_material); + crypto_insert_specific_key_relation(remote_reader_crypto->participant, relation); + } + CRYPTO_OBJECT_RELEASE(relation); + } + + result = true; + +err_inv_local: + CRYPTO_OBJECT_RELEASE(local_writer_crypto); +err_inv_remote: + CRYPTO_OBJECT_RELEASE(remote_reader_crypto); + return result; +} + +static bool +get_local_volatile_sec_writer_key_material( + dds_security_crypto_key_factory_impl *factory, + const DDS_Security_DatareaderCryptoHandle reader_id, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + bool result = false; + remote_datareader_crypto *reader_crypto; + + reader_crypto = (remote_datareader_crypto *)crypto_object_table_find(factory->crypto_objects, reader_id); + if (!reader_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE " %"PRIx64, reader_id); + goto err_no_crypto; + } + else if (!CRYPTO_OBJECT_VALID(reader_crypto, CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(reader_crypto->writer_session); + *protection_kind = reader_crypto->metadata_protectionKind; + result = true; + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(reader_crypto); +err_no_crypto: + return result; +} + +static bool +get_local_volatile_sec_reader_key_material( + dds_security_crypto_key_factory_impl *factory, + const DDS_Security_DatawriterCryptoHandle writer_id, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + bool result = false; + remote_datawriter_crypto *writer_crypto; + + writer_crypto = (remote_datawriter_crypto *)crypto_object_table_find(factory->crypto_objects, writer_id); + if (!writer_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_crypto; + } + else if (!CRYPTO_OBJECT_VALID(writer_crypto, CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE " %"PRIx64, writer_id); + goto err_inv_crypto; + } + + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(writer_crypto->reader_session); + *protection_kind = writer_crypto->metadata_protectionKind; + result = true; + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(writer_crypto); +err_no_crypto: + return result; +} + +bool +crypto_factory_get_local_participant_data_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_ParticipantCryptoHandle local_id, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + local_participant_crypto *participant_crypto; + bool result = false; + + participant_crypto = (local_participant_crypto *)crypto_object_table_find(impl->crypto_objects, local_id); + if (!(participant_crypto)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_crypto; + } + else if (!CRYPTO_OBJECT_VALID(participant_crypto, CRYPTO_OBJECT_KIND_LOCAL_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(participant_crypto->session); + *protection_kind = participant_crypto->rtps_protection_kind; + result = true; + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(participant_crypto); +err_no_crypto: + return result; +} + +bool +crypto_factory_get_writer_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle writer_id, + const DDS_Security_DatareaderCryptoHandle reader_id, + bool payload, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + local_datawriter_crypto *writer_crypto = NULL; + bool result = false; + + writer_crypto = (local_datawriter_crypto *)crypto_object_table_find(impl->crypto_objects, writer_id); + if (!writer_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE " %"PRIx64, writer_id); + goto err_remote; + } + if (!CRYPTO_OBJECT_VALID(writer_crypto, CRYPTO_OBJECT_KIND_LOCAL_WRITER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_remote; + } + if (!writer_crypto->is_builtin_participant_volatile_message_secure_writer) + { + if (payload) + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(writer_crypto->writer_session_payload); + else + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(writer_crypto->writer_session_message); + + if (protection_kind) + *protection_kind = writer_crypto->metadata_protectionKind; + result = true; + } + else if (!payload) + { + result = get_local_volatile_sec_writer_key_material(impl, reader_id, session_key, protection_kind, ex); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + } + +err_inv_remote: + CRYPTO_OBJECT_RELEASE(writer_crypto); +err_remote: + return result; +} + +bool +crypto_factory_get_reader_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle reader_id, + const DDS_Security_DatawriterCryptoHandle writer_id, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + local_datareader_crypto *reader_crypto; + bool result = false; + + reader_crypto = (local_datareader_crypto *)crypto_object_table_find(impl->crypto_objects, reader_id); + if (!reader_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE " %"PRIx64, reader_id); + goto err_no_crypto; + } + else if (!CRYPTO_OBJECT_VALID(reader_crypto, CRYPTO_OBJECT_KIND_LOCAL_READER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + else if (!reader_crypto->is_builtin_participant_volatile_message_secure_reader) + { + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(reader_crypto->reader_session); + if (protection_kind) + *protection_kind = reader_crypto->metadata_protectionKind; + result = true; + } + else + result = get_local_volatile_sec_reader_key_material(impl, writer_id, session_key, protection_kind, ex); + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(reader_crypto); +err_no_crypto: + return result; +} + +bool +crypto_factory_get_remote_writer_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle reader_id, + const DDS_Security_DatawriterCryptoHandle writer_id, + uint32_t key_id, + master_key_material **master_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_BasicProtectionKind *basic_protection_kind, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_datawriter_crypto *writer_crypto; + bool result = false; + + writer_crypto = (remote_datawriter_crypto *)crypto_object_table_find(impl->crypto_objects, writer_id); + if (!writer_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_crypto; + } + if (!CRYPTO_OBJECT_VALID(writer_crypto, CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + if (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); + goto err_inv_crypto; + } + + if (writer_crypto->writer2reader_key_material[0]->sender_key_id == key_id) + { + *master_key = (master_key_material *)CRYPTO_OBJECT_KEEP(writer_crypto->writer2reader_key_material[0]); + } + else if (writer_crypto->writer2reader_key_material[1]->sender_key_id == key_id) + { + *master_key = (master_key_material *)CRYPTO_OBJECT_KEEP(writer_crypto->writer2reader_key_material[1]); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + if (protection_kind) + *protection_kind = writer_crypto->metadata_protectionKind; + if (basic_protection_kind) + *basic_protection_kind = writer_crypto->data_protectionKind; + result = true; + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(writer_crypto); +err_no_crypto: + + return result; +} + +bool +crypto_factory_get_remote_reader_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle writer_id, + const DDS_Security_DatareaderCryptoHandle reader_id, + uint32_t key_id, + master_key_material **master_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_datareader_crypto *reader_crypto; + bool result = false; + + reader_crypto = (remote_datareader_crypto *)crypto_object_table_find(impl->crypto_objects, reader_id); + if (!reader_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_crypto; + } + if (!CRYPTO_OBJECT_VALID(reader_crypto, CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO)) + { + CRYPTO_OBJECT_RELEASE(reader_crypto); + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + if (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, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + if (reader_crypto->reader2writer_key_material->sender_key_id == key_id) + { + *master_key = (master_key_material *)CRYPTO_OBJECT_KEEP(reader_crypto->reader2writer_key_material); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + if (protection_kind) + *protection_kind = reader_crypto->metadata_protectionKind; + result = true; + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(reader_crypto); +err_no_crypto: + return result; +} + +bool +crypto_factory_get_remote_writer_sign_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle writer_id, + master_key_material **key_material, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_datawriter_crypto *writer_crypto; + bool result = false; + + assert(key_material); + assert(session_key); + assert(protection_kind); + + writer_crypto = (remote_datawriter_crypto *)crypto_object_table_find(impl->crypto_objects, writer_id); + if (!writer_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_crypto; + } + else if (!CRYPTO_OBJECT_VALID(writer_crypto, CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + + *key_material = (master_key_material *)CRYPTO_OBJECT_KEEP(writer_crypto->reader2writer_key_material); + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(writer_crypto->reader_session); + *protection_kind = writer_crypto->metadata_protectionKind; + result = true; + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(writer_crypto); +err_no_crypto: + return result; +} + +bool +crypto_factory_get_remote_reader_sign_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle reader_id, + master_key_material **key_material, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_datareader_crypto *reader_crypto; + bool result = false; + + assert(key_material); + assert(session_key); + assert(protection_kind); + + reader_crypto = (remote_datareader_crypto *)crypto_object_table_find(impl->crypto_objects, reader_id); + if (!reader_crypto) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_no_crypto; + } + else if (!CRYPTO_OBJECT_VALID(reader_crypto, CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto err_inv_crypto; + } + + *key_material = (master_key_material *)CRYPTO_OBJECT_KEEP(reader_crypto->writer2reader_key_material_message); + *session_key = (session_key_material *)CRYPTO_OBJECT_KEEP(reader_crypto->writer_session); + *protection_kind = reader_crypto->metadata_protectionKind; + result = true; + +err_inv_crypto: + CRYPTO_OBJECT_RELEASE(reader_crypto); +err_no_crypto: + return result; +} + +bool +crypto_factory_get_endpoint_relation( + const dds_security_crypto_key_factory *factory, + DDS_Security_ParticipantCryptoHandle local_participant_handle, + DDS_Security_ParticipantCryptoHandle remote_participant_handle, + uint32_t key_id, + DDS_Security_Handle *remote_handle, + DDS_Security_Handle *local_handle, + DDS_Security_SecureSubmessageCategory_t *category, + DDS_Security_SecurityException *ex) +{ + bool result = false; + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_participant_crypto *rmt_pp; + local_participant_crypto *loc_pp = NULL; + local_datareader_crypto *loc_rd = NULL; + key_relation *relation = NULL; + + rmt_pp = (remote_participant_crypto *)crypto_object_table_find(impl->crypto_objects, remote_participant_handle); + if (!rmt_pp) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto invalid_handle; + } + else if (!CRYPTO_OBJECT_VALID(rmt_pp, CRYPTO_OBJECT_KIND_REMOTE_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto invalid_handle; + } + + if (key_id == 0 && local_participant_handle != DDS_SECURITY_HANDLE_NIL) + { + loc_pp = (local_participant_crypto *)crypto_object_table_find(impl->crypto_objects, local_participant_handle); + if (!loc_pp) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto invalid_handle; + } + else if (!CRYPTO_OBJECT_VALID(loc_pp, CRYPTO_OBJECT_KIND_LOCAL_CRYPTO)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE); + goto invalid_handle; + } + loc_rd = loc_pp->builtin_reader; + } + + relation = crypto_find_endpoint_relation(rmt_pp, CRYPTO_OBJECT(loc_rd), key_id); + if (!relation) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE, 0, + DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE " key_id=%u", key_id); + goto invalid_handle; + } + + assert(key_id == relation->key_id); + + *category = relation->kind; + *remote_handle = CRYPTO_OBJECT_HANDLE(relation->remote_crypto); + *local_handle = CRYPTO_OBJECT_HANDLE(relation->local_crypto); + result = true; + +invalid_handle: + CRYPTO_OBJECT_RELEASE(relation); + CRYPTO_OBJECT_RELEASE(loc_pp); + CRYPTO_OBJECT_RELEASE(rmt_pp); + return result; +} + +bool +crypto_factory_get_specific_keymat( + const dds_security_crypto_key_factory *factory, + CryptoObjectKind_t kind, + DDS_Security_Handle rmt_handle, + const struct receiver_specific_mac * const mac_list, + uint32_t num_mac, + uint32_t *index, + master_key_material **key_mat) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + CryptoObject *obj; + remote_participant_crypto *rmt_pp = NULL; + remote_datawriter_crypto *rmt_wr = NULL; + remote_datareader_crypto *rmt_rd = NULL; + key_relation *relation = NULL; + bool result = false; + + obj = crypto_object_table_find(impl->crypto_objects, rmt_handle); + if (!obj) + return false; + + switch (kind) + { + case CRYPTO_OBJECT_KIND_REMOTE_CRYPTO: + rmt_pp = (remote_participant_crypto *)obj; + break; + case CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO: + rmt_wr = (remote_datawriter_crypto *)obj; + rmt_pp = rmt_wr->participant; + break; + case CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO: + rmt_rd = (remote_datareader_crypto *)obj; + rmt_pp = rmt_rd->participant; + break; + default: + goto invalid_handle; + break; + } + + for (uint32_t i = 0; i < num_mac; i++) + { + uint32_t key_id = CRYPTO_TRANSFORM_ID(mac_list[i].receiver_mac_key_id); + relation = crypto_find_specific_key_relation(rmt_pp, key_id); + if (relation) + { + *index = i; + *key_mat = CRYPTO_OBJECT_KEEP(relation->key_material); + result = true; + break; + } + } + +invalid_handle: + CRYPTO_OBJECT_RELEASE(relation); + CRYPTO_OBJECT_RELEASE(obj); + return result; +} + +master_key_material * +crypto_factory_get_master_key_material_for_test( + const dds_security_crypto_key_factory *factory, + DDS_Security_ParticipantCryptoHandle local_id, + DDS_Security_ParticipantCryptoHandle remote_id) +{ + dds_security_crypto_key_factory_impl *impl = (dds_security_crypto_key_factory_impl *)factory; + remote_participant_crypto *rmt_cr = (remote_participant_crypto *)crypto_object_table_find(impl->crypto_objects, remote_id); + participant_key_material *keymat; + master_key_material *master_keymat = NULL; + + if (rmt_cr) + { + keymat = crypto_remote_participant_lookup_keymat(rmt_cr, local_id); + if (keymat) + { + master_keymat = keymat->local_P2P_key_material; + CRYPTO_OBJECT_RELEASE(keymat); + } + } + + return master_keymat; +} diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.h b/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.h new file mode 100644 index 0000000..66538f4 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_key_factory.h @@ -0,0 +1,169 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTO_KEY_FACTORY_H +#define CRYPTO_KEY_FACTORY_H + +#include "dds/security/dds_security_api.h" +#include "crypto_objects.h" +#include "dds/security/export.h" + +/** + * @brief Allocation function for implementer structure (with internal variables) transparently. + */ +dds_security_crypto_key_factory * +dds_security_crypto_key_factory__alloc( + const dds_security_cryptography *crypto); + +void dds_security_crypto_key_factory__dealloc( + dds_security_crypto_key_factory *instance); + +int generate_key_pairs( + char **private_key, + char **public_key); + +bool crypto_factory_get_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, + DDS_Security_ParticipantCryptoHandle remote_id, + participant_key_material **pp_key_material, + master_key_material **remote_key_matarial, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_set_participant_crypto_tokens( + const dds_security_crypto_key_factory *factory, + const DDS_Security_ParticipantCryptoHandle local_id, + const DDS_Security_ParticipantCryptoHandle remote_id, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *remote_key_mat, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_datawriter_crypto_tokens( + const dds_security_crypto_key_factory *factory, + DDS_Security_DatawriterCryptoHandle local_writer_handle, + DDS_Security_DatareaderCryptoHandle remote_reader_handle, + master_key_material **key_mat, + uint32_t *num_key_mat, + DDS_Security_SecurityException *ex); + +bool crypto_factory_set_datawriter_crypto_tokens( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle local_reader_handle, + const DDS_Security_DatareaderCryptoHandle remote_writer_handle, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *key_mat, + const uint32_t num_key_mat, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_datareader_crypto_tokens( + const dds_security_crypto_key_factory *factory, + DDS_Security_DatawriterCryptoHandle local_reader_handle, + DDS_Security_DatareaderCryptoHandle remote_writer_handle, + master_key_material **key_mat, + DDS_Security_SecurityException *ex); + +bool crypto_factory_set_datareader_crypto_tokens( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle local_writer_handle, + const DDS_Security_DatareaderCryptoHandle remote_reader_handle, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *key_mat, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_writer_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle writer_id, + const DDS_Security_DatareaderCryptoHandle reader_id, + bool payload, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_reader_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle reader_id, + const DDS_Security_DatawriterCryptoHandle writer_id, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_remote_writer_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle reader_id, + const DDS_Security_DatawriterCryptoHandle writer_id, + uint32_t key_id, + master_key_material **master_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_BasicProtectionKind *basic_protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_local_participant_data_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_ParticipantCryptoHandle local_id, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_remote_reader_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatawriterCryptoHandle writer_id, + const DDS_Security_DatareaderCryptoHandle reader_id, + uint32_t key_id, + master_key_material **master_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_remote_writer_sign_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle writer_id, + master_key_material **key_material, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_remote_reader_sign_key_material( + const dds_security_crypto_key_factory *factory, + const DDS_Security_DatareaderCryptoHandle reader_id, + master_key_material **key_material, + session_key_material **session_key, + DDS_Security_ProtectionKind *protection_kind, + DDS_Security_SecurityException *ex); + +bool crypto_factory_get_endpoint_relation( + const dds_security_crypto_key_factory *factory, + DDS_Security_ParticipantCryptoHandle local_participant_handle, + DDS_Security_ParticipantCryptoHandle remote_participant_handle, + uint32_t key_id, + DDS_Security_Handle *remote_handle, + DDS_Security_Handle *local_handle, + DDS_Security_SecureSubmessageCategory_t *category, + DDS_Security_SecurityException *ex); + +bool +crypto_factory_get_specific_keymat( + const dds_security_crypto_key_factory *factory, + CryptoObjectKind_t kind, + DDS_Security_Handle rmt_handle, + const struct receiver_specific_mac * const mac_list, + uint32_t num_mac, + uint32_t *index, + master_key_material **key_mat); + +SECURITY_EXPORT master_key_material * +crypto_factory_get_master_key_material_for_test( + const dds_security_crypto_key_factory *factory, + DDS_Security_ParticipantCryptoHandle local_id, + DDS_Security_ParticipantCryptoHandle remote_id); + +#endif /* CRYPTO_KEY_FACTORY_H */ diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_objects.c b/src/security/builtin_plugins/cryptographic/src/crypto_objects.c new file mode 100644 index 0000000..9a9cf05 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_objects.c @@ -0,0 +1,788 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/hopscotch.h" +#include "dds/ddsrt/types.h" +#include "crypto_objects.h" +#include "crypto_utils.h" + +static int compare_participant_handle(const void *va, const void *vb); +static int compare_endpoint_relation (const void *va, const void *vb); +static int compare_relation_key (const void *va, const void *vb); +static void key_relation_free(CryptoObject *obj); + +const ddsrt_avl_ctreedef_t loc_pp_keymat_treedef = + DDSRT_AVL_CTREEDEF_INITIALIZER (offsetof (struct participant_key_material, loc_avlnode), offsetof (struct participant_key_material, rmt_pp_handle), compare_participant_handle, 0); + +const ddsrt_avl_ctreedef_t rmt_pp_keymat_treedef = + DDSRT_AVL_CTREEDEF_INITIALIZER (offsetof (struct participant_key_material, rmt_avlnode), offsetof (struct participant_key_material, loc_pp_handle), compare_participant_handle, 0); + +const ddsrt_avl_treedef_t endpoint_relation_treedef = + DDSRT_AVL_TREEDEF_INITIALIZER (offsetof (struct key_relation, avlnode), 0, compare_endpoint_relation, 0); + +const ddsrt_avl_treedef_t specific_key_treedef = + DDSRT_AVL_TREEDEF_INITIALIZER (offsetof (struct key_relation, avlnode), offsetof (struct key_relation, key_id), compare_relation_key, 0); + + +static int compare_participant_handle(const void *va, const void *vb) +{ + const DDS_Security_ParticipantCryptoHandle *ha = va; + const DDS_Security_ParticipantCryptoHandle *hb = vb; + + if (*ha > *hb) + return 1; + else if (*ha < *hb) + return -1; + return 0; +} + +static int compare_endpoint_relation (const void *va, const void *vb) +{ + const key_relation *ra = va; + const key_relation *rb = vb; + if (ra->key_id > rb->key_id) + return 1; + else if (ra->key_id < rb->key_id) + return -1; + else if ((uintptr_t) ra->local_crypto > (uintptr_t) rb->local_crypto) + return 1; + else if ((uintptr_t) ra->local_crypto < (uintptr_t) rb->local_crypto) + return -1; + else + return 0; +} + +static int compare_relation_key (const void *va, const void *vb) +{ + const uint32_t *ka = va; + const uint32_t *kb = vb; + return (*ka == *kb) ? 0 : (*ka < *kb) ? -1 : 1; +} + +bool crypto_object_valid(CryptoObject *obj, CryptoObjectKind_t kind) +{ + return (obj && obj->kind == kind && obj->handle == (int64_t)(uintptr_t)obj); +} + +static uint32_t crypto_object_hash(const void *obj) +{ + const CryptoObject *object = obj; + const uint64_t c = UINT64_C (16292676669999574021); + const uint32_t x = (uint32_t)object->handle; + return (uint32_t)((x * c) >> 32); +} + +static int crypto_object_equal(const void *ha, const void *hb) +{ + const CryptoObject *la = ha; + const CryptoObject *lb = hb; + return la->handle == lb->handle; +} + +void crypto_object_init(CryptoObject *obj, CryptoObjectKind_t kind, CryptoObjectDestructor destructor) +{ + assert(obj); + obj->kind = kind; + obj->handle = (int64_t)(uintptr_t)obj; + obj->destructor = destructor; + ddsrt_atomic_st32 (&obj->refcount, 1); +} + +static void crypto_object_deinit(CryptoObject *obj) +{ + assert(obj); + obj->handle = DDS_SECURITY_HANDLE_NIL; + obj->kind = CRYPTO_OBJECT_KIND_UNKNOWN; + obj->destructor = NULL; +} + +void crypto_object_free(CryptoObject *obj) +{ + + if (obj && obj->destructor) + obj->destructor(obj); +} + +void * crypto_object_keep(CryptoObject *obj) +{ + if (obj) + ddsrt_atomic_inc32(&obj->refcount); + return obj; +} + +void crypto_object_release(CryptoObject *obj) +{ + if (obj && ddsrt_atomic_dec32_nv(&obj->refcount) == 0) + crypto_object_free(obj); +} + +CryptoObject * crypto_object_table_find_by_template(const struct CryptoObjectTable *table, const void *template) +{ + return (CryptoObject *)ddsrt_hh_lookup(table->htab, template); +} + +static CryptoObject * default_crypto_table_find(const struct CryptoObjectTable *table, const void *arg) +{ + struct CryptoObject template; + template.handle = *(int64_t *)arg; + return crypto_object_table_find_by_template(table, &template); +} + +struct CryptoObjectTable * crypto_object_table_new(CryptoObjectHashFunction hashfnc, CryptoObjectEqualFunction equalfnc, CryptoObjectFindFunction findfnc) +{ + struct CryptoObjectTable *table; + if (!hashfnc) + hashfnc = crypto_object_hash; + if (!equalfnc) + equalfnc = crypto_object_equal; + table = ddsrt_malloc(sizeof(*table)); + table->htab = ddsrt_hh_new(32, hashfnc, equalfnc); + ddsrt_mutex_init(&table->lock); + table->findfnc = findfnc ? findfnc : default_crypto_table_find; + return table; +} + +void crypto_object_table_free(struct CryptoObjectTable *table) +{ + struct ddsrt_hh_iter it; + CryptoObject *obj; + + if (!table) + return; + + ddsrt_mutex_lock(&table->lock); + for (obj = ddsrt_hh_iter_first(table->htab, &it); obj; obj = ddsrt_hh_iter_next(&it)) + { + ddsrt_hh_remove(table->htab, obj); + crypto_object_release(obj); + } + ddsrt_hh_free(table->htab); + ddsrt_mutex_unlock(&table->lock); + ddsrt_mutex_destroy(&table->lock); + ddsrt_free(table); +} + +CryptoObject * crypto_object_table_insert(struct CryptoObjectTable *table, CryptoObject *object) +{ + CryptoObject *cur; + + assert(table); + assert(object); + + ddsrt_mutex_lock(&table->lock); + if (!(cur = crypto_object_keep (table->findfnc(table, &object->handle)))) + ddsrt_hh_add(table->htab, crypto_object_keep(object)); + else + crypto_object_release(cur); + ddsrt_mutex_unlock(&table->lock); + + return cur; +} + +void crypto_object_table_remove_object(struct CryptoObjectTable *table, CryptoObject *object) +{ + assert (table); + assert (object); + + ddsrt_mutex_lock (&table->lock); + ddsrt_hh_remove (table->htab, object); + ddsrt_mutex_unlock (&table->lock); + + crypto_object_release (object); +} + +CryptoObject * crypto_object_table_remove(struct CryptoObjectTable *table, int64_t handle) +{ + CryptoObject *object; + assert (table); + ddsrt_mutex_lock (&table->lock); + if ((object = crypto_object_keep (table->findfnc(table, &handle)))) + { + ddsrt_hh_remove (table->htab, object); + crypto_object_release (object); + } + ddsrt_mutex_unlock (&table->lock); + + return object; +} + +CryptoObject * crypto_object_table_find(struct CryptoObjectTable *table, int64_t handle) +{ + CryptoObject *object; + assert (table); + ddsrt_mutex_lock (&table->lock); + object = crypto_object_keep (table->findfnc(table, &handle)); + ddsrt_mutex_unlock (&table->lock); + + return object; +} + +void crypto_object_table_walk(struct CryptoObjectTable *table, CryptoObjectTableCallback callback, void *arg) +{ + struct ddsrt_hh_iter it; + CryptoObject *obj; + int r = 1; + + assert(table); + assert(callback); + ddsrt_mutex_lock (&table->lock); + for (obj = ddsrt_hh_iter_first (table->htab, &it); r && obj; obj = ddsrt_hh_iter_next (&it)) + r = callback(obj, arg); + ddsrt_mutex_unlock(&table->lock); +} + +static void master_key_material__free(CryptoObject *obj) +{ + master_key_material *keymat = (master_key_material *)obj; + if (obj) + { + CHECK_CRYPTO_OBJECT_KIND(obj, CRYPTO_OBJECT_KIND_KEY_MATERIAL); + if (CRYPTO_TRANSFORM_HAS_KEYS(keymat->transformation_kind)) + { + ddsrt_free (keymat->master_salt); + ddsrt_free (keymat->master_sender_key); + ddsrt_free (keymat->master_receiver_specific_key); + } + crypto_object_deinit ((CryptoObject *)keymat); + memset (keymat, 0, sizeof (*keymat)); + ddsrt_free (keymat); + } +} + +master_key_material * crypto_master_key_material_new(DDS_Security_CryptoTransformKind_Enum transform_kind) +{ + master_key_material *keymat = ddsrt_calloc (1, sizeof(*keymat)); + crypto_object_init((CryptoObject *)keymat, CRYPTO_OBJECT_KIND_KEY_MATERIAL, master_key_material__free); + keymat->transformation_kind = transform_kind; + if (CRYPTO_TRANSFORM_HAS_KEYS(transform_kind)) + { + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(keymat->transformation_kind); + keymat->master_salt = ddsrt_calloc(1, key_bytes); + keymat->master_sender_key = ddsrt_calloc(1, key_bytes); + keymat->master_receiver_specific_key = ddsrt_calloc(1, key_bytes); + } + return keymat; +} + +void crypto_master_key_material_set(master_key_material *dst, const master_key_material *src) +{ + if (CRYPTO_TRANSFORM_HAS_KEYS(dst->transformation_kind) && !CRYPTO_TRANSFORM_HAS_KEYS(src->transformation_kind)) + { + ddsrt_free(dst->master_salt); + ddsrt_free(dst->master_sender_key); + ddsrt_free(dst->master_receiver_specific_key); + } + else if (CRYPTO_TRANSFORM_HAS_KEYS(src->transformation_kind)) + { + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(src->transformation_kind); + if (!CRYPTO_TRANSFORM_HAS_KEYS(dst->transformation_kind)) + { + dst->master_salt = ddsrt_calloc(1, key_bytes); + dst->master_sender_key = ddsrt_calloc(1, key_bytes); + dst->master_receiver_specific_key = ddsrt_calloc(1, key_bytes); + } + memcpy (dst->master_salt, src->master_salt, key_bytes); + dst->sender_key_id = src->sender_key_id; + memcpy (dst->master_sender_key, src->master_sender_key, key_bytes); + /* Fixme: set the receiver specific key? */ + dst->receiver_specific_key_id = 0; + } + dst->transformation_kind = src->transformation_kind; +} + +static bool generate_session_key(session_key_material *session, DDS_Security_SecurityException *ex) +{ + session->id++; + session->block_counter = 0; + return crypto_calculate_session_key(&session->key, session->id, session->master_key_material->master_salt, session->master_key_material->master_sender_key, session->master_key_material->transformation_kind, ex); +} + +static void session_key_material__free(CryptoObject *obj) +{ + session_key_material *session = (session_key_material *)obj; + if (obj) + { + CHECK_CRYPTO_OBJECT_KIND(obj, CRYPTO_OBJECT_KIND_SESSION_KEY_MATERIAL); + CRYPTO_OBJECT_RELEASE(session->master_key_material); + crypto_object_deinit((CryptoObject *)session); + memset (session, 0, sizeof (*session)); + ddsrt_free(session); + } +} + +session_key_material * crypto_session_key_material_new(master_key_material *master_key) +{ + session_key_material *session = ddsrt_malloc(sizeof(*session)); + crypto_object_init((CryptoObject *)session, CRYPTO_OBJECT_KIND_SESSION_KEY_MATERIAL, session_key_material__free); + memset (session->key.data, 0, CRYPTO_KEY_SIZE_MAX); + session->block_size = CRYPTO_CIPHER_BLOCK_SIZE; + session->key_size = crypto_get_key_size(master_key->transformation_kind); + session->id = crypto_get_random_uint32(); + session->init_vector_suffix = crypto_get_random_uint64(); + session->max_blocks_per_session = INT64_MAX; /* FIXME: should be a config parameter */ + session->block_counter = session->max_blocks_per_session; + session->master_key_material = CRYPTO_OBJECT_KEEP(master_key); + + return session; +} + +bool crypto_session_key_material_update(session_key_material *session, uint32_t size, DDS_Security_SecurityException *ex) +{ + if (session->block_counter + (size / session->block_size) >= session->max_blocks_per_session) + return generate_session_key(session, ex); + return true; +} + +static void local_participant_crypto__free(CryptoObject *obj) +{ + local_participant_crypto *participant_crypto = (local_participant_crypto *)obj; + if (participant_crypto) + { + CHECK_CRYPTO_OBJECT_KIND (obj, CRYPTO_OBJECT_KIND_LOCAL_CRYPTO); + CRYPTO_OBJECT_RELEASE (participant_crypto->session); + CRYPTO_OBJECT_RELEASE (participant_crypto->key_material); + ddsrt_avl_cfree(&loc_pp_keymat_treedef, &participant_crypto->key_material_table, 0); + crypto_object_deinit ((CryptoObject *)participant_crypto); + ddsrt_mutex_init(&participant_crypto->lock); + ddsrt_free (participant_crypto); + } +} + +local_participant_crypto * crypto_local_participant_crypto__new(DDS_Security_IdentityHandle participant_identity) +{ + assert (participant_identity); + assert (sizeof(DDS_Security_ParticipantCryptoHandle) == 8); + local_participant_crypto *participant_crypto = ddsrt_calloc (1, sizeof(*participant_crypto)); + participant_crypto->identity_handle = participant_identity; + crypto_object_init ((CryptoObject *)participant_crypto, CRYPTO_OBJECT_KIND_LOCAL_CRYPTO, local_participant_crypto__free); + ddsrt_mutex_init(&participant_crypto->lock); + ddsrt_avl_cinit(&loc_pp_keymat_treedef, &participant_crypto->key_material_table); + + return participant_crypto; +} + +static void remote_participant_crypto__free(CryptoObject *obj) +{ + remote_participant_crypto *participant_crypto = (remote_participant_crypto *)obj; + + CHECK_CRYPTO_OBJECT_KIND (obj, CRYPTO_OBJECT_KIND_REMOTE_CRYPTO); + if (participant_crypto) + { + CRYPTO_OBJECT_RELEASE (participant_crypto->session); + ddsrt_avl_cfree(&rmt_pp_keymat_treedef, &participant_crypto->key_material_table, 0); + crypto_object_deinit ((CryptoObject *)participant_crypto); + ddsrt_avl_free(&endpoint_relation_treedef, &participant_crypto->relation_index, 0); + ddsrt_avl_free(&specific_key_treedef, &participant_crypto->specific_key_index, 0); + ddsrt_mutex_destroy(&participant_crypto->lock); + ddsrt_free(participant_crypto); + } +} + +remote_participant_crypto * crypto_remote_participant_crypto__new(DDS_Security_IdentityHandle participant_identity) +{ + assert (participant_identity); + remote_participant_crypto *participant_crypto = ddsrt_calloc (1, sizeof(*participant_crypto)); + crypto_object_init ((CryptoObject *)participant_crypto, CRYPTO_OBJECT_KIND_REMOTE_CRYPTO, remote_participant_crypto__free); + participant_crypto->identity_handle = participant_identity; + ddsrt_avl_cinit(&rmt_pp_keymat_treedef, &participant_crypto->key_material_table); + ddsrt_mutex_init(&participant_crypto->lock); + ddsrt_avl_init(&endpoint_relation_treedef, &participant_crypto->relation_index); + ddsrt_avl_init(&specific_key_treedef, &participant_crypto->specific_key_index); + + return participant_crypto; +} + + +static void participant_key_material_free(CryptoObject *obj) +{ + participant_key_material *keymaterial = (participant_key_material *)obj; + CHECK_CRYPTO_OBJECT_KIND(obj, CRYPTO_OBJECT_KIND_PARTICIPANT_KEY_MATERIAL); + if (keymaterial) + { + CRYPTO_OBJECT_RELEASE(keymaterial->P2P_writer_session); + CRYPTO_OBJECT_RELEASE(keymaterial->P2P_reader_session); + CRYPTO_OBJECT_RELEASE(keymaterial->P2P_kx_key_material); + CRYPTO_OBJECT_RELEASE(keymaterial->local_P2P_key_material); + CRYPTO_OBJECT_RELEASE(keymaterial->remote_key_material); + crypto_object_deinit((CryptoObject *)keymaterial); + ddsrt_free(keymaterial); + } +} + +participant_key_material * crypto_participant_key_material_new(const local_participant_crypto *loc_pp_crypto, const remote_participant_crypto *rmt_pp_crypto) +{ + participant_key_material *keymaterial = ddsrt_calloc(1, sizeof(*keymaterial)); + crypto_object_init((CryptoObject *)keymaterial, CRYPTO_OBJECT_KIND_PARTICIPANT_KEY_MATERIAL, participant_key_material_free); + keymaterial->loc_pp_handle = PARTICIPANT_CRYPTO_HANDLE(loc_pp_crypto); + keymaterial->rmt_pp_handle = PARTICIPANT_CRYPTO_HANDLE(rmt_pp_crypto); + keymaterial->local_P2P_key_material = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_NONE); + keymaterial->P2P_kx_key_material = crypto_master_key_material_new(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); /* as defined in table 67 of the DDS Security spec v1.1 */ + + return keymaterial; +} + +void crypto_local_participant_add_keymat(local_participant_crypto *loc_pp_crypto, participant_key_material *keymat) +{ + ddsrt_mutex_lock(&loc_pp_crypto->lock); + ddsrt_avl_cinsert(&loc_pp_keymat_treedef, &loc_pp_crypto->key_material_table, CRYPTO_OBJECT_KEEP(keymat)); + ddsrt_mutex_unlock(&loc_pp_crypto->lock); +} + +participant_key_material * crypto_local_participant_remove_keymat(local_participant_crypto *loc_pp_crypto, DDS_Security_ParticipantCryptoHandle rmt_pp_handle) +{ + participant_key_material *keymat; + ddsrt_avl_dpath_t dpath; + + ddsrt_mutex_lock(&loc_pp_crypto->lock); + keymat = ddsrt_avl_clookup_dpath(&loc_pp_keymat_treedef, &loc_pp_crypto->key_material_table, &rmt_pp_handle, &dpath); + if (keymat) + ddsrt_avl_cdelete_dpath(&loc_pp_keymat_treedef, &loc_pp_crypto->key_material_table, keymat, &dpath); + ddsrt_mutex_unlock(&loc_pp_crypto->lock); + + return keymat; +} + +participant_key_material * crypto_local_participant_lookup_keymat(local_participant_crypto *loc_pp_crypto, DDS_Security_ParticipantCryptoHandle rmt_pp_handle) +{ + participant_key_material *keymat; + + ddsrt_mutex_lock(&loc_pp_crypto->lock); + keymat = CRYPTO_OBJECT_KEEP(ddsrt_avl_clookup(&loc_pp_keymat_treedef, &loc_pp_crypto->key_material_table, &rmt_pp_handle)); + ddsrt_mutex_unlock(&loc_pp_crypto->lock); + + return keymat; +} + +void crypto_remote_participant_add_keymat(remote_participant_crypto *rmt_pp_crypto, participant_key_material *keymat) +{ + ddsrt_mutex_lock(&rmt_pp_crypto->lock); + ddsrt_avl_cinsert(&rmt_pp_keymat_treedef, &rmt_pp_crypto->key_material_table, CRYPTO_OBJECT_KEEP(keymat)); + ddsrt_mutex_unlock(&rmt_pp_crypto->lock); +} + +participant_key_material * crypto_remote_participant_remove_keymat_locked(remote_participant_crypto *rmt_pp_crypto, DDS_Security_ParticipantCryptoHandle loc_pp_handle) +{ + participant_key_material *keymat; + ddsrt_avl_dpath_t dpath; + + keymat = ddsrt_avl_clookup_dpath(&rmt_pp_keymat_treedef, &rmt_pp_crypto->key_material_table, &loc_pp_handle, &dpath); + if (keymat) + ddsrt_avl_cdelete_dpath(&rmt_pp_keymat_treedef, &rmt_pp_crypto->key_material_table, keymat, &dpath); + + return keymat; +} + +participant_key_material * crypto_remote_participant_lookup_keymat_locked(remote_participant_crypto *rmt_pp_crypto, DDS_Security_ParticipantCryptoHandle loc_pp_handle) +{ + return CRYPTO_OBJECT_KEEP(ddsrt_avl_clookup(&rmt_pp_keymat_treedef, &rmt_pp_crypto->key_material_table, &loc_pp_handle)); +} + +participant_key_material * crypto_remote_participant_lookup_keymat(remote_participant_crypto *rmt_pp_crypto, DDS_Security_ParticipantCryptoHandle loc_pp_handle) +{ + participant_key_material *keymat; + ddsrt_mutex_lock(&rmt_pp_crypto->lock); + keymat = crypto_remote_participant_lookup_keymat_locked(rmt_pp_crypto, loc_pp_handle); + ddsrt_mutex_unlock(&rmt_pp_crypto->lock); + return keymat; +} + +size_t crypto_local_participnant_get_matching(local_participant_crypto *loc_pp_crypto, DDS_Security_ParticipantCryptoHandle **handles) +{ + participant_key_material *keymat; + ddsrt_avl_citer_t it; + size_t num, i; + + ddsrt_mutex_lock(&loc_pp_crypto->lock); + num = ddsrt_avl_ccount(&loc_pp_crypto->key_material_table); + if (num > 0) + { + *handles = ddsrt_malloc(num * sizeof(DDS_Security_ParticipantCryptoHandle)); + for (i = 0, keymat = ddsrt_avl_citer_first(&loc_pp_keymat_treedef, &loc_pp_crypto->key_material_table, &it); i < num && keymat; i++, keymat = ddsrt_avl_citer_next(&it)) + (*handles)[i] = keymat->rmt_pp_handle; + } + ddsrt_mutex_unlock(&loc_pp_crypto->lock); + return num; +} + +size_t crypto_remote_participnant_get_matching(remote_participant_crypto *rmt_pp_crypto, DDS_Security_ParticipantCryptoHandle **handles) +{ + participant_key_material *keymat; + ddsrt_avl_citer_t it; + size_t num, i; + + ddsrt_mutex_lock(&rmt_pp_crypto->lock); + num = ddsrt_avl_ccount(&rmt_pp_crypto->key_material_table); + if (num > 0) + { + *handles = ddsrt_malloc(num * sizeof(DDS_Security_ParticipantCryptoHandle)); + for (i = 0, keymat = ddsrt_avl_citer_first(&rmt_pp_keymat_treedef, &rmt_pp_crypto->key_material_table, &it); i < num && keymat; i++, keymat = ddsrt_avl_citer_next(&it)) + (*handles)[i] = keymat->loc_pp_handle; + } + ddsrt_mutex_unlock(&rmt_pp_crypto->lock); + return num; +} + +static void key_relation_free(CryptoObject *obj) +{ + key_relation *relation = (key_relation *)obj; + if (relation) + { + CRYPTO_OBJECT_RELEASE(relation->key_material); + CRYPTO_OBJECT_RELEASE(relation->local_crypto); + CRYPTO_OBJECT_RELEASE(relation->remote_crypto); + crypto_object_deinit((CryptoObject *)relation); + ddsrt_free(relation); + } +} + +key_relation * crypto_key_relation_new(DDS_Security_SecureSubmessageCategory_t kind, + uint32_t key_id, CryptoObject *local_crypto, CryptoObject *remote_crypto, master_key_material *keymat) +{ + key_relation *relation = ddsrt_malloc(sizeof(*relation)); + crypto_object_init((CryptoObject *)relation, CRYPTO_OBJECT_KIND_RELATION, key_relation_free); + + relation->kind = kind; + relation->key_id = key_id; + relation->local_crypto = CRYPTO_OBJECT_KEEP(local_crypto); + relation->remote_crypto = CRYPTO_OBJECT_KEEP(remote_crypto); + relation->key_material = (master_key_material *)CRYPTO_OBJECT_KEEP(keymat); + + return relation; +} + +static void local_datawriter_crypto__free(CryptoObject *obj) +{ + local_datawriter_crypto *datawriter_crypto = (local_datawriter_crypto *)obj; + + if (obj) + { + CHECK_CRYPTO_OBJECT_KIND(obj, CRYPTO_OBJECT_KIND_LOCAL_WRITER_CRYPTO); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->writer_session_message); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->writer_session_payload); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->writer_key_material_message); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->writer_key_material_payload); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->participant); + crypto_object_deinit((CryptoObject *)datawriter_crypto); + ddsrt_free(datawriter_crypto); + } +} + +local_datawriter_crypto * crypto_local_datawriter_crypto__new(const local_participant_crypto *participant, + DDS_Security_ProtectionKind meta_protection, DDS_Security_BasicProtectionKind data_protection) +{ + local_datawriter_crypto *writer_crypto = ddsrt_calloc(1, sizeof(*writer_crypto)); + crypto_object_init((CryptoObject *)writer_crypto, CRYPTO_OBJECT_KIND_LOCAL_WRITER_CRYPTO, local_datawriter_crypto__free); + writer_crypto->participant = (local_participant_crypto *)CRYPTO_OBJECT_KEEP(participant); + writer_crypto->metadata_protectionKind = meta_protection; + writer_crypto->data_protectionKind = data_protection; + writer_crypto->is_builtin_participant_volatile_message_secure_writer = false; + + return writer_crypto; +} + + +static void remote_datawriter_crypto__free(CryptoObject *obj) +{ + remote_datawriter_crypto *datawriter_crypto = (remote_datawriter_crypto *)obj; + if (datawriter_crypto) + { + CHECK_CRYPTO_OBJECT_KIND(obj, CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->reader_session); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->reader2writer_key_material); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->writer2reader_key_material[0]); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->writer2reader_key_material[1]); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->local_reader); + CRYPTO_OBJECT_RELEASE(datawriter_crypto->participant); + crypto_object_deinit((CryptoObject *)datawriter_crypto); + ddsrt_free(datawriter_crypto); + } +} + +remote_datawriter_crypto * crypto_remote_datawriter_crypto__new(const remote_participant_crypto *participant, + DDS_Security_ProtectionKind meta_protection, DDS_Security_BasicProtectionKind data_protection, 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 = (local_datareader_crypto *)CRYPTO_OBJECT_KEEP(local_reader); + writer_crypto->is_builtin_participant_volatile_message_secure_writer = false; + + return writer_crypto; +} + + +static void local_datareader_crypto__free(CryptoObject *obj) +{ + local_datareader_crypto *datareader_crypto = (local_datareader_crypto *)obj; + if (datareader_crypto) + { + CHECK_CRYPTO_OBJECT_KIND(obj, CRYPTO_OBJECT_KIND_LOCAL_READER_CRYPTO); + CRYPTO_OBJECT_RELEASE(datareader_crypto->reader_session); + CRYPTO_OBJECT_RELEASE(datareader_crypto->reader_key_material); + CRYPTO_OBJECT_RELEASE(datareader_crypto->participant); + crypto_object_deinit((CryptoObject *)datareader_crypto); + ddsrt_free(datareader_crypto); + } +} + +local_datareader_crypto * crypto_local_datareader_crypto__new(const local_participant_crypto *participant, + DDS_Security_ProtectionKind meta_protection, DDS_Security_BasicProtectionKind data_protection) +{ + local_datareader_crypto *reader_crypto = ddsrt_calloc(1, sizeof(*reader_crypto)); + crypto_object_init((CryptoObject *)reader_crypto, CRYPTO_OBJECT_KIND_LOCAL_READER_CRYPTO, local_datareader_crypto__free); + reader_crypto->participant = (local_participant_crypto *)CRYPTO_OBJECT_KEEP(participant); + reader_crypto->metadata_protectionKind = meta_protection; + reader_crypto->data_protectionKind = data_protection; + reader_crypto->is_builtin_participant_volatile_message_secure_reader = false; + + return reader_crypto; +} + + +static void remote_datareader_crypto__free(CryptoObject *obj) +{ + remote_datareader_crypto *datareader_crypto = (remote_datareader_crypto *)obj; + if (datareader_crypto) + { + CHECK_CRYPTO_OBJECT_KIND(obj, CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO); + CRYPTO_OBJECT_RELEASE(datareader_crypto->writer_session); + CRYPTO_OBJECT_RELEASE(datareader_crypto->reader2writer_key_material); + CRYPTO_OBJECT_RELEASE(datareader_crypto->writer2reader_key_material_message); + CRYPTO_OBJECT_RELEASE(datareader_crypto->writer2reader_key_material_payload); + CRYPTO_OBJECT_RELEASE(datareader_crypto->local_writer); + CRYPTO_OBJECT_RELEASE(datareader_crypto->participant); + crypto_object_deinit((CryptoObject *)datareader_crypto); + ddsrt_free(datareader_crypto); + } +} + +remote_datareader_crypto *crypto_remote_datareader_crypto__new(const remote_participant_crypto *participant, DDS_Security_ProtectionKind metadata_protectionKind, + DDS_Security_BasicProtectionKind data_protectionKind, 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 = (local_datawriter_crypto *)CRYPTO_OBJECT_KEEP(local_writer); + reader_crypto->is_builtin_participant_volatile_message_secure_reader = false; + + return reader_crypto; +} + +void crypto_insert_endpoint_relation( + remote_participant_crypto *rpc, + key_relation *relation) +{ + assert (relation->local_crypto != NULL && relation->remote_crypto != NULL); + ddsrt_mutex_lock(&rpc->lock); + ddsrt_avl_insert(&endpoint_relation_treedef, &rpc->relation_index, CRYPTO_OBJECT_KEEP(relation)); + ddsrt_mutex_unlock(&rpc->lock); +} + +void crypto_remove_endpoint_relation( + remote_participant_crypto *rpc, + CryptoObject *lch, + uint32_t key_id) +{ + const key_relation template = { .key_id = key_id, .local_crypto = lch }; + key_relation *relation; + ddsrt_avl_dpath_t dpath; + ddsrt_mutex_lock(&rpc->lock); + relation = ddsrt_avl_lookup_dpath(&endpoint_relation_treedef, &rpc->relation_index, &template, &dpath); + if (relation) + { + ddsrt_avl_delete_dpath(&endpoint_relation_treedef, &rpc->relation_index, relation, &dpath); + CRYPTO_OBJECT_RELEASE(relation); + } + ddsrt_mutex_unlock(&rpc->lock); +} + +key_relation * crypto_find_endpoint_relation( + remote_participant_crypto *rpc, + CryptoObject *lch, + uint32_t key_id) +{ + const key_relation template = { .key_id = key_id, .local_crypto = lch }; + key_relation *relation, *cand; + ddsrt_mutex_lock(&rpc->lock); + if ((cand = ddsrt_avl_lookup_succ_eq (&endpoint_relation_treedef, &rpc->relation_index, &template)) == NULL || cand->key_id != key_id) + relation = NULL; + else + relation = CRYPTO_OBJECT_KEEP (cand); + ddsrt_mutex_unlock(&rpc->lock); + return relation; +} + +void crypto_insert_specific_key_relation_locked( + remote_participant_crypto *rpc, + key_relation *relation) +{ + ddsrt_avl_insert(&specific_key_treedef, &rpc->specific_key_index, CRYPTO_OBJECT_KEEP(relation)); +} + +void crypto_insert_specific_key_relation( + remote_participant_crypto *rpc, + key_relation *relation) +{ + ddsrt_mutex_lock(&rpc->lock); + crypto_insert_specific_key_relation_locked(rpc, relation); + ddsrt_mutex_unlock(&rpc->lock); +} + +void crypto_remove_specific_key_relation_locked( + remote_participant_crypto *rpc, + uint32_t key_id) +{ + key_relation *relation; + ddsrt_avl_dpath_t dpath; + relation = ddsrt_avl_lookup_dpath(&specific_key_treedef, &rpc->specific_key_index, &key_id, &dpath); + if (relation) + { + ddsrt_avl_delete_dpath(&specific_key_treedef, &rpc->specific_key_index, relation, &dpath); + CRYPTO_OBJECT_RELEASE(relation); + } +} + +void crypto_remove_specific_key_relation( + remote_participant_crypto *rpc, + uint32_t key_id) +{ + ddsrt_mutex_lock(&rpc->lock); + crypto_remove_specific_key_relation_locked(rpc, key_id); + ddsrt_mutex_unlock(&rpc->lock); +} + +key_relation * crypto_find_specific_key_relation_locked( + remote_participant_crypto *rpc, + uint32_t key_id) +{ + return CRYPTO_OBJECT_KEEP(ddsrt_avl_lookup(&specific_key_treedef, &rpc->specific_key_index, &key_id)); +} + +key_relation * crypto_find_specific_key_relation( + remote_participant_crypto *rpc, + uint32_t key_id) +{ + key_relation *relation; + + ddsrt_mutex_lock(&rpc->lock); + relation = crypto_find_specific_key_relation_locked(rpc, key_id); + ddsrt_mutex_unlock(&rpc->lock); + + return relation; +} diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_objects.h b/src/security/builtin_plugins/cryptographic/src/crypto_objects.h new file mode 100644 index 0000000..ebb34ed --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_objects.h @@ -0,0 +1,442 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTO_OBJECTS_H +#define CRYPTO_OBJECTS_H + +#include +#include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/avl.h" +#include "dds/ddsrt/sync.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "crypto_defs.h" + +#ifndef NDEBUG +#define CHECK_CRYPTO_OBJECT_KIND(o, k) assert(crypto_object_valid((CryptoObject *)(o), k)) +#else +#define CHECK_CRYPTO_OBJECT_KIND(o, k) +#endif + +#define CRYPTO_OBJECT(o) ((CryptoObject *)(o)) +#define CRYPTO_OBJECT_HANDLE(o) (CRYPTO_OBJECT(o)->handle) +#define PARTICIPANT_CRYPTO_HANDLE(o) ((DDS_Security_ParticipantCryptoHandle)CRYPTO_OBJECT_HANDLE(o)) +#define DATAWRITER_CRYPTO_HANDLE(o) ((DDS_Security_DatawriterCryptoHandle)CRYPTO_OBJECT_HANDLE(o)) +#define DATAREADER_CRYPTO_HANDLE(o) ((DDS_Security_DatareaderCryptoHandle)CRYPTO_OBJECT_HANDLE(o)) + +#define CRYPTO_OBJECT_KEEP(o) crypto_object_keep((CryptoObject *)(o)) +#define CRYPTO_OBJECT_RELEASE(o) crypto_object_release((CryptoObject *)(o)) +#define CRYPTO_OBJECT_VALID(o, k) crypto_object_valid((CryptoObject *)(o), k) + +#define CRYPTO_TRANSFORM_HAS_KEYS(k) ((k) != CRYPTO_TRANSFORMATION_KIND_NONE && (k) != CRYPTO_TRANSFORMATION_KIND_INVALID) + + +typedef DDS_Security_ParticipantCryptoHandle DDS_Security_LocalParticipantCryptoHandle; +typedef DDS_Security_ParticipantCryptoHandle DDS_Security_RemoteParticipantCryptoHandle; + +typedef enum +{ + CRYPTO_OBJECT_KIND_UNKNOWN, + CRYPTO_OBJECT_KIND_LOCAL_CRYPTO, + CRYPTO_OBJECT_KIND_REMOTE_CRYPTO, + CRYPTO_OBJECT_KIND_LOCAL_WRITER_CRYPTO, + CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO, + CRYPTO_OBJECT_KIND_LOCAL_READER_CRYPTO, + CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO, + CRYPTO_OBJECT_KIND_KEY_MATERIAL, + CRYPTO_OBJECT_KIND_SESSION_KEY_MATERIAL, + CRYPTO_OBJECT_KIND_PARTICIPANT_KEY_MATERIAL, + CRYPTO_OBJECT_KIND_RELATION +} CryptoObjectKind_t; + +typedef struct CryptoObject CryptoObject; +typedef void (*CryptoObjectDestructor)(CryptoObject *obj); + +struct CryptoObject +{ + int64_t handle; + ddsrt_atomic_uint32_t refcount; + CryptoObjectKind_t kind; + CryptoObjectDestructor destructor; +}; + +struct local_datawriter_crypto; +struct local_datareader_crypto; +struct remote_datawriter_crypto; +struct remote_datareader_crypto; + +typedef struct master_key_material +{ + CryptoObject _parent; + DDS_Security_CryptoTransformKind_Enum transformation_kind; + unsigned char *master_salt; + uint32_t sender_key_id; + unsigned char *master_sender_key; + uint32_t receiver_specific_key_id; + unsigned char *master_receiver_specific_key; +} master_key_material; + +typedef struct session_key_material +{ + CryptoObject _parent; + uint32_t id; + crypto_session_key_t key; + uint32_t key_size; + uint32_t block_size; + uint64_t block_counter; + uint64_t max_blocks_per_session; + uint64_t init_vector_suffix; + master_key_material *master_key_material; +} session_key_material; + +typedef struct remote_session_info +{ + uint32_t key_size; + uint32_t id; + crypto_session_key_t key; +} remote_session_info; + +typedef struct key_relation +{ + CryptoObject _parent; + ddsrt_avl_node_t avlnode; + DDS_Security_SecureSubmessageCategory_t kind; + uint32_t key_id; + CryptoObject *local_crypto; + CryptoObject *remote_crypto; + master_key_material *key_material; +} key_relation; + +typedef struct local_participant_crypto +{ + CryptoObject _parent; + ddsrt_mutex_t lock; + master_key_material *key_material; + DDS_Security_IdentityHandle identity_handle; + ddsrt_avl_ctree_t key_material_table; + session_key_material *session; + DDS_Security_ProtectionKind rtps_protection_kind; + struct local_datareader_crypto *builtin_reader; +} local_participant_crypto; + +typedef struct participant_key_material +{ + CryptoObject _parent; + ddsrt_avl_node_t loc_avlnode; + ddsrt_avl_node_t rmt_avlnode; + DDS_Security_ParticipantCryptoHandle loc_pp_handle; + DDS_Security_ParticipantCryptoHandle rmt_pp_handle; + master_key_material *remote_key_material; + master_key_material *local_P2P_key_material; + master_key_material *P2P_kx_key_material; + session_key_material *P2P_writer_session; + session_key_material *P2P_reader_session; +} participant_key_material; + +typedef struct remote_participant_crypto +{ + CryptoObject _parent; + ddsrt_mutex_t lock; + DDS_Security_GUID_t remoteGuid; + DDS_Security_IdentityHandle identity_handle; + ddsrt_avl_ctree_t key_material_table; + session_key_material *session; + DDS_Security_ProtectionKind rtps_protection_kind; + ddsrt_avl_tree_t relation_index; + ddsrt_avl_tree_t specific_key_index; +} remote_participant_crypto; + +typedef struct local_datawriter_crypto +{ + CryptoObject _parent; + local_participant_crypto *participant; + master_key_material *writer_key_material_message; + master_key_material *writer_key_material_payload; + session_key_material *writer_session_message; + session_key_material *writer_session_payload; + DDS_Security_ProtectionKind metadata_protectionKind; + DDS_Security_BasicProtectionKind data_protectionKind; + bool is_builtin_participant_volatile_message_secure_writer; +} local_datawriter_crypto; + +typedef struct remote_datawriter_crypto +{ + CryptoObject _parent; + remote_participant_crypto *participant; + DDS_Security_ProtectionKind metadata_protectionKind; + DDS_Security_BasicProtectionKind data_protectionKind; + master_key_material *reader2writer_key_material; + master_key_material *writer2reader_key_material[2]; + session_key_material *reader_session; /* reference to the session key used by the reader */ + struct local_datareader_crypto *local_reader; + bool is_builtin_participant_volatile_message_secure_writer; +} remote_datawriter_crypto; + +typedef struct local_datareader_crypto +{ + CryptoObject _parent; + local_participant_crypto *participant; + master_key_material *reader_key_material; + session_key_material *reader_session; + DDS_Security_ProtectionKind metadata_protectionKind; + DDS_Security_BasicProtectionKind data_protectionKind; + bool is_builtin_participant_volatile_message_secure_reader; +} local_datareader_crypto; + +typedef struct remote_datareader_crypto +{ + CryptoObject _parent; + remote_participant_crypto *participant; + DDS_Security_ProtectionKind metadata_protectionKind; + DDS_Security_BasicProtectionKind data_protectionKind; + master_key_material *reader2writer_key_material; + master_key_material *writer2reader_key_material_message; + master_key_material *writer2reader_key_material_payload; + session_key_material *writer_session; /* reference to the session key used by the writer */ + local_datawriter_crypto *local_writer; + bool is_builtin_participant_volatile_message_secure_reader; +} remote_datareader_crypto; + +master_key_material * +crypto_master_key_material_new(DDS_Security_CryptoTransformKind_Enum transform_kind); + +void crypto_master_key_material_set( + master_key_material *dst, + const master_key_material *src); + +session_key_material * +crypto_session_key_material_new( + master_key_material *master_key); + +bool crypto_session_key_material_update( + session_key_material *session, + uint32_t size, + DDS_Security_SecurityException *ex); + +local_participant_crypto * +crypto_local_participant_crypto__new( + DDS_Security_IdentityHandle participant_identity); + +remote_participant_crypto * +crypto_remote_participant_crypto__new( + DDS_Security_IdentityHandle participant_identity); + +void crypto_object_init( + CryptoObject *obj, + CryptoObjectKind_t kind, + CryptoObjectDestructor destructor); + +key_relation * +crypto_key_relation_new( + DDS_Security_SecureSubmessageCategory_t kind, + uint32_t key_id, + CryptoObject *local_crypto, + CryptoObject *remote_crypto, + master_key_material *keymat); + +void +crypto_insert_endpoint_relation( + remote_participant_crypto *rpc, + key_relation *relation); + +void +crypto_remove_endpoint_relation( + remote_participant_crypto *rpc, + CryptoObject *lch, + uint32_t key_id); + +key_relation * +crypto_find_endpoint_relation( + remote_participant_crypto *rpc, + CryptoObject *lch, + uint32_t key_id); + +void crypto_insert_specific_key_relation_locked( + remote_participant_crypto *rpc, + key_relation *relation); + +void +crypto_insert_specific_key_relation( + remote_participant_crypto *rpc, + key_relation *relation); + +void crypto_remove_specific_key_relation_locked( + remote_participant_crypto *rpc, + uint32_t key_id); + +void +crypto_remove_specific_key_relation( + remote_participant_crypto *rpc, + uint32_t key_id); + +key_relation * crypto_find_specific_key_relation_locked( + remote_participant_crypto *rpc, + uint32_t key_id); + +key_relation * +crypto_find_specific_key_relation( + remote_participant_crypto *rpc, + uint32_t key_id); + +local_datawriter_crypto * +crypto_local_datawriter_crypto__new( + const local_participant_crypto *participant, + DDS_Security_ProtectionKind meta_protection, + DDS_Security_BasicProtectionKind data_protection); + +remote_datareader_crypto * +crypto_remote_datareader_crypto__new( + const remote_participant_crypto *participant, + DDS_Security_ProtectionKind metadata_protectionKind, + DDS_Security_BasicProtectionKind data_protectionKind, + local_datawriter_crypto *local_writer); + +local_datareader_crypto * +crypto_local_datareader_crypto__new( + const local_participant_crypto *participant, + DDS_Security_ProtectionKind meta_protection, + DDS_Security_BasicProtectionKind data_protection); + +remote_datawriter_crypto * +crypto_remote_datawriter_crypto__new( + const remote_participant_crypto *participant, + DDS_Security_ProtectionKind meta_protection, + DDS_Security_BasicProtectionKind data_protection, + local_datareader_crypto *local_reader); + +void * +crypto_object_keep( + CryptoObject *obj); + +void crypto_object_release( + CryptoObject *obj); + +bool crypto_object_valid( + CryptoObject *obj, + CryptoObjectKind_t kind); + +void crypto_object_free( + CryptoObject *obj); + +local_participant_crypto * +crypto_local_participant_crypto__new( + DDS_Security_IdentityHandle participant_identity); + +remote_participant_crypto * +crypto_remote_participant_crypto__new( + DDS_Security_IdentityHandle participant_identity); + +participant_key_material * +crypto_participant_key_material_new( + const local_participant_crypto *loc_pp_crypto, + const remote_participant_crypto *rmt_pp_crypto); + +struct CryptoObjectTable; + +typedef uint32_t (*CryptoObjectHashFunction)(const void *obj); +typedef int (*CryptoObjectEqualFunction)(const void *ha, const void *hb); +typedef CryptoObject *(*CryptoObjectFindFunction)(const struct CryptoObjectTable *table, const void *arg); + +struct CryptoObjectTable * +crypto_object_table_new( + CryptoObjectHashFunction hashfnc, + CryptoObjectEqualFunction equalfnc, + CryptoObjectFindFunction findfnc); + +void crypto_object_table_free( + struct CryptoObjectTable *table); + +CryptoObject * +crypto_object_table_insert( + struct CryptoObjectTable *table, + CryptoObject *object); + +void crypto_object_table_remove_object( + struct CryptoObjectTable *table, + CryptoObject *object); + +CryptoObject * +crypto_object_table_remove( + struct CryptoObjectTable *table, + int64_t handle); + +CryptoObject * +crypto_object_table_find_by_template( + const struct CryptoObjectTable *table, + const void *template); + +CryptoObject * +crypto_object_table_find( + struct CryptoObjectTable *table, + int64_t handle); + +typedef int (*CryptoObjectTableCallback)(CryptoObject *obj, void *arg); + +struct CryptoObjectTable +{ + struct ddsrt_hh *htab; + ddsrt_mutex_t lock; + CryptoObjectFindFunction findfnc; +}; + +void crypto_object_table_walk( + struct CryptoObjectTable *table, + CryptoObjectTableCallback callback, + void *arg); + +void +crypto_local_participant_add_keymat( + local_participant_crypto *loc_pp_crypte, + participant_key_material *keymat); + +participant_key_material * +crypto_local_participant_remove_keymat( + local_participant_crypto *loc_pp_crypte, + DDS_Security_ParticipantCryptoHandle rmt_pp_handle); + +participant_key_material * +crypto_local_participant_lookup_keymat( + local_participant_crypto *loc_pp_crypte, + DDS_Security_ParticipantCryptoHandle rmt_pp_handle); + +void +crypto_remote_participant_add_keymat( + remote_participant_crypto *rmt_pp_crypte, + participant_key_material *keymat); + +participant_key_material * +crypto_remote_participant_remove_keymat_locked( + remote_participant_crypto *rmt_pp_crypte, + DDS_Security_ParticipantCryptoHandle loc_pp_handle); + +participant_key_material * +crypto_remote_participant_lookup_keymat_locked( + remote_participant_crypto *rmt_pp_crypto, + DDS_Security_ParticipantCryptoHandle loc_pp_handle); + +participant_key_material * +crypto_remote_participant_lookup_keymat( + remote_participant_crypto *rmt_pp_crypte, + DDS_Security_ParticipantCryptoHandle loc_pp_handle); + +size_t +crypto_local_participnant_get_matching( + local_participant_crypto *loc_pp_crypto, + DDS_Security_ParticipantCryptoHandle **handles); + +size_t +crypto_remote_participnant_get_matching( + remote_participant_crypto *rmt_pp_crypto, + DDS_Security_ParticipantCryptoHandle **handles); + +#endif /* CRYPTO_OBJECTS_H */ diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_transform.c b/src/security/builtin_plugins/cryptographic/src/crypto_transform.c new file mode 100644 index 0000000..58b1da3 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_transform.c @@ -0,0 +1,2447 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/openssl_support.h" +#include "cryptography.h" +#include "crypto_cipher.h" +#include "crypto_defs.h" +#include "crypto_key_factory.h" +#include "crypto_objects.h" +#include "crypto_transform.h" +#include "crypto_utils.h" + +#define CRYPTO_ENCRYPTION_MAX_PADDING 32 +#define CRYPTO_FOOTER_BASIC_SIZE (CRYPTO_HMAC_SIZE + sizeof(uint32_t)) +#define INFO_SRC_SIZE 24 +#define INFO_SRC_HDR_SIZE 8 +#define RTPS_HEADER_SIZE 20 + +struct submsg_header +{ + unsigned char id; + unsigned char flags; + uint16_t length; +}; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[CRYPTO_SESSION_ID_SIZE]; + unsigned char init_vector_suffix[CRYPTO_INIT_VECTOR_SUFFIX_SIZE]; +}; + +struct crypto_contents +{ + uint32_t _length; + unsigned char _data[]; +}; + +struct crypto_contents_ref +{ + uint32_t _length; + unsigned char *_data; +}; + +struct receiver_specific_mac_seq +{ + uint32_t _length; + struct receiver_specific_mac _buffer[]; +}; + +struct crypto_footer +{ + crypto_hmac_t common_mac; + struct receiver_specific_mac_seq receiver_specific_macs; +}; + +struct encrypted_data +{ + uint32_t length; + unsigned char data[]; +}; + +/* +const DDS_octet INFO_SRC_HDR[] = + { + RTPS_Message_Type_INFO_SRC, + 0x00, // BIG ENDIAN + 0x14, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 + }; +*/ + + +/** + * Implementation structure for storing encapsulated members of the instance + * while giving only the interface definition to user + */ +typedef struct dds_security_crypto_transform_impl +{ + dds_security_crypto_transform base; + const dds_security_cryptography *crypto; +} dds_security_crypto_transform_impl; + +static bool +is_encryption_required( + uint32_t transform_kind) +{ + return ((transform_kind == CRYPTO_TRANSFORMATION_KIND_AES256_GCM) || + (transform_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM)); +} + +static bool +is_authentication_required( + uint32_t transform_kind) +{ + return ((transform_kind == CRYPTO_TRANSFORMATION_KIND_AES256_GMAC) || + (transform_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC)); +} + +static bool +is_encryption_expected( + DDS_Security_ProtectionKind protection_kind) +{ + return ((protection_kind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT) || + (protection_kind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION)); +} + +static bool +is_authentication_expected( + DDS_Security_ProtectionKind protection_kind) +{ + return ((protection_kind == DDS_SECURITY_PROTECTION_KIND_SIGN) || + (protection_kind == DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION)); +} + +static bool +has_origin_authentication( + DDS_Security_ProtectionKind kind) +{ + return ((kind == DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION) || (kind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION)); +} + +static inline bool +crypto_buffer_read_uint32( + uint32_t *value, + unsigned char **ptr, + uint32_t *remain) +{ + if ((*remain) < sizeof(uint32_t)) + return false; + + *value = ddsrt_fromBE4u(*(uint32_t *)(*ptr)); + (*ptr) += sizeof(uint32_t); + (*remain) -= (uint32_t)sizeof(uint32_t); + + return true; +} + +static inline bool +crypto_buffer_read_bytes( + unsigned char *bytes, + uint32_t num, + unsigned char **ptr, + uint32_t *remain) +{ + if ((*remain) < num) + return false; + memcpy(bytes, *ptr, num); + (*ptr) += num; + (*remain) -= num; + + return true; +} + + +/** + * Increase the length of the submessage + * When the buffer does not contain enough memory the + * buffer is reallocated with the increased size. + * The function returns the submessage which may + * be reallocated in memory. + */ +static struct submsg_header * +append_submessage( + DDS_Security_OctetSeq *seq, + struct submsg_header *msg, + size_t size) +{ + assert ((size_t)msg->length + size <= UINT16_MAX); + if (size + seq->_length > seq->_maximum) + { + size_t l = seq->_length + size; + unsigned char *ptr = seq->_buffer; + size_t offset = (size_t)(((unsigned char *)msg) - ptr); + + seq->_buffer = ddsrt_realloc(ptr, l); + seq->_maximum = (DDS_Security_unsigned_long)l; + msg = (struct submsg_header *)&seq->_buffer[offset]; + } + seq->_length += (uint32_t)size; + msg->length = (uint16_t)(msg->length + size); + + return msg; +} + +/** + * Add a new submessage to the tail of the supplied buffer. + * When the supplied buffer does not contain enough memory + * it will be reallocated. + * The buffer's maximum indicated the total size of the + * buffer. The buffer's length indicates the used size. + * + * @param[in] seq Buffer + * @param[in] id Submessage id + * @param[in] flags Indicates big or little endian + * @param[in] size The octetToNextSubmessage + */ +static struct submsg_header * +add_submessage( + DDS_Security_OctetSeq *seq, + unsigned char id, + unsigned char flags, + size_t size) +{ + struct submsg_header *msg; + size_t len = sizeof(struct submsg_header) + size; + assert (size <= UINT16_MAX); + + if (len + seq->_length > seq->_maximum) + { + size_t l = len + seq->_length; + unsigned char *ptr = seq->_buffer; + seq->_buffer = ddsrt_realloc (ptr, l); + seq->_maximum = (DDS_Security_unsigned_long)l; + } + + msg = (struct submsg_header *)&seq->_buffer[seq->_length]; + msg->id = id; + msg->flags = flags; + msg->length = (uint16_t)size; + seq->_length += (uint32_t)len; + + return msg; +} + +/** + * @brief Adds info_src content after info_src header and returns next available location + */ +static bool +add_info_src( + DDS_Security_OctetSeq *seq, + unsigned char *rtps_header, + unsigned char flags) +{ + struct submsg_header *info_src_hdr = add_submessage(seq, SMID_SRTPS_INFO_SRC_KIND, + flags, INFO_SRC_SIZE - sizeof(struct submsg_header)); + unsigned char *ptr = (unsigned char *)(info_src_hdr + 1); + memset(ptr, 0, 4); /* skip unused bytes */ + memcpy(ptr + 4, rtps_header + 4, INFO_SRC_SIZE - sizeof(struct submsg_header) - 4); + return true; +} + +static bool +read_rtps_header( + DDS_Security_OctetSeq *rtps_header, + unsigned char **ptr, + uint32_t *remain) +{ + if ((*remain) > RTPS_HEADER_SIZE) + { + rtps_header->_buffer = *ptr; + rtps_header->_length = rtps_header->_maximum = RTPS_HEADER_SIZE; + (*ptr) += RTPS_HEADER_SIZE; + (*remain) -= RTPS_HEADER_SIZE; + return true; + } + + return false; +} + +/** + * Initialize the remote session info which is used + * to decode a received message. It will calculate the + * session key from the received crypto_header. + * + * @param[in,out] info The remote session information which is determined by this function + * @param[in] header The received crypto_header + * @param[in] master_salt The master_salt associated with the remote entity + * @param[in] master_key The master_key associated with the remote entity + * @param[in] transformation_kind The transformation kind (to determine key and salt size) + * @param[in,out] ex Security exception + */ +static bool +initialize_remote_session_info( + remote_session_info *info, + struct crypto_header *header, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + DDS_Security_SecurityException *ex) +{ + info->key_size = crypto_get_key_size (transformation_kind); + info->id = CRYPTO_TRANSFORM_ID(header->session_id); + return crypto_calculate_session_key(&info->key, info->id, master_salt, master_key, transformation_kind, ex); +} + +static bool transform_kind_valid(DDS_Security_CryptoTransformKind_Enum kind) +{ + return ((kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC) || + (kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM) || + (kind == CRYPTO_TRANSFORMATION_KIND_AES256_GMAC) || + (kind == CRYPTO_TRANSFORMATION_KIND_AES256_GCM)); +} + +/** + * @brief Read the crypto_header from the received data buffer + * + * @param[in] header The returned crypto_header + * @param[in,out] ptr Current read pointer in the received buffer + * @param[in,out] remain Remaining size in the received buffer + */ +static bool +read_crypto_header( + struct crypto_header *header, + unsigned char **ptr, + uint32_t *remain) +{ + return crypto_buffer_read_bytes((unsigned char *)header, sizeof(*header), ptr, remain); +} + +/** + * @brief Read the payload from the received data buffer + * + * @param[in,out] contents The returned payload + * @param[in] ptr Current read pointer in the received buffer + * @param[in] size Remaining size in the received buffer + */ +static DDS_Security_boolean +read_crypto_contents( + struct crypto_contents_ref *contents, + unsigned char *ptr, + uint32_t size) +{ + bool result = false; + + if (crypto_buffer_read_uint32(&contents->_length, &ptr, &size)) + { + contents->_data = ptr; + if (size == contents->_length) + result = true; + } + return result; +} + +/** + * Read the crypto_footer from the received data buffer + * The size of the footer depends on the number of + * receiver specific macs present in the message. + * + * @param[in,out] footer The returned crypto_footer + * @param[in,out] ptr Current read pointer in the received buffer + * @param[in,out] remain Remaining size in the received buffer + */ +static bool +read_crypto_footer( + struct crypto_footer **footer, + unsigned char **ptr, + uint32_t *remain) +{ + uint32_t len; + size_t sz; + struct crypto_footer *ft; + crypto_hmac_t common_mac; + + if (!crypto_buffer_read_bytes(common_mac.data, CRYPTO_HMAC_SIZE, ptr, remain) || + !crypto_buffer_read_uint32(&len, ptr, remain)) + return false; + + if (len > (*remain)) + return false; + + sz = CRYPTO_HMAC_SIZE + sizeof(uint32_t) + len * sizeof(struct receiver_specific_mac); + ft = ddsrt_malloc(sz); + + memcpy(ft->common_mac.data, common_mac.data, CRYPTO_HMAC_SIZE); + ft->receiver_specific_macs._length = len; + + if (len > 0) + { + sz = len * sizeof(struct receiver_specific_mac); + if (!crypto_buffer_read_bytes((unsigned char *)&ft->receiver_specific_macs._buffer[0], (uint32_t)sz, ptr, remain)) + { + ddsrt_free(ft); + *footer = NULL; + return false; + } + } + + *footer = ft; + return true; +} + +/** + * @brief Read the submessage header from the received data buffer + * + * @param[in,out] submsg The returned submessage header + * @param[in,out] ptr Current read pointer in the received buffer + * @param[in,out] remain Remaining size in the received buffer + */ +static bool +read_submsg_header( + struct submsg_header *submsg, + unsigned char **ptr, + uint32_t *remain) +{ + int swap; + bool result = crypto_buffer_read_bytes((unsigned char *)submsg, sizeof(*submsg), ptr, remain); + if (result) + { + if ((submsg->flags & 0x01) == 0) + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + submsg->length = swap ? ddsrt_bswap2u(submsg->length) : submsg->length; + if ((uint32_t)(submsg->length) > (*remain)) + result = false; + } + + return result; +} + +/** + * @brief Used by the decode_serialized_payload function to split the received message in the composed components: + * + * @param[in] payload The received serialized payload + * @param[in] header The crypto_header contained in the payload + * @param[in,out] payload_ptr The actual payload (either encoded or plain) + * @param[in,out] payload_len Length of the payload + * @param[in,out] footer The crypto_footer contained in the payload + */ +static bool +split_encoded_serialized_payload( + const DDS_Security_OctetSeq *payload, + struct crypto_header *header, + unsigned char **payload_ptr, + uint32_t *payload_len, + struct crypto_footer **footer) +{ + /* For data, the footer is always the same length. */ + const uint32_t footer_len = CRYPTO_HMAC_SIZE + sizeof(uint32_t); + unsigned char *ptr = payload->_buffer; + uint32_t remain = payload->_length; + + /* Get header. */ + if (read_crypto_header(header, &ptr, &remain)) + { + if (remain >= footer_len) + { + /* Get contents. */ + *payload_ptr = ptr; + *payload_len = remain - footer_len; + /* Get footer. */ + ptr = (*payload_ptr) + (*payload_len); + remain = footer_len; + if (read_crypto_footer(footer, &ptr, &remain)) + return true; + } + } + + return false; +} + +/** + * @brief Read the SEC_PREFIX submessage from a received message + * + * @param[in,out] prefix The contents of the SEC_PREFIX submessage header + * @param[in,out] header The crypto_header contained in the SEC_PREFIX submessage + * @param[in,out] ptr Current read pointer in the received buffer + * @param[in,out] remain Remaining size in the received buffer + * @param[in] expected Expected submessage kind + */ +static bool +read_prefix_submessage( + struct submsg_header *prefix, + struct crypto_header *header, + unsigned char **ptr, + uint32_t *remain, + enum SecureSubmsgKind_t expected) +{ + uint32_t datalen; + + if (!read_submsg_header(prefix, ptr, remain)) + return false; + + if (prefix->id != expected) + return false; + + datalen = prefix->length; + if (datalen != sizeof(struct crypto_header)) + return false; + + if (!read_crypto_header(header, ptr, remain)) + return false; + + return true; +} + +/** + * @brief Read the SEC_POSTFIX submessage from a received message + * + * @param[in,out] postfix The contents of the SEC_POSTFIX submessage header + * @param[in,out] footer The crypto_footer contained in the SEC_POSTFIX submessage + * @param[in,out] ptr Current read pointer in the received buffer + * @param[in,out] remain Remaining size in the received buffer + * @param[in] expected Expected submessage kind + */ +static bool +read_postfix_submessage( + struct submsg_header *postfix, + struct crypto_footer **footer, + unsigned char **ptr, + uint32_t *remain, + enum SecureSubmsgKind_t expected) +{ + uint32_t datalen; + size_t sz; + + if (!read_submsg_header(postfix, ptr, remain)) + return false; + + if (postfix->id != expected) + return false; + + datalen = postfix->length; + + if (!read_crypto_footer(footer, ptr, remain)) + return false; + + sz = CRYPTO_FOOTER_BASIC_SIZE + (*footer)->receiver_specific_macs._length * sizeof(struct receiver_specific_mac); + + if (datalen != sz) + { + ddsrt_free(*footer); + *footer = NULL; + return false; + } + + return true; +} + +/** + * Read the body submessage from a received message + * The message received may be encoded or not. When encoded + * a SEC_BODY submessage is present otherwise the original + * submessage is present. When a SEC_BODY submessage is present + * the contents will be set to the contents of the SEC_BODY otherwise + * the contents will be set to the submessage itself. + * + * @param[in,out] body The contents of the body submessage header + * @param[in,out] contents The contents of the SEC_BODY submessage or the submessage itself + * @param[in,out] ptr Current read pointer in the received buffer + * @param[in,out] remain Remaining size in the received buffer + */ +static bool +read_body_submessage( + struct submsg_header *body, + struct crypto_contents_ref *contents, + unsigned char **ptr, + uint32_t *remain) +{ + uint32_t datalen; + struct encrypted_data *encrypted; + + contents->_data = *ptr; + + if (!read_submsg_header(body, ptr, remain)) + return false; + + datalen = body->length; + if (body->id == SMID_SEC_BODY_KIND) + { + encrypted = (struct encrypted_data *)*ptr; + contents->_length = ddsrt_fromBE4u(encrypted->length); + contents->_data = encrypted->data; + if (contents->_length > datalen) + return false; + } + else + { + contents->_length = datalen + (uint32_t)sizeof(struct submsg_header); + } + + if ((*remain) < datalen) + return false; + + (*ptr) += datalen; + (*remain) -= datalen; + + return true; +} + +/** + * body is invalid if not encrypted + * info_src is invalid if encrypted + */ +static bool +read_rtps_body( + struct submsg_header *body, + struct crypto_contents_ref *contents, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + unsigned char **ptr, + uint32_t *remain) +{ + uint32_t datalen; + struct submsg_header submessage_header; + + if (is_encryption_required(transformation_kind)) + { /*read sec body */ + if (!read_body_submessage(body, contents, ptr, remain) || body->id != SMID_SEC_BODY_KIND) + return false; + } + else + { + unsigned char *body_start_with_info = *ptr; + bool arrived_to_postfix = false; + + if (!read_submsg_header(&submessage_header, ptr, remain) || submessage_header.id != SMID_SRTPS_INFO_SRC_KIND) + return false; + + (*ptr) += submessage_header.length; + (*remain) -= submessage_header.length; + + while (*remain > sizeof(struct submsg_header) && !arrived_to_postfix) + { + if (!read_submsg_header(&submessage_header, ptr, remain)) + return false; + + if (submessage_header.id != SMID_SRTPS_POSTFIX_KIND) + { + (*ptr) += submessage_header.length; + (*remain) -= submessage_header.length; + } + else + { + /*revert last read*/ + (*ptr) -= sizeof(struct submsg_header); + (*remain) += (uint32_t)sizeof(struct submsg_header); + arrived_to_postfix = true; + } + } + + if (!arrived_to_postfix) + return false; + + datalen = (uint32_t)(*ptr - body_start_with_info); /* rtps submessage + info_src + body data*/ + contents->_data = body_start_with_info; + contents->_length = datalen; + } + + return true; +} + +/** + * @brief Split a received message is the various components + * + * @param[in] data Buffer containing the received message + * @param[in] prefix The SEC_PREFIX submessage header + * @param[in] body The body submessage, either SEC_BODY or the not encoded submessage + * @param[in] postfix The SEC_POSTFIX submessage header + * @param[in] header Crypto_header contained in the SEC_PREFIX submessage + * @param[in] contents Crypto contents + * @param[in,out] footer Crypto_footer contained in the SEC_POSTFIX submessage + */ +static bool +split_encoded_submessage( + const DDS_Security_OctetSeq *data, + struct submsg_header *prefix, + struct submsg_header *body, + struct submsg_header *postfix, + struct crypto_header *header, + struct crypto_contents_ref *contents, + struct crypto_footer **footer) +{ + unsigned char *ptr = data->_buffer; + uint32_t remain = data->_length; + *footer = NULL; + + return (read_prefix_submessage(prefix, header, &ptr, &remain, SMID_SEC_PREFIX_KIND) && + read_body_submessage(body, contents, &ptr, &remain) && + read_postfix_submessage(postfix, footer, &ptr, &remain, SMID_SEC_POSTFIX_KIND)); +} + +static bool +split_encoded_rtps_message( + const DDS_Security_OctetSeq *data, + DDS_Security_OctetSeq *rtps_header, + struct submsg_header *prefix, + struct submsg_header *body, + struct submsg_header *postfix, + struct crypto_header *header, + struct crypto_contents_ref *contents, + struct crypto_footer **footer) +{ + unsigned char *ptr = data->_buffer; + uint32_t remain = data->_length; + uint32_t transform_kind; + *footer = NULL; + if (rtps_header->_buffer) + return false; + if (!read_rtps_header(rtps_header, &ptr, &remain)) + return false; + if (!read_prefix_submessage(prefix, header, &ptr, &remain, SMID_SRTPS_PREFIX_KIND)) + return false; + + transform_kind = CRYPTO_TRANSFORM_KIND(header->transform_identifier.transformation_kind); + + if (!read_rtps_body(body, contents, transform_kind, &ptr, &remain)) + return false; + if (!read_postfix_submessage(postfix, footer, &ptr, &remain, SMID_SRTPS_POSTFIX_KIND)) + return false; + + return true; +} + +/** + * @brief Initialize the crypto_header + */ +static void +set_crypto_header( + struct crypto_header *header, + uint32_t transform_kind, + uint32_t transform_id, + uint32_t session_id, + uint64_t init_vector_suffx) +{ + struct + { + uint32_t tkind; + uint32_t tid; + uint32_t sid; + uint32_t ivh; + uint32_t ivl; + } s; + uint64_t ivs = ddsrt_toBE8u(init_vector_suffx); + + s.tkind = ddsrt_toBE4u(transform_kind); + s.tid = ddsrt_toBE4u(transform_id); + s.sid = ddsrt_toBE4u(session_id); + s.ivh = (uint32_t)(ivs >> 32); + s.ivl = (uint32_t)ivs; + + memcpy(header, &s, sizeof(*header)); +} + +/* + * Function implementations + */ + +static DDS_Security_boolean +encode_serialized_payload( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_buffer, + DDS_Security_OctetSeq *extra_inline_qos, + const DDS_Security_OctetSeq *plain_buffer, + const DDS_Security_DatawriterCryptoHandle writer_id, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + dds_security_crypto_key_factory *factory; + session_key_material *session; + struct crypto_header *header; + struct crypto_contents *contents = NULL; + struct crypto_footer *footer; + unsigned char *buffer; + unsigned char *payload; + crypto_hmac_t hmac; + uint32_t payload_len; + uint32_t transform_kind, transform_id; + size_t size, offset; + + DDSRT_UNUSED_ARG(extra_inline_qos); + + memset(hmac.data, 0, sizeof(crypto_hmac_t)); + + if (!instance || !encoded_buffer || !plain_buffer || plain_buffer->_length == 0 || writer_id == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_serialized_payload: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_inv_arg; + } + + /* check if the payload is aligned on a 4 byte boundary */ + if ((plain_buffer->_length % 4) != 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_DATA_NOT_ALIGNED_CODE, 0, + "encode_serialized_payload: " DDS_SECURITY_ERR_INVALID_CRYPTO_DATA_NOT_ALIGNED_MESSAGE); + goto fail_inv_arg; + } + + /* Retrieve key material from sending_datawriter_crypto from factory */ + factory = cryptography_get_crypto_key_factory(impl->crypto); + if (!crypto_factory_get_writer_key_material(factory, writer_id, 0, true, &session, NULL, ex)) + goto fail_inv_arg; + + if (!session) + { + DDS_Security_OctetSeq_copy(encoded_buffer, plain_buffer); + return true; + } + + transform_kind = session->master_key_material->transformation_kind; + transform_id = session->master_key_material->sender_key_id; + + if (!is_encryption_required(transform_kind) && !is_authentication_required(transform_kind)) + { + DDS_Security_OctetSeq_copy(encoded_buffer, plain_buffer); + CRYPTO_OBJECT_RELEASE(session); + return true; + } + + /* update sessionKey when needed */ + if (!crypto_session_key_material_update(session, plain_buffer->_length, ex)) + goto fail_update_key; + + /* increment init_vector_suffix */ + session->init_vector_suffix++; + + /* + * allocate buffer for encoded data, size includes: + * - CryptoHeader + * if (encrypted) { + * - CryptoContents : size of the data + cypher block_size + 1 + * } else { + * - Plain payload + * } + * - CryptoFooter + * See spec: 9.5.3.3.4.4 Result from encode_serialized_payload + * Make sure to allocate enough memory for both options. + */ + size = sizeof(*header) + sizeof(*contents) + sizeof(*footer) + plain_buffer->_length + session->block_size + 1; + buffer = ddsrt_malloc(size); + header = (struct crypto_header *)buffer; + payload = &buffer[sizeof(*header)]; + + /* create CryptoHeader */ + set_crypto_header(header, transform_kind, transform_id, session->id, session->init_vector_suffix); + + /* if the transformation_kind indicates encryption then encrypt the buffer */ + payload_len = 0; + if (is_encryption_required(transform_kind)) + { + contents = (struct crypto_contents *)payload; + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, plain_buffer->_buffer, plain_buffer->_length, NULL, 0, contents->_data, &payload_len, &hmac, ex)) + goto fail_encrypt; + contents->_length = ddsrt_toBE4u(payload_len); + payload_len += (uint32_t)sizeof(uint32_t); + } + else if (is_authentication_required(transform_kind)) + { + /* the transformation_kind indicates only indicates authentication the determine HMAC */ + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, NULL, 0, plain_buffer->_buffer, plain_buffer->_length, NULL, NULL, &hmac, ex)) + goto fail_encrypt; + memcpy(payload, plain_buffer->_buffer, plain_buffer->_length); + payload_len = plain_buffer->_length; + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_serialized_payload: unknown transform_kind %d", (int)transform_kind); + goto fail_encrypt; + } + + /* create CryptoFooter */ + offset = sizeof(*header) + payload_len; + footer = (struct crypto_footer *)(buffer + offset); + memset(footer, 0, sizeof(*footer)); + memcpy(footer->common_mac.data, hmac.data, CRYPTO_HMAC_SIZE); + + size = offset + CRYPTO_HMAC_SIZE + sizeof(uint32_t); + + encoded_buffer->_length = encoded_buffer->_maximum = (uint32_t)size; + encoded_buffer->_buffer = buffer; + + CRYPTO_OBJECT_RELEASE(session); + + return true; + +fail_encrypt: + ddsrt_free(buffer); +fail_update_key: + CRYPTO_OBJECT_RELEASE(session); +fail_inv_arg: + return false; +} + +static bool +add_reader_specific_mac( + DDS_Security_OctetSeq *data, + struct submsg_header *postfix, + master_key_material *key_material, + session_key_material *session, + DDS_Security_ProtectionKind protection_kind, + DDS_Security_SecurityException *ex) +{ + bool result = true; + struct submsg_header *prefix; + struct crypto_header *header; + struct crypto_footer *footer; + crypto_session_key_t key; + crypto_hmac_t hmac; + + if (has_origin_authentication(protection_kind)) + { + uint32_t index; + + postfix = append_submessage(data, postfix, sizeof(struct receiver_specific_mac)); + /* determine header crypto header because the append operation may have changed the buffer location */ + prefix = (struct submsg_header *)data->_buffer; + header = (struct crypto_header *)(prefix + 1); + footer = (struct crypto_footer *)(postfix + 1); + index = ddsrt_fromBE4u(footer->receiver_specific_macs._length); + + if (!crypto_calculate_receiver_specific_key(&key, session->id, key_material->master_salt, key_material->master_receiver_specific_key, key_material->transformation_kind, ex) || + !crypto_cipher_encrypt_data(&key, session->key_size, header->session_id, NULL, 0, footer->common_mac.data, CRYPTO_HMAC_SIZE, NULL, NULL, &hmac, ex)) + { + result = false; + } + else + { + uint32_t key_id = ddsrt_toBE4u(key_material->receiver_specific_key_id); + memcpy(footer->receiver_specific_macs._buffer[index].receiver_mac.data, hmac.data, CRYPTO_HMAC_SIZE); + memcpy(footer->receiver_specific_macs._buffer[index].receiver_mac_key_id, &key_id, sizeof(key_id)); + footer->receiver_specific_macs._length = ddsrt_toBE4u(++index); + } + } + + return result; +} + +static bool +add_crypto_reader_specific_mac( + dds_security_crypto_key_factory *factory, + DDS_Security_OctetSeq *data, + DDS_Security_DatareaderCryptoHandle reader_crypto, + struct submsg_header *postfix, + DDS_Security_SecurityException *ex) +{ + bool result = true; + master_key_material *key_material = NULL; + session_key_material *session = NULL; + DDS_Security_ProtectionKind protection_kind; + + if (!crypto_factory_get_remote_reader_sign_key_material(factory, reader_crypto, &key_material, &session, &protection_kind, ex)) + return false; + + result = add_reader_specific_mac(data, postfix, key_material, session, protection_kind, ex); + + CRYPTO_OBJECT_RELEASE(session); + CRYPTO_OBJECT_RELEASE(key_material); + + return result; +} + +static bool +add_receiver_specific_mac( + dds_security_crypto_key_factory *factory, + DDS_Security_OctetSeq *data, + DDS_Security_DatareaderCryptoHandle sending_participant_crypto, + DDS_Security_DatareaderCryptoHandle receiving_participant_crypto, + struct submsg_header *postfix, + DDS_Security_SecurityException *ex) +{ + bool result = true; + session_key_material *session = NULL; + struct submsg_header *prefix; + struct crypto_header *header; + struct crypto_footer *footer; + DDS_Security_ProtectionKind local_protection_kind; + DDS_Security_ProtectionKind remote_protection_kind; + crypto_session_key_t key; + crypto_hmac_t hmac; + participant_key_material *pp_key_material; + + /* get local crypto and session*/ + if (!crypto_factory_get_local_participant_data_key_material(factory, sending_participant_crypto, &session, &local_protection_kind, ex)) + return false; + + /* get remote crypto tokens */ + if (!crypto_factory_get_participant_crypto_tokens(factory, sending_participant_crypto, receiving_participant_crypto, &pp_key_material, NULL, &remote_protection_kind, ex)) + { + CRYPTO_OBJECT_RELEASE(session); + return false; + } + + if (has_origin_authentication(remote_protection_kind)) + { + uint32_t index; + + postfix = append_submessage(data, postfix, sizeof(struct receiver_specific_mac)); + /* determine header crypto header because the append operation may have changed the buffer location */ + prefix = (struct submsg_header *)(data->_buffer + RTPS_HEADER_SIZE); + header = (struct crypto_header *)(prefix + 1); + footer = (struct crypto_footer *)(postfix + 1); + index = ddsrt_fromBE4u(footer->receiver_specific_macs._length); + + if (!crypto_calculate_receiver_specific_key(&key, session->id, pp_key_material->local_P2P_key_material->master_salt, + pp_key_material->local_P2P_key_material->master_receiver_specific_key, pp_key_material->local_P2P_key_material->transformation_kind, ex) || + !crypto_cipher_encrypt_data(&key, session->key_size, header->session_id, NULL, 0, footer->common_mac.data, CRYPTO_HMAC_SIZE, NULL, NULL, &hmac, ex)) + { + result = false; + } + else + { + uint32_t key_id = ddsrt_toBE4u(pp_key_material->local_P2P_key_material->receiver_specific_key_id); + memcpy(footer->receiver_specific_macs._buffer[index].receiver_mac.data, hmac.data, CRYPTO_HMAC_SIZE); + memcpy(footer->receiver_specific_macs._buffer[index].receiver_mac_key_id, &key_id, sizeof(key_id)); + footer->receiver_specific_macs._length = ddsrt_toBE4u(++index); + } + } + CRYPTO_OBJECT_RELEASE(pp_key_material); + CRYPTO_OBJECT_RELEASE(session); + return result; +} + +static DDS_Security_boolean +encode_datawriter_submessage_sign ( + dds_security_crypto_key_factory *factory, + DDS_Security_OctetSeq *encoded_submsg, + const DDS_Security_DatareaderCryptoHandleSeq *reader_crypto_list, + int32_t *index, + DDS_Security_SecurityException *ex +) +{ + DDS_Security_boolean result; + struct submsg_header *prefix = (struct submsg_header *)encoded_submsg->_buffer; + struct submsg_header *body = (struct submsg_header *)(((unsigned char *)prefix) + prefix->length + sizeof(struct submsg_header)); + struct submsg_header *postfix = (struct submsg_header *)(((unsigned char *)body) + body->length + sizeof(struct submsg_header)); + + result = add_crypto_reader_specific_mac(factory, encoded_submsg, reader_crypto_list->_buffer[*index], postfix, ex); + if (result) + (*index)++; + + return result; +} + +static DDS_Security_boolean +encode_datawriter_submessage_encrypt ( + dds_security_crypto_key_factory *factory, + DDS_Security_OctetSeq *encoded_submsg, + const DDS_Security_OctetSeq *plain_submsg, + const DDS_Security_DatawriterCryptoHandle writer_crypto, + const DDS_Security_DatareaderCryptoHandleSeq *reader_crypto_list, + int32_t *index, + DDS_Security_SecurityException *ex +) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto = 0; + DDS_Security_OctetSeq data; + session_key_material *session = NULL; + DDS_Security_ProtectionKind protection_kind; + unsigned char flags; + unsigned char *contents; + crypto_hmac_t hmac; + uint32_t payload_len; + size_t size; + struct submsg_header *prefix; + struct crypto_header *header; + struct submsg_header *postfix; + struct crypto_footer *footer; + uint32_t transform_kind, transform_id; + DDS_Security_boolean result = false; + + if (reader_crypto_list->_length > 0) + reader_crypto = reader_crypto_list->_buffer[0]; + + if (!crypto_factory_get_writer_key_material(factory, writer_crypto, reader_crypto, false, &session, &protection_kind, ex)) + goto enc_dw_submsg_fail_keymat; + + /* Determine the size of the buffer + * When no encryption + * - submsg header SEC_PREFIX + * - crypto header + * - size of the plain_submsg + * - submsg header SEC_POSTFIX + * - crypto footer based on the size of the receiving_datareader_crypto_list + * When encryption is required: + * - submsg header SEC_PREFIX + * - crypto header + * - submsg header SEC_BODY + * - estimated size of the encoded submessage (size of the plain_submsg + some extra for possible padding + * - submsg header SEC_POSTFIX + * - crypto footer based on the size of the receiving_datareader_crypto_list + */ + + size = 2 * sizeof(struct submsg_header) + sizeof(struct crypto_header) + sizeof(struct crypto_footer) + ALIGN4(plain_submsg->_length); + size += reader_crypto_list->_length * sizeof(struct receiver_specific_mac); + /* assure that the buffer contains enough memory to accommodate the encrypted payload */ + if (is_encryption_required(session->master_key_material->transformation_kind)) + size += sizeof(struct submsg_header) + sizeof(uint32_t) + CRYPTO_ENCRYPTION_MAX_PADDING; + + flags = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN) ? 0x01 : 0x00; + + /* allocate a buffer to store the encoded submessage */ + data._buffer = ddsrt_malloc(size); + data._length = 0; + data._maximum = (uint32_t)size; + + /* Set the SEC_PREFIX and associated CryptoHeader */ + prefix = add_submessage(&data, SMID_SEC_PREFIX_KIND, flags, sizeof(struct crypto_header)); + header = (struct crypto_header *)(prefix + 1); + contents = (unsigned char *)(header + 1); + + /* update sessionKey when needed */ + if (!crypto_session_key_material_update(session, plain_submsg->_length, ex)) + goto enc_dw_submsg_fail; + + /* increment init_vector_suffix */ + session->init_vector_suffix++; + + transform_kind = session->master_key_material->transformation_kind; + transform_id = session->master_key_material->sender_key_id; + + set_crypto_header(header, transform_kind, transform_id, session->id, session->init_vector_suffix); + + if (is_encryption_required(transform_kind)) + { + struct encrypted_data *encrypted; + size_t submsg_len = plain_submsg->_length + sizeof(uint32_t); + if (submsg_len > UINT16_MAX) + goto enc_dw_submsg_fail; + + /* add SEC_BODY submessage */ + struct submsg_header *body = add_submessage(&data, SMID_SEC_BODY_KIND, flags, submsg_len); + encrypted = (struct encrypted_data *)(body + 1); + contents = encrypted->data; + + /* encrypt submessage */ + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, plain_submsg->_buffer, plain_submsg->_length, NULL, 0, contents, &payload_len, &hmac, ex)) + goto enc_dw_submsg_fail; + + /* adjust the length of the body submessage when needed */ + encrypted->length = ddsrt_toBE4u(payload_len); + if (payload_len > plain_submsg->_length) + { + size_t inc = payload_len - plain_submsg->_length; + body->length = (uint16_t)(body->length + inc); + data._length += (uint32_t)inc; + } + } + else if (is_authentication_required(transform_kind)) + { + /* the transformation_kind indicates only indicates authentication the determine HMAC */ + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, NULL, 0, plain_submsg->_buffer, plain_submsg->_length, NULL, NULL, &hmac, ex)) + goto enc_dw_submsg_fail; + + /* copy submessage */ + memcpy(contents, plain_submsg->_buffer, plain_submsg->_length); + payload_len = plain_submsg->_length; + data._length += payload_len; + } + else + { + goto enc_dw_submsg_fail; + } + + postfix = add_submessage(&data, SMID_SEC_POSTFIX_KIND, flags, CRYPTO_FOOTER_BASIC_SIZE); + footer = (struct crypto_footer *)(postfix + 1); + + /* Set initial SEC_POSTFIX and CryptoFooter containing the common_mac + * Note that the length of the postfix may increase when reader specific macs are added */ + memcpy(footer->common_mac.data, hmac.data, CRYPTO_HMAC_SIZE); + footer->receiver_specific_macs._length = 0; + + *encoded_submsg = data; + if (!has_origin_authentication(protection_kind)) + *index = (int32_t) reader_crypto_list->_length; + else + { + if (reader_crypto_list->_length != 0) + { + if (!add_crypto_reader_specific_mac(factory, encoded_submsg, reader_crypto_list->_buffer[0], postfix, ex)) + goto enc_dw_submsg_fail; + (*index)++; + } + } + + result = true; + +enc_dw_submsg_fail: + CRYPTO_OBJECT_RELEASE(session); + if (!result) + { + ddsrt_free(data._buffer); + encoded_submsg->_buffer = NULL; + encoded_submsg->_length = 0; + encoded_submsg->_maximum = 0; + } +enc_dw_submsg_fail_keymat: + return result; +} + +static DDS_Security_boolean +encode_datawriter_submessage( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_submsg, + const DDS_Security_OctetSeq *plain_submsg, + const DDS_Security_DatawriterCryptoHandle writer_crypto, + const DDS_Security_DatareaderCryptoHandleSeq *reader_crypto_list, + int32_t *index, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_boolean result = false; + + /* check arguments */ + if (!instance || !encoded_submsg || (writer_crypto == 0) || !reader_crypto_list || + (reader_crypto_list->_length == 0) || (reader_crypto_list->_length > INT32_MAX) || + !index || ((*index) >= (int32_t)reader_crypto_list->_length)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_datawriter_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_dw_submsg_inv_args; + } + + if (*index == 0) + { + if (!plain_submsg || (plain_submsg->_length == 0)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_datawriter_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_dw_submsg_inv_args; + } + } + else + { + if (encoded_submsg->_length == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_datawriter_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_dw_submsg_inv_args; + } + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + if (*index == 0) + { + /* When the index is 0 then retrieve the key material of the writer */ + result = encode_datawriter_submessage_encrypt (factory, encoded_submsg, plain_submsg, + writer_crypto, reader_crypto_list, index, ex); + } + else + { + /* When the index is not 0 then add a signature for the specific reader */ + result = encode_datawriter_submessage_sign (factory, encoded_submsg, reader_crypto_list, index, ex); + } + +enc_dw_submsg_inv_args: + return result; +} + +static bool +add_writer_specific_mac( + dds_security_crypto_key_factory *factory, + DDS_Security_OctetSeq *data, + DDS_Security_DatawriterCryptoHandle writer_crypto, + struct submsg_header *postfix, + DDS_Security_SecurityException *ex) +{ + bool result = true; + master_key_material *key_material = NULL; + session_key_material *session = NULL; + DDS_Security_ProtectionKind protection_kind; + + if (!crypto_factory_get_remote_writer_sign_key_material(factory, writer_crypto, &key_material, &session, &protection_kind, ex)) + return false; + + result = add_reader_specific_mac(data, postfix, key_material, session, protection_kind, ex); + + CRYPTO_OBJECT_RELEASE(session); + CRYPTO_OBJECT_RELEASE(key_material); + + return result; +} + +static DDS_Security_boolean +encode_datareader_submessage( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_submsg, + const DDS_Security_OctetSeq *plain_submsg, + const DDS_Security_DatareaderCryptoHandle reader_crypto, + const DDS_Security_DatawriterCryptoHandleSeq *writer_crypto_list, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_DatawriterCryptoHandle writer_crypto = 0; + DDS_Security_OctetSeq data; + struct submsg_header *prefix; + struct crypto_header *header; + struct submsg_header *postfix; + struct crypto_footer *footer; + session_key_material *session = NULL; + DDS_Security_ProtectionKind protection_kind; + unsigned char flags; + unsigned char *contents; + crypto_hmac_t hmac; + uint32_t payload_len; + size_t size; + DDS_Security_boolean result = false; + uint32_t transform_kind, transform_id; + + /* check arguments */ + if (!instance || !encoded_submsg || (reader_crypto == 0) || + !plain_submsg || (plain_submsg->_length == 0) || + !writer_crypto_list || (writer_crypto_list->_length == 0)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_datawriter_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_dr_submsg_inv_args; + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + if (writer_crypto_list->_length > 0) + writer_crypto = writer_crypto_list->_buffer[0]; + + if (!crypto_factory_get_reader_key_material(factory, reader_crypto, writer_crypto, &session, &protection_kind, ex)) + goto enc_dr_submsg_fail_keymat; + + /* Determine the size of the buffer + * When no encryption + * - submsg header SEC_PREFIX + * - crypto header + * - size of the plain_submsg + * - submsg header SEC_POSTFIX + * - crypto footer based on the size of the receiving_datareader_crypto_list + * When encryption is required: + * - submsg header SEC_PREFIX + * - crypto header + * - submsg header SEC_BODY + * - estimated size of the encoded submessage (size of the plain_submsg + some extra for possible padding + * - submsg header SEC_POSTFIX + * - crypto footer based on the size of the receiving_datareader_crypto_list + */ + + size = 2 * sizeof(struct submsg_header) + sizeof(struct crypto_header) + sizeof(struct crypto_footer) + ALIGN4(plain_submsg->_length); + size += writer_crypto_list->_length * sizeof(struct receiver_specific_mac); + /* assure that the buffer contains enough memory to accommodate the encrypted payload */ + if (is_encryption_required(session->master_key_material->transformation_kind)) + size += sizeof(struct submsg_header) + sizeof(uint32_t) + CRYPTO_ENCRYPTION_MAX_PADDING; + + flags = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN) ? 0x01 : 0x00; + + /* allocate a buffer to store the encoded submessage */ + data._buffer = ddsrt_malloc(size); + data._length = 0; + data._maximum = (uint32_t)size; + + /* Set the SEC_PREFIX and associated CryptoHeader */ + + prefix = add_submessage(&data, SMID_SEC_PREFIX_KIND, flags, sizeof(struct crypto_header)); + header = (struct crypto_header *)(prefix + 1); + contents = (unsigned char *)(header + 1); + + /* update sessionKey when needed */ + if (!crypto_session_key_material_update(session, plain_submsg->_length, ex)) + goto enc_dr_submsg_fail; + + /* increment init_vector_suffix */ + session->init_vector_suffix++; + + transform_kind = session->master_key_material->transformation_kind; + transform_id = session->master_key_material->sender_key_id; + + set_crypto_header(header, transform_kind, transform_id, session->id, session->init_vector_suffix); + + if (is_encryption_required(transform_kind)) + { + struct encrypted_data *encrypted; + size_t submsg_len = plain_submsg->_length + sizeof (uint32_t); + if (submsg_len > UINT16_MAX) + goto enc_dr_submsg_fail; + + /* add SEC_BODY submessage */ + struct submsg_header *body = add_submessage(&data, SMID_SEC_BODY_KIND, flags, submsg_len); + encrypted = (struct encrypted_data *)(body + 1); + contents = encrypted->data; + + /* encrypt submessage */ + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, plain_submsg->_buffer, plain_submsg->_length, NULL, 0, contents, &payload_len, &hmac, ex)) + goto enc_dr_submsg_fail; + + /* adjust the length of the body submessage when needed */ + encrypted->length = ddsrt_toBE4u(payload_len); + if (payload_len > plain_submsg->_length) + { + size_t inc = payload_len - plain_submsg->_length; + body->length = (uint16_t)(body->length + inc); + data._length += (uint32_t)inc; + } + } + else if (is_authentication_required(transform_kind)) + { + /* the transformation_kind indicates only indicates authentication the determine HMAC */ + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, NULL, 0, plain_submsg->_buffer, plain_submsg->_length, NULL, NULL, &hmac, ex)) + goto enc_dr_submsg_fail; + + /* copy submessage */ + memcpy(contents, plain_submsg->_buffer, plain_submsg->_length); + payload_len = plain_submsg->_length; + data._length += payload_len; + } + else + { + goto enc_dr_submsg_fail; + } + + postfix = add_submessage(&data, SMID_SEC_POSTFIX_KIND, flags, CRYPTO_FOOTER_BASIC_SIZE); + footer = (struct crypto_footer *)(postfix + 1); + + /* Set initial SEC_POSTFIX and CryptoFooter containing the common_mac + * Note that the length of the postfix may increase when writer specific macs are added */ + memcpy(footer->common_mac.data, hmac.data, CRYPTO_HMAC_SIZE); + footer->receiver_specific_macs._length = 0; + + if (has_origin_authentication(protection_kind)) + { + for (uint32_t i = 0; i < writer_crypto_list->_length; i++) + { + if (!add_writer_specific_mac(factory, &data, writer_crypto_list->_buffer[i], postfix, ex)) + goto enc_dr_submsg_fail; + } + } + *encoded_submsg = data; + result = true; + +enc_dr_submsg_fail: + CRYPTO_OBJECT_RELEASE(session); + if (!result) + { + ddsrt_free(data._buffer); + encoded_submsg->_buffer = NULL; + encoded_submsg->_maximum = 0; + encoded_submsg->_length = 0; + } +enc_dr_submsg_fail_keymat: +enc_dr_submsg_inv_args: + return result; +} + +static bool +check_reader_specific_mac( + dds_security_crypto_key_factory *factory, + struct crypto_header *header, + struct crypto_footer *footer, + CryptoObjectKind_t kind, + DDS_Security_Handle rmt_handle, + const char *context, + DDS_Security_SecurityException *ex) +{ + bool result = false; + master_key_material *keymat = NULL; + uint32_t index; + uint32_t session_id; + crypto_session_key_t key; + crypto_hmac_t *href = NULL; + crypto_hmac_t hmac; + + if (footer->receiver_specific_macs._length == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_RECEIVER_SIGN_CODE, 0, + "%s: message does not contain a receiver specific mac", context); + return false; + } + + if (!crypto_factory_get_specific_keymat(factory, kind, rmt_handle, &footer->receiver_specific_macs._buffer[0], footer->receiver_specific_macs._length, &index, &keymat)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_RECEIVER_SIGN_CODE, 0, + "%s: message does not contain a known receiver specific key", context); + goto check_failed; + } + + href = &footer->receiver_specific_macs._buffer[index].receiver_mac; + if (!href) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_RECEIVER_SIGN_CODE, 0, + "%s: message does not contain receiver specific mac", context); + goto check_failed; + } + + session_id = CRYPTO_TRANSFORM_ID(header->session_id); + if (!crypto_calculate_receiver_specific_key(&key, session_id, keymat->master_salt, keymat->master_receiver_specific_key, keymat->transformation_kind, ex)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_RECEIVER_SIGN_CODE, 0, + "%s: failed to calculate receiver specific session key", context); + goto check_failed; + } + + if (!crypto_cipher_encrypt_data(&key, crypto_get_key_size(keymat->transformation_kind), header->session_id, NULL, 0, footer->common_mac.data, CRYPTO_HMAC_SIZE, NULL, NULL, &hmac, ex)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_RECEIVER_SIGN_CODE, 0, + "%s: failed to calculate receiver specific hmac", context); + goto check_failed; + } + + if (memcmp(hmac.data, href->data, CRYPTO_HMAC_SIZE) != 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_RECEIVER_SIGN_CODE, 0, + "%s: message does not contain a valid receiver specific mac", context); + goto check_failed; + } + + result = true; + +check_failed: + CRYPTO_OBJECT_RELEASE(keymat); + return result; +} + +static DDS_Security_boolean encode_rtps_message_sign ( + dds_security_crypto_key_factory *factory, + DDS_Security_OctetSeq *encoded_rtps_message, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + int32_t *receiving_participant_crypto_list_index, + DDS_Security_ParticipantCryptoHandle remote_id, + DDS_Security_SecurityException *ex +) +{ + DDS_Security_boolean result; + struct submsg_header *prefix = (struct submsg_header *)(encoded_rtps_message->_buffer + RTPS_HEADER_SIZE); + struct crypto_header *header = (struct crypto_header *)(prefix + 1); + struct submsg_header *submessage_header = (struct submsg_header *)(header + 1); + struct submsg_header *postfix = (struct submsg_header *)(((unsigned char *)submessage_header) + submessage_header->length + sizeof(struct submsg_header)); + + if (submessage_header->id == SMID_SRTPS_INFO_SRC_KIND) /* not encrypted */ + { + /* skip INFO_SRC_HDR to RTPS submessage header */ + unsigned char *ptr = ((unsigned char *)submessage_header + sizeof(struct submsg_header) + submessage_header->length); + size_t remaining = (size_t) (encoded_rtps_message->_buffer + encoded_rtps_message->_length - ptr); + /* There may be multiple RTPS submessages until postfix */ + while (remaining - sizeof(struct submsg_header) > 0) + { + submessage_header = (struct submsg_header *)ptr; + size_t length_to_postfix = submessage_header->length + sizeof(struct submsg_header); + postfix = (struct submsg_header *)(((unsigned char *)submessage_header) + length_to_postfix); + if (postfix->id == SMID_SRTPS_POSTFIX_KIND) + break; + remaining -= length_to_postfix; + ptr += length_to_postfix; + } + } + + result = add_receiver_specific_mac(factory, encoded_rtps_message, sending_participant_crypto, remote_id, postfix, ex); + if (result) + (*receiving_participant_crypto_list_index)++; + + return result; +} + +static DDS_Security_boolean encode_rtps_message_encrypt ( + dds_security_crypto_key_factory *factory, + DDS_Security_OctetSeq *encoded_rtps_message, + const DDS_Security_OctetSeq *plain_rtps_message, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + const DDS_Security_ParticipantCryptoHandleSeq *receiving_participant_crypto_list, + int32_t *receiving_participant_crypto_list_index, + DDS_Security_ParticipantCryptoHandle remote_id, + DDS_Security_SecurityException *ex +) +{ + session_key_material *session = NULL; + DDS_Security_ProtectionKind protection_kind; + DDS_Security_OctetSeq data; + DDS_Security_OctetSeq secure_body_plain; + struct submsg_header *prefix; + struct crypto_header *header; + struct submsg_header *postfix; + struct submsg_header *body; + struct crypto_footer *footer; + DDS_Security_boolean result = false; + unsigned char *contents; + crypto_hmac_t hmac; + uint32_t payload_len; + size_t size; + uint32_t transform_kind, transform_id; + unsigned char flags = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN) ? 0x01 : 0x00; + unsigned char *rtps_body = plain_rtps_message->_buffer + RTPS_HEADER_SIZE; + unsigned rtps_body_size = plain_rtps_message->_length - RTPS_HEADER_SIZE; + unsigned secure_body_plain_size = rtps_body_size + INFO_SRC_SIZE; + + /* get local crypto and session*/ + if (!crypto_factory_get_local_participant_data_key_material(factory, sending_participant_crypto, &session, &protection_kind, ex)) + goto enc_rtps_inv_keymat; + + secure_body_plain._buffer = ddsrt_malloc(secure_body_plain_size); + secure_body_plain._maximum = secure_body_plain_size; + secure_body_plain._length = 0; + + /* info_src and body */ + if (!add_info_src(&secure_body_plain, plain_rtps_message->_buffer, flags)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_rtps_message: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_rtps_fail; + } + memcpy(secure_body_plain._buffer + secure_body_plain._length, rtps_body, rtps_body_size); /* rtps message body */ + secure_body_plain._length += rtps_body_size; + + /* Determine the size of the buffer + * When no encryption + * - rtps header + * - submsg header SEC_PREFIX + * - crypto header + * - INFO_SRC (24) + * - size of the plain_rtps body + * - submsg header SEC_POSTFIX + * - crypto footer based on the size of the receiving_participant_crypto_list + * When encryption is required: + * - rtps header + * - submsg header SEC_PREFIX + * - crypto header + * - submsg header SEC_BODY + * - INFO_SRC (24) + * - estimated size of the encoded submessage (size of the plain_rtps_message + some extra for possible padding + * - submsg header SEC_POSTFIX + * - crypto footer based on the size of the receiving_participant_crypto_list + */ + + size = RTPS_HEADER_SIZE; /* RTPS Header */ + size += 2 * sizeof(struct submsg_header) + sizeof(struct crypto_header) + sizeof(struct crypto_footer) + ALIGN4(plain_rtps_message->_length); + size += receiving_participant_crypto_list->_length * sizeof(struct receiver_specific_mac); + size += sizeof(struct submsg_header) + RTPS_HEADER_SIZE; /* INFO_SRC */ + + if (is_encryption_required(session->master_key_material->transformation_kind)) + size += sizeof(struct submsg_header) + sizeof(uint32_t); + + /* allocate a buffer to store the encoded message */ + data._buffer = ddsrt_malloc(size); + data._length = 0; + data._maximum = (uint32_t)size; + + /* Add RTPS header */ + memcpy(data._buffer, plain_rtps_message->_buffer, RTPS_HEADER_SIZE); + data._length += RTPS_HEADER_SIZE; + + /* Set the SEC_PREFIX and associated CryptoHeader */ + prefix = add_submessage(&data, SMID_SRTPS_PREFIX_KIND, flags, sizeof(struct crypto_header)); + header = (struct crypto_header *)(prefix + 1); + contents = (unsigned char *)(header + 1); + + /* update sessionKey when needed */ + if (!crypto_session_key_material_update(session, secure_body_plain_size, ex)) + goto enc_rtps_fail_data; + + /* increment init_vector_suffix */ + session->init_vector_suffix++; + + transform_kind = session->master_key_material->transformation_kind; + transform_id = session->master_key_material->sender_key_id; + set_crypto_header(header, transform_kind, transform_id, session->id, session->init_vector_suffix); + + if (is_encryption_required(transform_kind)) + { + struct encrypted_data *encrypted; + size_t submsg_len = secure_body_plain_size + sizeof (uint32_t); + if (submsg_len > UINT16_MAX) + goto enc_rtps_fail_data; + + /* add SEC_BODY submessage */ + body = add_submessage(&data, SMID_SEC_BODY_KIND, flags, submsg_len); + encrypted = (struct encrypted_data *)(body + 1); + contents = encrypted->data; + + /* encrypt message */ + /* FIXME: improve performance by not copying plain_rtps_message to a new buffer (crypto_cipher_encrypt_data should allow encrypting parts of a message) */ + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, secure_body_plain._buffer, secure_body_plain_size, NULL, 0, contents, &payload_len, &hmac, ex)) + goto enc_rtps_fail_data; + + encrypted->length = ddsrt_toBE4u(payload_len); + if (payload_len + sizeof(encrypted->length) > secure_body_plain_size) + { + size_t inc = payload_len + sizeof(encrypted->length) - secure_body_plain_size; + body->length = (uint16_t)(body->length + inc); + data._length += (uint32_t)inc; + } + } + else if (is_authentication_required(transform_kind)) + { + /* the transformation_kind indicates only indicates authentication the determine HMAC */ + if (!crypto_cipher_encrypt_data(&session->key, session->key_size, header->session_id, NULL, 0, secure_body_plain._buffer, secure_body_plain_size, NULL, NULL, &hmac, ex)) + goto enc_rtps_fail_data; + + /* copy submessage */ + memcpy(contents, secure_body_plain._buffer, secure_body_plain_size); + payload_len = secure_body_plain_size; + data._length += payload_len; + } + else + { + goto enc_rtps_fail_data; + } + + postfix = add_submessage(&data, SMID_SRTPS_POSTFIX_KIND, flags, CRYPTO_FOOTER_BASIC_SIZE); + footer = (struct crypto_footer *)(postfix + 1); + + /* Set initial SEC_POSTFIX and CryptoFooter containing the common_mac + * Note that the length of the postfix may increase when reader specific macs are added */ + memcpy(footer->common_mac.data, hmac.data, CRYPTO_HMAC_SIZE); + footer->receiver_specific_macs._length = 0; + *encoded_rtps_message = data; + if (has_origin_authentication(protection_kind)) + { + if (receiving_participant_crypto_list->_length != 0) + { + if (!add_receiver_specific_mac(factory, encoded_rtps_message, sending_participant_crypto, remote_id, postfix, ex)) + goto enc_rtps_fail_data; + (*receiving_participant_crypto_list_index)++; + } + } + else + { + *receiving_participant_crypto_list_index = (int32_t) receiving_participant_crypto_list->_length; + } + result = true; + +enc_rtps_fail_data: + if (!result) + { + ddsrt_free(data._buffer); + encoded_rtps_message->_buffer = NULL; + encoded_rtps_message->_length = 0; + encoded_rtps_message->_maximum = 0; + } +enc_rtps_fail: + CRYPTO_OBJECT_RELEASE(session); + ddsrt_free(secure_body_plain._buffer); +enc_rtps_inv_keymat: + return result; +} + +static DDS_Security_boolean +encode_rtps_message(dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_rtps_message, + const DDS_Security_OctetSeq *plain_rtps_message, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + const DDS_Security_ParticipantCryptoHandleSeq *receiving_participant_crypto_list, + int32_t *receiving_participant_crypto_list_index, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_ParticipantCryptoHandle remote_id; + DDS_Security_boolean result = false; + + /* check arguments */ + if (!instance || !encoded_rtps_message || sending_participant_crypto == 0 || !receiving_participant_crypto_list || + !receiving_participant_crypto_list_index || receiving_participant_crypto_list->_length == 0 || + (*receiving_participant_crypto_list_index) > (int32_t)receiving_participant_crypto_list->_length || + receiving_participant_crypto_list->_length > INT32_MAX) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_rtps_message: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_rtps_inv_arg; + } + + if (*receiving_participant_crypto_list_index == 0) + { + if (!plain_rtps_message || plain_rtps_message->_length == 0 || !plain_rtps_message->_buffer) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_rtps_message: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_rtps_inv_arg; + } + } + else + { + if (encoded_rtps_message->_length == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "encode_rtps_message: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto enc_rtps_inv_arg; + } + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + /* get remote participant handle */ + remote_id = receiving_participant_crypto_list->_buffer[*receiving_participant_crypto_list_index]; + + /* When the receiving_participant_crypto_list_index is 0 then retrieve the key material of the writer */ + if (*receiving_participant_crypto_list_index == 0) + { + result = encode_rtps_message_encrypt (factory, encoded_rtps_message, plain_rtps_message, sending_participant_crypto, + receiving_participant_crypto_list, receiving_participant_crypto_list_index, remote_id, ex); + } + else + { + /* When the receiving_participant_crypto_list_index is not 0 then add a signature for the specific reader */ + result = encode_rtps_message_sign (factory, encoded_rtps_message, sending_participant_crypto, + receiving_participant_crypto_list_index, remote_id, ex); + } + +enc_rtps_inv_arg: + return result; +} + + + +static DDS_Security_boolean +decode_rtps_message(dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_buffer, + const DDS_Security_OctetSeq *encoded_buffer, + const DDS_Security_ParticipantCryptoHandle receiving_participant_crypto, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + dds_security_crypto_key_factory *factory; + uint32_t transform_kind; + remote_session_info remote_session; + DDS_Security_OctetSeq rtps_header; + struct submsg_header prefix; + struct crypto_header header; + struct submsg_header postfix; + struct submsg_header body; + struct crypto_footer *footer; + struct crypto_contents_ref contents = {0, NULL}; + unsigned char *decoded_body; + uint32_t decoded_body_size; + static const char *context = "decode_rtps_message"; + participant_key_material *pp_key_material; + master_key_material *remote_key_material; + DDS_Security_ProtectionKind remote_protection_kind; + bool result = false; + + /* FIXME: when decoding a message the message is split in several parts (header, body, footer, etc) and for this + * memory is allocated which is probably not necessary. Performance should be improved by removing these allocations + * and use pointer to the data instead. */ + + /* check arguments */ + if (!instance || !encoded_buffer || sending_participant_crypto == 0 || receiving_participant_crypto == 0 || + encoded_buffer->_length == 0 || !encoded_buffer->_buffer || !plain_buffer) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_rtps_message: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_invalid_input; + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + memset(&rtps_header, 0, sizeof(DDS_Security_OctetSeq)); + + /* split the encoded submessage in the corresponding parts */ + if (!split_encoded_rtps_message(encoded_buffer, &rtps_header, &prefix, &body, &postfix, &header, &contents, &footer)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_rtps_message: invalid message"); + goto fail_invalid_input; + } + + transform_kind = CRYPTO_TRANSFORM_KIND(header.transform_identifier.transformation_kind); + + /* Retrieve key material from sending_participant_crypto and receiving_participant_crypto from factory */ + if (!crypto_factory_get_participant_crypto_tokens(factory, receiving_participant_crypto, sending_participant_crypto, &pp_key_material, &remote_key_material, &remote_protection_kind, ex)) + goto fail_tokens; + if (remote_key_material == NULL) + goto fail_remote_keys_not_ready; + + if (has_origin_authentication(remote_protection_kind)) + { /* default governance value */ + if (!check_reader_specific_mac(factory, &header, footer, CRYPTO_OBJECT_KIND_REMOTE_CRYPTO, sending_participant_crypto, context, ex)) + goto fail_reader_mac; + } + + /* calculate the session key */ + decoded_body = DDS_Security_OctetSeq_allocbuf(contents._length); + if (!initialize_remote_session_info(&remote_session, &header, remote_key_material->master_salt, + remote_key_material->master_sender_key, remote_key_material->transformation_kind, ex)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_rtps_message: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_decrypt; + } + + if (is_encryption_required(transform_kind)) + { + if (!is_encryption_expected(remote_protection_kind)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_rtps_submessage: message is encrypted, which is unexpected"); + goto fail_decrypt; + } + + /* When the CryptoHeader indicates that encryption is performed then decrypt the submessage body */ + /* check if the body is a SEC_BODY submessage */ + if (body.id != SMID_SEC_BODY_KIND) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_rtps_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_decrypt; + } + + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, contents._data, contents._length, NULL, 0, + decoded_body, &decoded_body_size, &footer->common_mac, ex)) + { + goto fail_decrypt; + } + } + else if (is_authentication_required(transform_kind)) + { + if (!is_authentication_expected(remote_protection_kind)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_rtps_message: message is signed, which is unexpected"); + goto fail_decrypt; + } + /* When the CryptoHeader indicates that authentication is performed then calculate the HMAC */ + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, NULL, 0, contents._data, contents._length, NULL, 0, &footer->common_mac, ex)) + goto fail_decrypt; + decoded_body_size = contents._length; + memcpy(decoded_body, contents._data, contents._length); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_CODE, 0, + "decode_rtps_message: " DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_MESSAGE); + goto fail_decrypt; + } + + plain_buffer->_buffer = DDS_Security_OctetSeq_allocbuf(decoded_body_size - 4); /* INFO_SRC removed, "RTPS" prefix added */ + plain_buffer->_length = plain_buffer->_maximum = decoded_body_size - 4; /* INFO_SRC removed, "RTPS" prefix added */ + memcpy(plain_buffer->_buffer, "RTPS", 4); /* ADD RTPS */ + memcpy(plain_buffer->_buffer + 4, decoded_body + 8, decoded_body_size - 8); /* remove INFO_SRC */ + result = true; + +fail_decrypt: + ddsrt_free(decoded_body); +fail_remote_keys_not_ready: +fail_reader_mac: + CRYPTO_OBJECT_RELEASE(pp_key_material); +fail_tokens: + ddsrt_free(footer); +fail_invalid_input: + return result; +} + +static DDS_Security_boolean +preprocess_secure_submsg( + dds_security_crypto_transform *instance, + DDS_Security_DatawriterCryptoHandle *datawriter_crypto, + DDS_Security_DatareaderCryptoHandle *datareader_crypto, + DDS_Security_SecureSubmessageCategory_t *secure_submessage_category, + const DDS_Security_OctetSeq *encoded_rtps_submessage, + const DDS_Security_ParticipantCryptoHandle receiving_participant_crypto, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_Handle remote_handle; + DDS_Security_Handle local_handle; + DDS_Security_boolean result; + struct submsg_header submsg; + struct crypto_header cheader; + uint32_t transform_kind, key_id; + unsigned char *pdata; + uint32_t remain; + + if (!instance || !datawriter_crypto || !datareader_crypto || sending_participant_crypto == 0 || + !secure_submessage_category || !encoded_rtps_submessage || encoded_rtps_submessage->_length == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "preprocess_secure_submsg: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + pdata = encoded_rtps_submessage->_buffer; + remain = encoded_rtps_submessage->_length; + + if (!read_submsg_header(&submsg, &pdata, &remain)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "preprocess_secure_submsg: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + if (submsg.id != SMID_SEC_PREFIX_KIND) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "preprocess_secure_submsg: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + if (!read_crypto_header(&cheader, &pdata, &remain)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "preprocess_secure_submsg: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + transform_kind = CRYPTO_TRANSFORM_KIND(cheader.transform_identifier.transformation_kind); + key_id = CRYPTO_TRANSFORM_ID(cheader.transform_identifier.transformation_key_id); + + if (!transform_kind_valid(transform_kind)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "preprocess_secure_submsg: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + /* Lookup the end point information associated with the transform id */ + result = crypto_factory_get_endpoint_relation( + factory, receiving_participant_crypto, sending_participant_crypto, + key_id, &remote_handle, &local_handle, secure_submessage_category, ex); + + if (result) + { + if (*secure_submessage_category == DDS_SECURITY_DATAWRITER_SUBMESSAGE) + { + *datawriter_crypto = (DDS_Security_DatawriterCryptoHandle)remote_handle; + *datareader_crypto = (DDS_Security_DatareaderCryptoHandle)local_handle; + } + else + { + *datareader_crypto = (DDS_Security_DatareaderCryptoHandle)remote_handle; + *datawriter_crypto = (DDS_Security_DatawriterCryptoHandle)local_handle; + } + } + + return result; +} + +static DDS_Security_boolean +decode_datawriter_submessage( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_submsg, + const DDS_Security_OctetSeq *encoded_submsg, + const DDS_Security_DatareaderCryptoHandle reader_crypto, + const DDS_Security_DatawriterCryptoHandle writer_crypto, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + static const char *context = "decode_datawriter_submessage"; + dds_security_crypto_key_factory *factory; + uint32_t transform_kind, transform_id; + master_key_material *writer_master_key; + DDS_Security_ProtectionKind protection_kind; + remote_session_info remote_session; + struct submsg_header prefix; + struct crypto_header header; + struct submsg_header postfix; + struct submsg_header body; + struct crypto_footer *footer; + struct crypto_contents_ref contents; + + /* check arguments */ + if (!instance || writer_crypto == 0 || reader_crypto == 0 || !encoded_submsg || + encoded_submsg->_length == 0 || !encoded_submsg->_buffer || !plain_submsg) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datawriter_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + memset(plain_submsg, 0, sizeof(*plain_submsg)); + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + /* split the encoded submessage in the corresponding parts */ + if (!split_encoded_submessage(encoded_submsg, &prefix, &body, &postfix, &header, &contents, &footer)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datawriter_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + transform_kind = CRYPTO_TRANSFORM_KIND(header.transform_identifier.transformation_kind); + transform_id = CRYPTO_TRANSFORM_ID(header.transform_identifier.transformation_key_id); + + /* Retrieve key material from sending_datawriter_crypto from factory */ + if (!crypto_factory_get_remote_writer_key_material(factory, reader_crypto, writer_crypto, transform_id, &writer_master_key, &protection_kind, NULL, ex)) + goto fail_invalid_arg; + + if (has_origin_authentication(protection_kind)) + { + if (!check_reader_specific_mac(factory, &header, footer, CRYPTO_OBJECT_KIND_REMOTE_WRITER_CRYPTO, writer_crypto, context, ex)) + goto fail_reader_mac; + } + + /* calculate the session key */ + if (!initialize_remote_session_info(&remote_session, &header, writer_master_key->master_salt, writer_master_key->master_sender_key, writer_master_key->transformation_kind, ex)) + goto fail_decrypt; + + if (is_encryption_required(transform_kind)) + { + if (!is_encryption_expected(protection_kind)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datawriter_submessage: submessage is encrypted, which is unexpected (%d vs %d)", + (int)transform_kind, (int)protection_kind); + goto fail_decrypt; + } + /* When the CryptoHeader indicates that encryption is performed then decrypt the submessage body */ + /* check if the body is a SEC_BODY submessage */ + if (body.id != SMID_SEC_BODY_KIND) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datawriter_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_decrypt; + } + + plain_submsg->_buffer = DDS_Security_OctetSeq_allocbuf(contents._length); + plain_submsg->_length = plain_submsg->_maximum = contents._length; + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, contents._data, contents._length, NULL, 0, + plain_submsg->_buffer, &plain_submsg->_length, &footer->common_mac, ex)) + { + goto fail_decrypt; + } + } + else if (is_authentication_required(transform_kind)) + { + if (!is_authentication_expected(protection_kind)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datawriter_submessage: submessage is signed, which is unexpected"); + goto fail_decrypt; + } + assert(transform_id != 0); + /* When the CryptoHeader indicates that authentication is performed then calculate the HMAC */ + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, NULL, 0, contents._data, contents._length, NULL, 0, &footer->common_mac, ex)) + goto fail_decrypt; + plain_submsg->_buffer = DDS_Security_OctetSeq_allocbuf(contents._length); + plain_submsg->_length = plain_submsg->_maximum = contents._length; + memcpy(plain_submsg->_buffer, contents._data, contents._length); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_CODE, 0, + "decode_serialized_payload: " DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_MESSAGE); + goto fail_decrypt; + } + + ddsrt_free(footer); + CRYPTO_OBJECT_RELEASE(writer_master_key); + return true; + + +fail_decrypt: + DDS_Security_OctetSeq_deinit(plain_submsg); +fail_reader_mac: + CRYPTO_OBJECT_RELEASE(writer_master_key); +fail_invalid_arg: + ddsrt_free(footer); + return false; +} + +static DDS_Security_boolean +decode_datareader_submessage( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_submsg, + const DDS_Security_OctetSeq *encoded_submsg, + const DDS_Security_DatawriterCryptoHandle writer_crypto, + const DDS_Security_DatareaderCryptoHandle reader_crypto, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + static const char *context = "decode_datareader_submessage"; + dds_security_crypto_key_factory *factory; + uint32_t transform_kind, transform_id; + master_key_material *reader_master_key; + DDS_Security_ProtectionKind protection_kind; + remote_session_info remote_session; + struct submsg_header prefix; + struct crypto_header header; + struct submsg_header postfix; + struct submsg_header body; + struct crypto_footer *footer; + struct crypto_contents_ref contents; + + /* check arguments */ + if (!instance || writer_crypto == 0 || reader_crypto == 0 || !encoded_submsg || + encoded_submsg->_length == 0 || !encoded_submsg->_buffer || !plain_submsg) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datareader_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + memset(plain_submsg, 0, sizeof(*plain_submsg)); + + factory = cryptography_get_crypto_key_factory(impl->crypto); + + /* split the encoded submessage in the corresponding parts */ + if (!split_encoded_submessage(encoded_submsg, &prefix, &body, &postfix, &header, &contents, &footer)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datareader_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + return false; + } + + transform_kind = CRYPTO_TRANSFORM_KIND(header.transform_identifier.transformation_kind); + transform_id = CRYPTO_TRANSFORM_ID(header.transform_identifier.transformation_key_id); + + /* Retrieve key material from sending_datareader_crypto from factory */ + if (!crypto_factory_get_remote_reader_key_material(factory, writer_crypto, reader_crypto, transform_id, &reader_master_key, &protection_kind, ex)) + goto fail_invalid_arg; + + if (has_origin_authentication(protection_kind)) + { + if (!check_reader_specific_mac(factory, &header, footer, CRYPTO_OBJECT_KIND_REMOTE_READER_CRYPTO, reader_crypto, context, ex)) + goto fail_reader_mac; + } + + /* calculate the session key */ + if (!initialize_remote_session_info(&remote_session, &header, reader_master_key->master_salt, reader_master_key->master_sender_key, reader_master_key->transformation_kind, ex)) + goto fail_decrypt; + + if (is_encryption_required(transform_kind)) + { + if (!is_encryption_expected(protection_kind)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datareader_submessage: submessage is encrypted, which is unexpected"); + goto fail_decrypt; + } + /* When the CryptoHeader indicates that encryption is performed then decrypt the submessage body */ + /* check if the body is a SEC_BODY submessage */ + if (body.id != SMID_SEC_BODY_KIND) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datareader_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_decrypt; + } + + plain_submsg->_buffer = DDS_Security_OctetSeq_allocbuf(contents._length); + plain_submsg->_length = plain_submsg->_maximum = contents._length; + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, contents._data, contents._length, NULL, 0, + plain_submsg->_buffer, &plain_submsg->_length, &footer->common_mac, ex)) + { + goto fail_decrypt; + } + } + else if (is_authentication_required(transform_kind)) + { + if (!is_authentication_expected(protection_kind)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_datareader_submessage: submessage is signed, which is unexpected"); + goto fail_decrypt; + } + /* When the CryptoHeader indicates that authentication is performed then calculate the HMAC */ + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, NULL, 0, contents._data, contents._length, NULL, 0, &footer->common_mac, ex)) + goto fail_decrypt; + plain_submsg->_buffer = DDS_Security_OctetSeq_allocbuf(contents._length); + plain_submsg->_length = plain_submsg->_maximum = contents._length; + memcpy(plain_submsg->_buffer, contents._data, contents._length); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, + DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_CODE, 0, + "decode_datareader_submessage: " DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_MESSAGE); + goto fail_decrypt; + } + ddsrt_free(footer); + CRYPTO_OBJECT_RELEASE(reader_master_key); + return true; + +fail_decrypt: + DDS_Security_OctetSeq_deinit(plain_submsg); +fail_reader_mac: + CRYPTO_OBJECT_RELEASE(reader_master_key); +fail_invalid_arg: + ddsrt_free(footer); + return false; +} + +static DDS_Security_boolean +decode_serialized_payload( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_buffer, + const DDS_Security_OctetSeq *encoded_buffer, + const DDS_Security_OctetSeq *inline_qos, + const DDS_Security_DatareaderCryptoHandle reader_id, + const DDS_Security_DatawriterCryptoHandle writer_id, + DDS_Security_SecurityException *ex) +{ + dds_security_crypto_transform_impl *impl = (dds_security_crypto_transform_impl *)instance; + dds_security_crypto_key_factory *factory; + DDS_Security_BasicProtectionKind basic_protection_kind; + master_key_material *writer_master_key; + remote_session_info remote_session; + uint32_t transform_kind, transform_id; + struct crypto_header header; + unsigned char *payload_ptr; + uint32_t payload_len; + struct crypto_footer *footer = NULL; + + DDSRT_UNUSED_ARG(inline_qos); + + if (!instance || !encoded_buffer || !plain_buffer || reader_id == 0 || writer_id == 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_serialized_payload: " DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_MESSAGE); + goto fail_inv_arg; + } + + if ((plain_buffer->_buffer != NULL) || (plain_buffer->_length != 0)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_serialized_payload: given plain_buffer not empty"); + goto fail_inv_arg; + } + + /* Retrieve key material from sending_datawriter_crypto from factory */ + factory = cryptography_get_crypto_key_factory(impl->crypto); + + /* determine CryptoHeader, CryptoContent and CryptoFooter*/ + if (!split_encoded_serialized_payload(encoded_buffer, &header, &payload_ptr, &payload_len, &footer)) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_serialized_payload: Invalid syntax of encoded payload"); + goto fail_split; + } + + if (footer->receiver_specific_macs._length != 0) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_serialized_payload: Received specific_macs"); + goto fail_prepare; + } + + transform_kind = CRYPTO_TRANSFORM_KIND(header.transform_identifier.transformation_kind); + transform_id = CRYPTO_TRANSFORM_ID(header.transform_identifier.transformation_key_id); + + if (!crypto_factory_get_remote_writer_key_material(factory, reader_id, writer_id, transform_id, &writer_master_key, NULL, &basic_protection_kind, ex)) + goto fail_prepare; + + /* calculate the session key */ + if (!initialize_remote_session_info(&remote_session, &header, writer_master_key->master_salt, writer_master_key->master_sender_key, writer_master_key->transformation_kind, ex)) + goto fail_decrypt; + + /* + * Depending on encryption, the payload part between Header and Footer is + * either CryptoContent or the original plain payload. + * See spec: 9.5.3.3.4.4 Result from encode_serialized_payload + */ + if (is_encryption_required(transform_kind)) + { + struct crypto_contents_ref contents; + /* Is encryption expected? */ + if (basic_protection_kind != DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_serialized_payload: payload is encrypted, which is unexpected"); + goto fail_decrypt; + } + /* When encrypted, the content payload starts with a length: update contents. */ + if (read_crypto_contents(&contents, payload_ptr, payload_len)) + { + /* When the CryptoHeader indicates that encryption is performed then decrypt the payload */ + plain_buffer->_buffer = DDS_Security_OctetSeq_allocbuf(contents._length); + plain_buffer->_length = plain_buffer->_maximum = contents._length; + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, contents._data, contents._length, NULL, 0, plain_buffer->_buffer, &plain_buffer->_length, &footer->common_mac, ex)) + { + goto fail_decrypt; + } + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_CODE, 0, + "decode_serialized_payload: invalid payload format"); + goto fail_decrypt; + } + } + else if (is_authentication_required(transform_kind)) + { + /* Is signing expected? */ + if (basic_protection_kind != DDS_SECURITY_BASICPROTECTION_KIND_SIGN) + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_ARGUMENT_CODE, 0, + "decode_serialized_payload: payload is signed, which is unexpected"); + goto fail_decrypt; + } + /* When the CryptoHeader indicates that authentication is performed then calculate the HMAC */ + if (!crypto_cipher_decrypt_data(&remote_session, header.session_id, NULL, 0, payload_ptr, payload_len, NULL, 0, &footer->common_mac, ex)) + { + goto fail_decrypt; + } + plain_buffer->_buffer = DDS_Security_OctetSeq_allocbuf(payload_len); + plain_buffer->_length = plain_buffer->_maximum = payload_len; + memcpy(plain_buffer->_buffer, payload_ptr, payload_len); + } + else + { + DDS_Security_Exception_set(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_CODE, 0, + "decode_serialized_payload: " DDS_SECURITY_ERR_INVALID_CRYPTO_TRANSFORMATION_MESSAGE); + goto fail_decrypt; + } + ddsrt_free(footer); + CRYPTO_OBJECT_RELEASE(writer_master_key); + return true; + +fail_decrypt: + DDS_Security_OctetSeq_deinit(plain_buffer); + CRYPTO_OBJECT_RELEASE(writer_master_key); +fail_prepare: + ddsrt_free(footer); +fail_split: +fail_inv_arg: + return false; +} + +dds_security_crypto_transform * +dds_security_crypto_transform__alloc( + const dds_security_cryptography *crypto) +{ + dds_security_crypto_transform_impl *instance; + instance = (dds_security_crypto_transform_impl *)ddsrt_malloc( + sizeof(dds_security_crypto_transform_impl)); + + instance->crypto = crypto; + instance->base.encode_datawriter_submessage = &encode_datawriter_submessage; + instance->base.encode_datareader_submessage = &encode_datareader_submessage; + instance->base.encode_rtps_message = &encode_rtps_message; + instance->base.encode_serialized_payload = &encode_serialized_payload; + instance->base.decode_rtps_message = &decode_rtps_message; + instance->base.preprocess_secure_submsg = &preprocess_secure_submsg; + instance->base.decode_datawriter_submessage = &decode_datawriter_submessage; + instance->base.decode_datareader_submessage = &decode_datareader_submessage; + instance->base.decode_serialized_payload = &decode_serialized_payload; + + dds_openssl_init (); + return (dds_security_crypto_transform *)instance; +} + +void dds_security_crypto_transform__dealloc( + dds_security_crypto_transform *instance) +{ + ddsrt_free((dds_security_crypto_transform_impl *)instance); +} diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_transform.h b/src/security/builtin_plugins/cryptographic/src/crypto_transform.h new file mode 100644 index 0000000..7a73075 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_transform.h @@ -0,0 +1,28 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTO_TRANSFORM_H +#define CRYPTO_TRANSFORM_H + +#include "dds/security/dds_security_api.h" + +/** + * @brief Allocation function for implementer structure (with internal variables) transparently. + */ +dds_security_crypto_transform * +dds_security_crypto_transform__alloc( + const dds_security_cryptography *crypto); + +void +dds_security_crypto_transform__dealloc( + dds_security_crypto_transform *instance); + +#endif /* CRYPTO_TRANSFORM_H */ diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_utils.c b/src/security/builtin_plugins/cryptographic/src/crypto_utils.c new file mode 100644 index 0000000..075a8ef --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_utils.c @@ -0,0 +1,152 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/openssl_support.h" +#include "crypto_defs.h" +#include "crypto_utils.h" + +char *crypto_openssl_error_message(void) +{ + BIO *bio = BIO_new(BIO_s_mem()); + char *msg; + char *buf = NULL; + size_t len; + + if (!bio) + return ddsrt_strdup ("BIO_new failed"); + + ERR_print_errors(bio); + len = (size_t) BIO_get_mem_data(bio, &buf); + msg = ddsrt_malloc(len + 1); + memset(msg, 0, len + 1); + memcpy(msg, buf, len); + BIO_free(bio); + return msg; +} + +static bool +crypto_calculate_key_impl( + const char *prefix, + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + DDS_Security_SecurityException *ex) +{ + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(transformation_kind); + uint32_t id = ddsrt_toBE4u(session_id); + size_t sz = strlen(prefix) + key_bytes + sizeof(id); + unsigned char *buffer = ddsrt_malloc (sz); + unsigned char md[EVP_MAX_MD_SIZE]; + + memcpy(buffer, prefix, strlen(prefix)); + memcpy(&buffer[strlen(prefix)], master_salt, key_bytes); + memcpy(&buffer[strlen(prefix) + key_bytes], &id, sizeof(id)); + + if (HMAC(EVP_sha256(), master_key, (int)key_bytes, buffer, sz, md, NULL) == NULL) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_CIPHER_ERROR, 0, "HMAC failed: "); + ddsrt_free (buffer); + return false; + } + memcpy (session_key->data, md, key_bytes); + ddsrt_free (buffer); + return true; +} + +bool +crypto_calculate_session_key( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + DDS_Security_SecurityException *ex) +{ + return crypto_calculate_key_impl("SessionKey", session_key, session_id, master_salt, master_key, transformation_kind, ex); +} + +bool +crypto_calculate_receiver_specific_key( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + DDS_Security_SecurityException *ex) +{ + return crypto_calculate_key_impl("SessionReceiverKey", session_key, session_id, master_salt, master_key, transformation_kind, ex); +} + +uint32_t +crypto_get_key_size( + DDS_Security_CryptoTransformKind_Enum kind) +{ + switch (kind) + { + case CRYPTO_TRANSFORMATION_KIND_AES128_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES128_GCM: + return 128; + case CRYPTO_TRANSFORMATION_KIND_AES256_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES256_GCM: + return 256; + default: + return 0; + } +} + +uint32_t +crypto_get_random_uint32(void) +{ + uint32_t val; + RAND_bytes((unsigned char *)&val, sizeof(uint32_t)); + return val; +} + +uint64_t +crypto_get_random_uint64(void) +{ + uint64_t val; + RAND_bytes((unsigned char *)&val, sizeof(uint64_t)); + return val; +} + +unsigned char * +crypto_hmac256( + const unsigned char *key, + uint32_t key_size, + const unsigned char *data, + uint32_t data_size, + DDS_Security_SecurityException *ex) +{ + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned char *result; + + assert (key_size <= INT32_MAX); + if (HMAC(EVP_sha256(), key, (int) key_size, data, data_size, md, NULL) == NULL) + { + DDS_Security_Exception_set_with_openssl_error(ex, DDS_CRYPTO_PLUGIN_CONTEXT, DDS_SECURITY_ERR_UNDEFINED_CODE, 0, "Failed to init hashing context: "); + return NULL; + } + result = ddsrt_malloc(key_size); + memcpy (result, md, key_size); + return result; +} diff --git a/src/security/builtin_plugins/cryptographic/src/crypto_utils.h b/src/security/builtin_plugins/cryptographic/src/crypto_utils.h new file mode 100644 index 0000000..b9ef5b9 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/crypto_utils.h @@ -0,0 +1,95 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTO_UTILS_H +#define CRYPTO_UTILS_H + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/types.h" +#include "dds/security/export.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_types.h" +#include "crypto_defs.h" + +#define CRYPTO_TRANSFORM_KIND(k) ddsrt_fromBE4u((*(uint32_t *)&((k)[0]))) +#define CRYPTO_TRANSFORM_ID(k) ddsrt_fromBE4u((*(uint32_t *)&((k)[0]))) +#define CRYPTO_KEY_SIZE_BYTES(kind) (crypto_get_key_size(kind) >> 3) + +#define ALIGN4(x) (((x) + 3) & (uint32_t)(-4)) + +struct init_vector_suffix +{ + uint32_t high; + uint32_t low; +}; + +/** + * Return a string that contains an openssl error description + * When a openssl function returns an error this function can be + * used to retrieve a descriptive error string. + * Note that the returned string should be freed. + */ +char *crypto_openssl_error_message(void); + +/** + * @param[in,out] session_key Session key + * @param[in] session_id Session Id + * @param[in] master_salt Master salt + * @param[in] master_key Master key + * @param[in] transformation_kind Transformation kind + * @param[in,out] ex Security exception + */ +SECURITY_EXPORT bool crypto_calculate_session_key( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + DDS_Security_SecurityException *ex); + +/** + * @param[in,out] session_key Session key + * @param[in] session_id Session Id + * @param[in] master_salt Master salt + * @param[in] master_key Master key + * @param[in] transformation_kind Transformation kind + * @param[in,out] ex Security exception + */ +SECURITY_EXPORT bool crypto_calculate_receiver_specific_key( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + DDS_Security_SecurityException *ex); + +SECURITY_EXPORT uint32_t crypto_get_key_size(DDS_Security_CryptoTransformKind_Enum kind); +SECURITY_EXPORT uint32_t crypto_get_random_uint32(void); +SECURITY_EXPORT uint64_t crypto_get_random_uint64(void); + +/** + * @brief Compute a HMAC256 on the provided data. + * + * @param[in] key The key used to compute the HMAC256 result + * @param[in] key_size The size of the key (128 or 256 bits) + * @param[in] data The data on which the HMAC is computed + * @param[in] data_size The size of the data + * @param[in,out] ex Security exception + */ +SECURITY_EXPORT unsigned char *crypto_hmac256( + const unsigned char *key, + uint32_t key_size, + const unsigned char *data, + uint32_t data_size, + DDS_Security_SecurityException *ex); + +#endif /* CRYPTO_UTILS_H */ diff --git a/src/security/builtin_plugins/cryptographic/src/cryptography.c b/src/security/builtin_plugins/cryptographic/src/cryptography.c new file mode 100644 index 0000000..6e4f780 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/cryptography.c @@ -0,0 +1,101 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/security/dds_security_api.h" +#include "cryptography.h" +#include "crypto_key_exchange.h" +#include "crypto_key_factory.h" +#include "crypto_transform.h" + +/** + * Implementation structure for storing encapsulated members of the instance + * while giving only the interface definition to user + */ + +typedef struct dds_security_cryptography_impl { + dds_security_cryptography base; + struct ddsi_domaingv *gv; +} dds_security_cryptography_impl; + +dds_security_crypto_key_factory *cryptography_get_crypto_key_factory (const struct dds_security_cryptography *crypto) +{ + const dds_security_cryptography_impl *instance = (dds_security_cryptography_impl *) crypto; + return instance->base.crypto_key_factory; +} + +dds_security_crypto_key_exchange *cryptography_get_crypto_key_exchange (const struct dds_security_cryptography *crypto) +{ + const dds_security_cryptography_impl *instance = (dds_security_cryptography_impl *) crypto; + return instance->base.crypto_key_exchange; +} + +dds_security_crypto_transform *cryptography_get_crypto_transform (const struct dds_security_cryptography *crypto) +{ + const dds_security_cryptography_impl *instance = (dds_security_cryptography_impl *) crypto; + return instance->base.crypto_transform; +} + + +int init_crypto (const char *argument, void **context, struct ddsi_domaingv *gv) +{ + dds_security_cryptography_impl *cryptography; + dds_security_crypto_key_exchange *crypto_key_exchange; + dds_security_crypto_key_factory *crypto_key_factory; + dds_security_crypto_transform *crypto_transform; + + DDSRT_UNUSED_ARG (argument); + + /* allocate new instance */ + cryptography = ddsrt_malloc (sizeof(*cryptography)); + cryptography->base.gv = gv; + + /* assign the sub components */ + crypto_key_exchange = dds_security_crypto_key_exchange__alloc ((dds_security_cryptography *)cryptography); + if (!crypto_key_exchange) goto err_exchange; + + crypto_key_factory = dds_security_crypto_key_factory__alloc ((dds_security_cryptography *)cryptography); + if (!crypto_key_factory) goto err_factory; + + crypto_transform = dds_security_crypto_transform__alloc ((dds_security_cryptography *)cryptography); + if (!crypto_transform) goto err_transform; + + cryptography->base.crypto_key_exchange = crypto_key_exchange; + cryptography->base.crypto_key_factory = crypto_key_factory; + cryptography->base.crypto_transform = crypto_transform; + + /* return the instance */ + *context = cryptography; + return DDS_SECURITY_SUCCESS; + +err_transform: + dds_security_crypto_key_factory__dealloc (crypto_key_factory); +err_factory: + dds_security_crypto_key_exchange__dealloc (crypto_key_exchange); +err_exchange: + ddsrt_free (cryptography); + *context = NULL; + return DDS_SECURITY_FAILED; +} + +int finalize_crypto (void *instance) +{ + dds_security_cryptography_impl* instance_impl = (dds_security_cryptography_impl*) instance; + /* deallocate components */ + dds_security_crypto_key_exchange__dealloc (instance_impl->base.crypto_key_exchange); + dds_security_crypto_key_factory__dealloc (instance_impl->base.crypto_key_factory); + dds_security_crypto_transform__dealloc (instance_impl->base.crypto_transform); + /* deallocate cryptography */ + ddsrt_free (instance_impl); + return DDS_SECURITY_SUCCESS; +} diff --git a/src/security/builtin_plugins/cryptographic/src/cryptography.h b/src/security/builtin_plugins/cryptographic/src/cryptography.h new file mode 100644 index 0000000..a74b771 --- /dev/null +++ b/src/security/builtin_plugins/cryptographic/src/cryptography.h @@ -0,0 +1,26 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef CRYPTOGRAPHY_H +#define CRYPTOGRAPHY_H + +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/export.h" + +SECURITY_EXPORT int init_crypto(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_crypto(void *instance); + +dds_security_crypto_key_factory *cryptography_get_crypto_key_factory(const dds_security_cryptography *crypto); +dds_security_crypto_key_exchange * cryptography_get_crypto_key_exchange(const dds_security_cryptography *crypto); +dds_security_crypto_transform *cryptography_get_crypto_transform(const dds_security_cryptography *crypto); + +#endif /* CRYPTOGRAPHY_H */ diff --git a/src/security/builtin_plugins/tests/CMakeLists.txt b/src/security/builtin_plugins/tests/CMakeLists.txt new file mode 100644 index 0000000..6f26a68 --- /dev/null +++ b/src/security/builtin_plugins/tests/CMakeLists.txt @@ -0,0 +1,85 @@ + # +# Copyright(c) 2006 to 2019 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +include(CUnit) + +set(security_auth_test_sources + "common/src/loader.c" + "common/src/handshake_helper.c" + "get_authenticated_peer_credential_token/src/get_authenticated_peer_credential_token_utests.c" + "process_handshake/src/process_handshake_utests.c" + "validate_begin_handshake_reply/src/validate_begin_handshake_reply_utests.c" + "validate_begin_handshake_request/src/validate_begin_handshake_request_utests.c" + "validate_local_identity/src/validate_local_identity_utests.c" + "validate_remote_identity/src/validate_remote_identity_utests.c" + "listeners_authentication/src/listeners_authentication_utests.c" + "listeners_access_control/src/listeners_access_control_utests.c" +) + +set(security_ac_test_sources + "access_control_fnmatch/src/access_control_fnmatch_utests.c" + "get_permissions_credential_token/src/get_permissions_credential_token_utests.c" + "get_permissions_token/src/get_permissions_token_utests.c" + "get_xxx_sec_attributes/src/get_xxx_sec_attributes_utests.c" + # "listeners_access_control/src/listeners_access_control_utests.c" + "validate_local_permissions/src/validate_local_permissions_utests.c" + "validate_remote_permissions/src/validate_remote_permissions_utests.c" +) + +set(security_crypto_test_sources + "common/src/crypto_helper.c" + "create_local_datareader_crypto_tokens/src/create_local_datareader_crypto_tokens_utests.c" + "create_local_datawriter_crypto_tokens/src/create_local_datawriter_crypto_tokens_utests.c" + "create_local_participant_crypto_tokens/src/create_local_participant_crypto_tokens_utests.c" + "decode_datareader_submessage/src/decode_datareader_submessage_utests.c" + "decode_datawriter_submessage/src/decode_datawriter_submessage_utests.c" + "decode_rtps_message/src/decode_rtps_message_utests.c" + "decode_serialized_payload/src/decode_serialized_payload_utests.c" + "encode_datareader_submessage/src/encode_datareader_submessage_utests.c" + "encode_datawriter_submessage/src/encode_datawriter_submessage_utests.c" + "encode_rtps_message/src/encode_rtps_message_utests.c" + "encode_serialized_payload/src/encode_serialized_payload_utests.c" + "preprocess_secure_submsg/src/preprocess_secure_submsg_utests.c" + "register_local_datareader/src/register_local_datareader_utests.c" + "register_local_datawriter/src/register_local_datawriter_utests.c" + "register_local_participant/src/register_local_participant_utests.c" + "register_matched_remote_datareader/src/register_matched_remote_datareader_utests.c" + "register_matched_remote_datawriter/src/register_matched_remote_datawriter_utests.c" + "register_matched_remote_participant/src/register_matched_remote_participant_utests.c" + "set_remote_datareader_crypto_tokens/src/set_remote_datareader_crypto_tokens_utests.c" + "set_remote_datawriter_crypto_tokens/src/set_remote_datawriter_crypto_tokens_utests.c" + "set_remote_participant_crypto_tokens/src/set_remote_participant_crypto_tokens_utests.c" +) + +add_cunit_executable(cunit_security_plugins ${security_auth_test_sources} ${security_ac_test_sources} ${security_crypto_test_sources}) + +target_include_directories( + cunit_security_plugins PRIVATE + "$" + "$" + "$" + "$>" + "$>" + "$>" + "$>" + "$" + "$" +) +target_link_libraries(cunit_security_plugins PRIVATE ddsc security_api dds_security_ac dds_security_crypto) +target_link_libraries(cunit_security_plugins PRIVATE security_openssl) +target_link_libraries(cunit_security_plugins PRIVATE OpenSSL::SSL) +if(CMAKE_GENERATOR MATCHES "Visual Studio") + set_target_properties(cunit_security_plugins PROPERTIES LINK_FLAGS "/ignore:4099") +endif() + +set(CUnit_builtin_plugins_tests_dir "${CMAKE_CURRENT_LIST_DIR}") +set(CUnit_build_dir "${CMAKE_CURRENT_BINARY_DIR}") +configure_file("config_env.h.in" "config_env.h") diff --git a/src/security/builtin_plugins/tests/access_control_fnmatch/src/access_control_fnmatch_utests.c b/src/security/builtin_plugins/tests/access_control_fnmatch/src/access_control_fnmatch_utests.c new file mode 100644 index 0000000..08568a3 --- /dev/null +++ b/src/security/builtin_plugins/tests/access_control_fnmatch/src/access_control_fnmatch_utests.c @@ -0,0 +1,67 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#include +#include +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "assert.h" +#include "access_control_utils.h" + + +CU_Test(ddssec_builtin_access_control_fnmatch, basic) +{ + CU_ASSERT(ac_fnmatch("", "")); + CU_ASSERT(ac_fnmatch("abc", "abc")); + CU_ASSERT(!ac_fnmatch("abc", "ab")); + CU_ASSERT(!ac_fnmatch("", "a")); + CU_ASSERT(!ac_fnmatch("a", "")); + + CU_ASSERT(ac_fnmatch("a?", "ab")); + CU_ASSERT(ac_fnmatch("?b", "ab")); + CU_ASSERT(ac_fnmatch("a?c", "abc")); + CU_ASSERT(!ac_fnmatch("a?", "abc")); + CU_ASSERT(!ac_fnmatch("?c", "abc")); + + CU_ASSERT(ac_fnmatch("a*", "a")); + CU_ASSERT(ac_fnmatch("a*", "abc")); + CU_ASSERT(ac_fnmatch("a*c", "abc")); + CU_ASSERT(ac_fnmatch("a*c", "abbc")); + CU_ASSERT(ac_fnmatch("*c", "abc")); + CU_ASSERT(ac_fnmatch("*c", "c")); + CU_ASSERT(!ac_fnmatch("a*", "")); + CU_ASSERT(!ac_fnmatch("a*c", "bc")); + + CU_ASSERT(ac_fnmatch("[ab]", "a")); + CU_ASSERT(ac_fnmatch("[ab]", "b")); + CU_ASSERT(ac_fnmatch("a[bc]", "ab")); + CU_ASSERT(ac_fnmatch("a[bc]", "ac")); + CU_ASSERT(ac_fnmatch("a[bc]d", "abd")); + CU_ASSERT(ac_fnmatch("a[b-d]", "ab")); + CU_ASSERT(ac_fnmatch("a[b-d]", "ac")); + CU_ASSERT(ac_fnmatch("a[b-d]", "ad")); + CU_ASSERT(ac_fnmatch("a[-b]", "ab")); + CU_ASSERT(ac_fnmatch("a[!b]", "ac")); + CU_ASSERT(ac_fnmatch("a[!bc]d", "aad")); + CU_ASSERT(ac_fnmatch("a]", "a]")); + CU_ASSERT(!ac_fnmatch("[ab]", "c")); + CU_ASSERT(!ac_fnmatch("a[bc]", "ad")); + CU_ASSERT(!ac_fnmatch("a[bc]", "abc")); + CU_ASSERT(!ac_fnmatch("a[b-]", "ab")); + CU_ASSERT(!ac_fnmatch("a[-", "a")); + CU_ASSERT(!ac_fnmatch("a[", "a[")); + CU_ASSERT(!ac_fnmatch("a[-", "a[-")); + CU_ASSERT(!ac_fnmatch("a[!b]", "ab")); + CU_ASSERT(!ac_fnmatch("a[!bc]d", "abd")); + CU_ASSERT(!ac_fnmatch("a[!b-d]", "ac")); + CU_ASSERT(!ac_fnmatch("a[!-b]", "ab")); +} diff --git a/src/security/builtin_plugins/tests/common/src/crypto_helper.c b/src/security/builtin_plugins/tests/common/src/crypto_helper.c new file mode 100644 index 0000000..824918b --- /dev/null +++ b/src/security/builtin_plugins/tests/common/src/crypto_helper.c @@ -0,0 +1,109 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "crypto_helper.h" +#include "crypto_utils.h" + + +static bool +crypto_calculate_session_key_impl_test( + const char *prefix, + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + bool result = true; + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(transformation_kind); + uint32_t id = ddsrt_toBE4u(session_id); + size_t sz = strlen(prefix) + key_bytes + sizeof(id); + unsigned char *buffer = ddsrt_malloc (sz); + memcpy(buffer, prefix, strlen(prefix)); + memcpy(&buffer[strlen(prefix)], master_salt, key_bytes); + memcpy(&buffer[strlen(prefix) + key_bytes], &id, sizeof(id)); + if (HMAC(EVP_sha256(), master_key, (int)key_bytes, buffer, sz, session_key->data, NULL) == NULL) + { + ERR_print_errors_fp(stderr); + result = false; + } + ddsrt_free (buffer); + return result; +} + +bool +crypto_calculate_session_key_test( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + return crypto_calculate_session_key_impl_test ("SessionKey", session_key, session_id, master_salt, master_key, transformation_kind); +} + +bool calculate_receiver_specific_key_test( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + return crypto_calculate_session_key_impl_test ("SessionReceiverKey", session_key, session_id, master_salt, master_key, transformation_kind); +} + +int master_salt_not_empty(master_key_material *keymat) +{ + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(keymat->transformation_kind); + for (uint32_t i = 0; i < key_bytes; i++) + { + if (keymat->master_salt[i]) + return 1; + } + return 0; +} + +int master_key_not_empty(master_key_material *keymat) +{ + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(keymat->transformation_kind); + for (uint32_t i = 0; i < key_bytes; i++) + { + if (keymat->master_sender_key[i]) + return 1; + } + return 0; +} + +int master_receiver_specific_key_not_empty(master_key_material *keymat) +{ + uint32_t key_bytes = CRYPTO_KEY_SIZE_BYTES(keymat->transformation_kind); + for (uint32_t i = 0; i < key_bytes; i++) + { + if (keymat->master_receiver_specific_key[i]) + return 1; + } + return 0; +} diff --git a/src/security/builtin_plugins/tests/common/src/crypto_helper.h b/src/security/builtin_plugins/tests/common/src/crypto_helper.h new file mode 100644 index 0000000..775a1d7 --- /dev/null +++ b/src/security/builtin_plugins/tests/common/src/crypto_helper.h @@ -0,0 +1,39 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef DDS_SECURITY_BUITIN_TEST_CRYPTO_HELPER_H +#define DDS_SECURITY_BUITIN_TEST_CRYPTO_HELPER_H + +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "crypto_objects.h" + +bool +crypto_calculate_session_key_test( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind); + +bool calculate_receiver_specific_key_test( + crypto_session_key_t *session_key, + uint32_t session_id, + const unsigned char *master_salt, + const unsigned char *master_key, + DDS_Security_CryptoTransformKind_Enum transformation_kind); + +int master_salt_not_empty(master_key_material *keymat); +int master_key_not_empty(master_key_material *keymat); +int master_receiver_specific_key_not_empty(master_key_material *keymat); + +#endif /* DDS_SECURITY_BUITIN_TEST_CRYPTO_HELPER_H */ + diff --git a/src/security/builtin_plugins/tests/common/src/handshake_helper.c b/src/security/builtin_plugins/tests/common/src/handshake_helper.c new file mode 100644 index 0000000..ae755f8 --- /dev/null +++ b/src/security/builtin_plugins/tests/common/src/handshake_helper.c @@ -0,0 +1,569 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include + +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/misc.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "handshake_helper.h" + +const BIGNUM * +dh_get_public_key( + DH *dhkey) +{ +#ifdef AUTH_INCLUDE_DH_ACCESSORS + const BIGNUM *pubkey, *privkey; + DH_get0_key(dhkey, &pubkey, &privkey); + return pubkey; +#else + return dhkey->pub_key; +#endif +} + +int +dh_set_public_key( + DH *dhkey, + BIGNUM *pubkey) +{ +#ifdef AUTH_INCLUDE_DH_ACCESSORS + return DH_set0_key(dhkey, pubkey, NULL); +#else + dhkey->pub_key = pubkey; +#endif + return 1; +} + + +/* for DEBUG purposes */ +void print_binary_test( char* name, unsigned char *value, uint32_t size){ + uint32_t i; + printf("%s: ",name ); + for( i=0; i< size; i++) + { + printf("%x",value[i]); + } + printf("\n"); +} + +DDS_Security_BinaryProperty_t * +print_binary_properties_test( + DDS_Security_DataHolder *token) +{ + DDS_Security_BinaryProperty_t *result = NULL; + uint32_t i; + for (i = 0; i < token->binary_properties._length && !result; i++) { + print_binary_test( token->binary_properties._buffer[i].name, token->binary_properties._buffer[i].value._buffer, token->binary_properties._buffer[i].value._length); + } + + return result; +} + +DDS_Security_ValidationResult_t +create_signature_for_test( + EVP_PKEY *pkey, + const DDS_Security_BinaryProperty_t **binary_properties, + const uint32_t binary_properties_length, + unsigned char **signature, + size_t *signatureLen, + DDS_Security_SecurityException *ex) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_Serializer serializer; + unsigned char *buffer; + size_t size; + + serializer = DDS_Security_Serializer_new(4096, 4096); + + DDS_Security_Serialize_BinaryPropertyArray(serializer,binary_properties, binary_properties_length); + DDS_Security_Serializer_buffer(serializer, &buffer, &size); + + result = create_asymmetrical_signature_for_test(pkey, buffer, size, signature, signatureLen, ex); + + ddsrt_free(buffer); + DDS_Security_Serializer_free(serializer); + + return result; +} + +#if( AC_TESTS_IMPLEMENTED ) +static DDS_Security_ValidationResult_t +screate_asymmetrical_signature_for_test( + EVP_PKEY *pkey, + void *data, + size_t dataLen, + unsigned char **signature, + size_t *signatureLen, + DDS_Security_SecurityException *ex) +{ + DDS_Security_ValidationResult_t result = DDS_SECURITY_VALIDATION_OK; + EVP_MD_CTX *mdctx = NULL; + EVP_PKEY_CTX *kctx = NULL; + + if (!(mdctx = EVP_MD_CTX_create())) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, result, "Failed to create signing context: %s", msg); + ddsrt_free(msg); + goto err_create_ctx; + } + + if (EVP_DigestSignInit(mdctx, &kctx, EVP_sha256(), NULL, pkey) != 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, result, "Failed to initialize signing context: %s", msg); + ddsrt_free(msg); + goto err_sign; + } + + if (EVP_PKEY_CTX_set_rsa_padding(kctx, RSA_PKCS1_PSS_PADDING) < 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, result, "Failed to initialize signing context: %s", msg); + ddsrt_free(msg); + goto err_sign; + } + + if (EVP_DigestSignUpdate(mdctx, data, dataLen) != 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, result, "Failed to update signing context: %s", msg); + ddsrt_free(msg); + goto err_sign; + } + + if (EVP_DigestSignFinal(mdctx, NULL, signatureLen) != 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, result, "Failed to finalize signing context: %s", msg); + ddsrt_free(msg); + goto err_sign; + } + + //*signature = ddsrt_malloc(sizeof(unsigned char) * (*signatureLen)); + *signature = OPENSSL_malloc(*signatureLen); + if (EVP_DigestSignFinal(mdctx, *signature, signatureLen) != 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, result, "Failed to finalize signing context: %s", msg); + ddsrt_free(msg); + ddsrt_free(signature); + } + +err_sign: + EVP_MD_CTX_destroy(mdctx); +err_create_ctx: + return result; +} +#endif + + +char * +get_openssl_error_message_for_test( + void) +{ + BIO *bio = BIO_new(BIO_s_mem()); + char *msg; + char *buf = NULL; + size_t len; + + if (bio) { + ERR_print_errors(bio); + len = (size_t)BIO_get_mem_data (bio, &buf); + msg = ddsrt_malloc(len + 1); + memset(msg, 0, len+1); + memcpy(msg, buf, len); + BIO_free(bio); + } else { + msg = ddsrt_strdup("BIO_new failed"); + } + + return msg; +} + +DDS_Security_ValidationResult_t +validate_asymmetrical_signature_for_test( + EVP_PKEY *pkey, + void *data, + size_t dataLen, + unsigned char *signature, + size_t signatureLen, + DDS_Security_SecurityException *ex) +{ + DDS_Security_ValidationResult_t result = DDS_SECURITY_VALIDATION_OK; + EVP_MD_CTX *mdctx = NULL; + + if (!(mdctx = EVP_MD_CTX_create())) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to create verify context: %s", msg); + ddsrt_free(msg); + goto err_create_ctx; + } + + if (EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to initialize verify context: %s", msg); + ddsrt_free(msg); + goto err_verify; + } + + if (EVP_DigestVerifyUpdate(mdctx, data, dataLen) != 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to update verify context: %s", msg); + ddsrt_free(msg); + goto err_verify; + } + + if (EVP_DigestVerifyFinal(mdctx, signature, signatureLen) != 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to finalize verify context: %s", msg); + ddsrt_free(msg); + goto err_verify; + } + +err_verify: + EVP_MD_CTX_destroy(mdctx); +err_create_ctx: + return result; +} + +DDS_Security_ValidationResult_t +get_public_key( + EVP_PKEY *pkey, + unsigned char **buffer, + size_t *length, + DDS_Security_SecurityException *ex) +{ + DDS_Security_ValidationResult_t result = DDS_SECURITY_VALIDATION_OK; + BIO *bio = NULL; + char *ptr = NULL; + size_t sz; + + assert(pkey); + assert(buffer); + + *length = 0; + + bio = BIO_new(BIO_s_mem()); + + if ( bio == NULL) { + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to get public key: BIO_new_mem_buf failed"); + } else if (!PEM_write_bio_PUBKEY(bio, pkey)) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to get public key: PEM_write_bio_PUBKEY failed: %s", msg); + ddsrt_free(msg); + } else { + sz = (size_t)BIO_get_mem_data(bio, &ptr); + *buffer = ddsrt_malloc(sz +1); + memcpy(*buffer, ptr, sz); + *length = sz; + } + + if (bio) BIO_free(bio); + + return result; +} + +static EVP_PKEY * +modp_data_to_pubkey( + const unsigned char *data, + uint32_t size) +{ + EVP_PKEY *pkey= NULL; + DH *dhkey = NULL; + ASN1_INTEGER *asni; + BIGNUM *bn = NULL; + + if (!(asni = d2i_ASN1_INTEGER(NULL, &data, size))) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to decode DH public key: %s", msg); + ddsrt_free(msg); + goto fail_asni; + } + + if (!(bn = ASN1_INTEGER_to_BN(asni, NULL))) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to convert to BIGNU<: %s", msg); + ddsrt_free(msg); + goto fail_bn; + } + + if (!(dhkey = DH_get_2048_256())) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate dhkey: %s", msg); + ddsrt_free(msg); + goto fail_dhkey; + } + + dh_set_public_key(dhkey,bn); + + if (!(pkey = EVP_PKEY_new())) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate pkey: %s", msg); + ddsrt_free(msg); + goto fail_pkey; + } + + if (!EVP_PKEY_set1_DH(pkey, dhkey)) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to set public key: %s", msg); + ddsrt_free(msg); + EVP_PKEY_free(pkey); + pkey = NULL; + } + + ASN1_INTEGER_free(asni); + DH_free(dhkey); + + return pkey; + +fail_pkey: + DH_free(dhkey); +fail_dhkey: + BN_free(bn); +fail_bn: + ASN1_INTEGER_free(asni); +fail_asni: + return NULL; +} + +static EVP_PKEY * +ecdh_data_to_pubkey( + const unsigned char *data, + uint32_t size) +{ + EVP_PKEY *pkey = NULL; + EC_KEY *eckey = NULL; + EC_GROUP *group = NULL; + EC_POINT *point = NULL; + + if (!(group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1))) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate EC group: %s", msg); + ddsrt_free(msg); + } else if (!(point = EC_POINT_new(group))) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate EC point: %s", msg); + ddsrt_free(msg); + } else if (EC_POINT_oct2point(group, point, data, size, NULL) != 1) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to deserialize EC public key to EC point: %s", msg); + ddsrt_free(msg); + } else if (!(eckey = EC_KEY_new())) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate EC KEY: %s", msg); + ddsrt_free(msg); + } else if (EC_KEY_set_group(eckey, group) != 1) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to convert octet sequence to ASN1 integer: %s", msg); + ddsrt_free(msg); + } else if (EC_KEY_set_public_key(eckey, point) != 1) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to set EC public key: %s", msg); + ddsrt_free(msg); + } else if (!(pkey = EVP_PKEY_new())) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate EVP key: %s", msg); + ddsrt_free(msg); + } else if (EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to set EVP key to EC public key: %s", msg); + ddsrt_free(msg); + EVP_PKEY_free(pkey); + pkey = NULL; + } + + if (eckey) EC_KEY_free(eckey); + if (point) EC_POINT_free(point); + if (group) EC_GROUP_free(group); + + return pkey; +} + +int +check_shared_secret( + dds_security_authentication *auth, + int use_ecdh, + const DDS_Security_BinaryProperty_t *dh_remote, + EVP_PKEY *dh_local_private, + + DDS_Security_HandshakeHandle handshake_handle) + +{ +/* calculate shared secret with the other side */ + EVP_PKEY_CTX *ctx = NULL; + size_t skeylen; + EVP_PKEY *dh_remote_public = NULL; + DDS_Security_SharedSecretHandle shared_secret_local_handle; + DDS_Security_SecurityException exception; + DDS_Security_octet *shared_secret_local; + DDS_Security_octet shared_secret_remote[SHA256_DIGEST_LENGTH]; + DDS_Security_octet *secret; + int result; + + if (use_ecdh) { + dh_remote_public = ecdh_data_to_pubkey(dh_remote->value._buffer, dh_remote->value._length); + } else { + dh_remote_public = modp_data_to_pubkey(dh_remote->value._buffer, dh_remote->value._length); + } + + if (!dh_remote_public) { + CU_FAIL("Coud not decode DH public key"); + } + + ctx = EVP_PKEY_CTX_new(dh_local_private, NULL /* no engine */); + if (!ctx) + { + /* Error occurred */ + CU_FAIL("Coud not allocate CTX"); + } + + if (EVP_PKEY_derive_init(ctx) <= 0) + { + /* Error */ + CU_FAIL("Coud not init"); + } + result = EVP_PKEY_derive_set_peer(ctx, dh_remote_public) ; + if (result<= 0) + { + /* Error */ + char *msg = get_openssl_error_message_for_test(); + printf("DH remote public: %s\n",dh_remote->value._buffer); + printf("SSL Error: %s\n", msg); + ddsrt_free(msg); + CU_FAIL("Could not set peer"); + } + + /* Determine buffer length */ + result = EVP_PKEY_derive(ctx, NULL, &skeylen); + if (result <= 0) + { + /* Error */ + CU_FAIL("Could not set derive"); + } + + secret = ddsrt_malloc(skeylen+1); + + if (EVP_PKEY_derive(ctx, secret, &skeylen) <= 0) + { + /* Error */ + CU_FAIL("Could not set derive"); + } + + SHA256(secret, skeylen, shared_secret_remote); + + ddsrt_free(secret); + + /* get the secret handle */ + shared_secret_local_handle = auth->get_shared_secret( auth, handshake_handle, &exception); + + /* convert handle to object */ + shared_secret_local = ((DDS_Security_SharedSecretHandleImpl *)(shared_secret_local_handle))->shared_secret; + /*compare with remote. They should be same */ + + if (ctx) { + EVP_PKEY_CTX_free(ctx); + } + + if (dh_remote_public) { + EVP_PKEY_free(dh_remote_public); + } + + return memcmp(shared_secret_local, shared_secret_remote, SHA256_DIGEST_LENGTH); +} + + + +DDS_Security_ValidationResult_t +create_asymmetrical_signature_for_test( + EVP_PKEY *pkey, + void *data, + size_t dataLen, + unsigned char **signature, + size_t *signatureLen, + DDS_Security_SecurityException *ex) +{ + DDS_Security_ValidationResult_t result = DDS_SECURITY_VALIDATION_OK; + EVP_MD_CTX *mdctx = NULL; + EVP_PKEY_CTX *kctx = NULL; + + if (!(mdctx = EVP_MD_CTX_create())) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to create signing context: %s", msg); + ddsrt_free(msg); + goto err_create_ctx; + } + + if (EVP_DigestSignInit(mdctx, &kctx, EVP_sha256(), NULL, pkey) != 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to initialize signing context: %s", msg); + ddsrt_free(msg); + goto err_sign; + } + + if (EVP_PKEY_CTX_set_rsa_padding(kctx, RSA_PKCS1_PSS_PADDING) < 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to initialize signing context: %s", msg); + ddsrt_free(msg); + goto err_sign; + } + + if (EVP_DigestSignUpdate(mdctx, data, dataLen) != 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to update signing context: %s", msg); + ddsrt_free(msg); + goto err_sign; + } + + if (EVP_DigestSignFinal(mdctx, NULL, signatureLen) != 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to finalize signing context: %s", msg); + ddsrt_free(msg); + goto err_sign; + } + + //*signature = os_malloc(sizeof(unsigned char) * (*signatureLen)); + *signature = OPENSSL_malloc(*signatureLen); + if (EVP_DigestSignFinal(mdctx, *signature, signatureLen) != 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to finalize signing context: %s", msg); + ddsrt_free(msg); + ddsrt_free(signature); + } + + err_sign: + EVP_MD_CTX_destroy(mdctx); + err_create_ctx: + return result; +} + + diff --git a/src/security/builtin_plugins/tests/common/src/handshake_helper.h b/src/security/builtin_plugins/tests/common/src/handshake_helper.h new file mode 100644 index 0000000..b0e3df2 --- /dev/null +++ b/src/security/builtin_plugins/tests/common/src/handshake_helper.h @@ -0,0 +1,82 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef DDS_SECURITY_BUITIN_TEST_HANDSHAKE_HELPER_H +#define DDS_SECURITY_BUITIN_TEST_HANDSHAKE_HELPER_H + +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/openssl_support.h" + +const BIGNUM * +dh_get_public_key( + DH *dhkey); + +int +dh_set_public_key( + DH *dhkey, + BIGNUM *pubkey); + +DDS_Security_ValidationResult_t +create_signature_for_test( + EVP_PKEY *pkey, + const DDS_Security_BinaryProperty_t **binary_properties, + const uint32_t binary_properties_length, + unsigned char **signature, + size_t *signatureLen, + DDS_Security_SecurityException *ex); + +DDS_Security_ValidationResult_t +create_asymmetrical_signature_for_test( + EVP_PKEY *pkey, + void *data, + size_t dataLen, + unsigned char **signature, + size_t *signatureLen, + DDS_Security_SecurityException *ex); + +char * +get_openssl_error_message_for_test( + void); + +DDS_Security_ValidationResult_t +validate_asymmetrical_signature_for_test( + EVP_PKEY *pkey, + void *data, + size_t dataLen, + unsigned char *signature, + size_t signatureLen, + DDS_Security_SecurityException *ex); + +DDS_Security_ValidationResult_t +get_public_key( + EVP_PKEY *pkey, + unsigned char **buffer, + size_t *length, + DDS_Security_SecurityException *ex); + +/* for DEBUG purposes */ +void print_binary_test( char* name, unsigned char *value, uint32_t size); + +DDS_Security_BinaryProperty_t * +print_binary_properties_test( + DDS_Security_DataHolder *token); + +int +check_shared_secret( + dds_security_authentication *auth, + int use_ecdh, + const DDS_Security_BinaryProperty_t *dh_remote, + EVP_PKEY *dh_local_private, + DDS_Security_HandshakeHandle handshake_handle); + +#endif diff --git a/src/security/builtin_plugins/tests/common/src/loader.c b/src/security/builtin_plugins/tests/common/src/loader.c new file mode 100644 index 0000000..023e2c5 --- /dev/null +++ b/src/security/builtin_plugins/tests/common/src/loader.c @@ -0,0 +1,222 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#include +#include +#include "loader.h" +#include "dds/ddsrt/dynlib.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "sys/stat.h" +#include "assert.h" +#include "stdio.h" +#include "string.h" +#include "dds/security/core/dds_security_utils.h" + +struct plugin_info { + void *context; + ddsrt_dynlib_t lib_handle; + plugin_init func_init; + plugin_finalize func_fini; +}; + +struct plugins_hdl { + struct plugin_info plugin_ac; + struct plugin_info plugin_auth; + struct plugin_info plugin_crypto; +}; + +static void* +load_plugin( + struct plugin_info *info, + const char *name_lib, + const char *name_init, + const char *name_fini) +{ + dds_return_t result; + void *plugin = NULL; + assert(info); + + result = ddsrt_dlopen(name_lib, true, &info->lib_handle); + if (result == DDS_RETCODE_OK && info->lib_handle) { + + result = ddsrt_dlsym(info->lib_handle, name_init, (void **)&info->func_init); + if( result != DDS_RETCODE_OK || info->func_init == NULL) { + char buf[200]; + ddsrt_dlerror(buf, 200); + printf("ERROR: could not init %s\n. Invalid init function: %s: %s", name_lib, name_init, buf); + return plugin; + } + + result = ddsrt_dlsym(info->lib_handle, name_fini, (void **)&info->func_fini); + if( result != DDS_RETCODE_OK || info->func_fini == NULL ) { + printf("ERROR: could not init %s\n. Invalid fini function: %s", name_lib, name_fini); + return plugin; + } + + char * init_parameters = ""; + (void)info->func_init(init_parameters, &plugin, NULL); + if (plugin) { + info->context = plugin; + } else { + printf("ERROR: could not init %s\n", name_lib); + } + } else { + char buffer[300]; + ddsrt_dlerror(buffer,300); + printf("ERROR: could not load %s. %s\n", name_lib, buffer); + } + return plugin; +} + +struct plugins_hdl* +load_plugins( + dds_security_access_control **ac, + dds_security_authentication **auth, + dds_security_cryptography **crypto) +{ + struct plugins_hdl *plugins = ddsrt_malloc(sizeof(struct plugins_hdl)); + assert(plugins); + memset(plugins, 0, sizeof(struct plugins_hdl)); + if (ac) { + *ac = load_plugin(&(plugins->plugin_ac), + "dds_security_ac", + "init_access_control", + "finalize_access_control"); + if (!(*ac)) { + goto err; + } + } + if (auth) { + *auth = load_plugin(&(plugins->plugin_auth), + //"dds_security_auth", + "dds_security_auth", + "init_authentication", + "finalize_authentication"); + if (!(*auth)) { + goto err; + } + } + if (crypto) { + *crypto = load_plugin(&(plugins->plugin_crypto), + "dds_security_crypto", + "init_crypto", + "finalize_crypto"); + if (!(*crypto)) { + goto err; + } + } + return plugins; + +err: + unload_plugins(plugins); + return NULL; +} + +static void +unload_plugin( + struct plugin_info *info) +{ + dds_return_t result; + assert(info); + + if (info->lib_handle) { + if (info->func_fini && info->context) { + info->func_fini(info->context); + } + result = ddsrt_dlclose( info->lib_handle ); + if ( result != 0 ){ + printf( "Error occured while closing the library\n"); + } + } +} + +void +unload_plugins( + struct plugins_hdl *plugins) +{ + assert (plugins); + unload_plugin(&(plugins->plugin_ac)); + unload_plugin(&(plugins->plugin_auth)); + unload_plugin(&(plugins->plugin_crypto)); + ddsrt_free(plugins); +} + +static size_t +regular_file_size( + const char *filename) +{ + size_t sz = 0; + /* Provided? */ + if (filename) { + /* Accessible? */ +#if _WIN32 + struct _stat stat_info; + int ret = _stat( filename, &stat_info ); +#else + struct stat stat_info; + int ret = stat( filename, &stat_info ); +#endif + if ( ret == 0 ) { + /* Regular? */ +#ifdef WIN32 + if (stat_info.st_mode & _S_IFREG) { +#else + if (S_ISREG(stat_info.st_mode)) { +#endif + /* Yes, so get the size. */ + sz = ( size_t ) stat_info.st_size; + } + } + } + return sz; +} + +char * +load_file_contents( + const char *filename) +{ + char *document = NULL; + char *fname; + size_t sz, r; + FILE *fp; + + assert(filename); + + /* Get portable file name. */ + fname = DDS_Security_normalize_file( filename ); + if (fname) { + /* Get size if it is a accessible regular file (no dir or link). */ + sz = regular_file_size(fname); + if (sz > 0) { + /* Open the actual file. */ + DDSRT_WARNING_MSVC_OFF(4996); + fp = fopen(fname, "r"); + DDSRT_WARNING_MSVC_ON(4996); + if (fp) { + /* Read the content. */ + document = ddsrt_malloc(sz + 1); + r = fread(document, 1, sz, fp); + if (r == 0) { + ddsrt_free(document); + document = NULL; + } else { + document[r] = '\0'; + } + (void)fclose(fp); + } + } + ddsrt_free(fname); + } + + return document; +} diff --git a/src/security/builtin_plugins/tests/common/src/loader.h b/src/security/builtin_plugins/tests/common/src/loader.h new file mode 100644 index 0000000..305ac53 --- /dev/null +++ b/src/security/builtin_plugins/tests/common/src/loader.h @@ -0,0 +1,34 @@ +/* + * 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 _DBT_SECURITY_PLUGINS_LOADER_H_ +#define _DBT_SECURITY_PLUGINS_LOADER_H_ + +#include "dds/security/dds_security_api.h" + +struct plugins_hdl; + +struct plugins_hdl* +load_plugins( + dds_security_access_control **ac, + dds_security_authentication **auth, + dds_security_cryptography **crypto); + +void +unload_plugins( + struct plugins_hdl *plugins); + +char* +load_file_contents( + const char *filename); + +#endif diff --git a/src/security/builtin_plugins/tests/config_env.h.in b/src/security/builtin_plugins/tests/config_env.h.in new file mode 100644 index 0000000..c22d1f5 --- /dev/null +++ b/src/security/builtin_plugins/tests/config_env.h.in @@ -0,0 +1,18 @@ +/* + * 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 CONFIG_ENV_H +#define CONFIG_ENV_H + +#define CONFIG_ENV_TESTS_DIR "@CUnit_builtin_plugins_tests_dir@" +#define CONFIG_ENV_BUILD_DIR "@CUnit_build_dir@" + +#endif /* CONFIG_ENV_H */ diff --git a/src/security/builtin_plugins/tests/create_local_datareader_crypto_tokens/src/create_local_datareader_crypto_tokens_utests.c b/src/security/builtin_plugins/tests/create_local_datareader_crypto_tokens/src/create_local_datareader_crypto_tokens_utests.c new file mode 100644 index 0000000..014b3e2 --- /dev/null +++ b/src/security/builtin_plugins/tests/create_local_datareader_crypto_tokens/src/create_local_datareader_crypto_tokens_utests.c @@ -0,0 +1,497 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +#define CRYPTO_TRANSFORM_KIND(k) (*(uint32_t *)&((k)[0])) +#define CRYPTO_TRANSFORM_ID(k) (*(uint32_t *)&((k)[0])) + +static const char *CRYPTO_TOKEN_CLASS_ID = "DDS:Crypto:AES_GCM_GMAC"; +static const char *CRYPTO_TOKEN_PROPERTY_NAME = "dds.cryp.keymat"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_particpant_crypto = 0; +static DDS_Security_ParticipantCryptoHandle remote_particpant_crypto = 0; +static DDS_Security_DatawriterCryptoHandle local_reader_crypto = 0; +static DDS_Security_DatareaderCryptoHandle remote_writer_crypto = 0; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_endpoint_security_attributes(DDS_Security_EndpointSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + local_particpant_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_particpant_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_particpant_crypto ? 0 : -1; +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_particpant_crypto = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_particpant_crypto, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_particpant_crypto == 0) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_particpant_crypto ? 0 : -1; +} + +static int register_local_datareader(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + memset(&datareader_properties, 0, sizeof(datareader_properties)); + + prepare_endpoint_security_attributes(&datareader_security_attributes); + + local_reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_particpant_crypto, + &datareader_properties, + &datareader_security_attributes, + &exception); + + if (local_reader_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_reader_crypto ? 0 : -1; +} + +static int register_remote_datawriter(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + remote_writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_crypto, + remote_particpant_crypto, + shared_secret_handle, + &exception); + + if (remote_writer_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_writer_crypto ? 0 : -1; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void suite_create_local_datareader_crypto_tokens_init(void) +{ + allocate_shared_secret(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_local_datareader(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_datawriter(), 0); +} + +static void suite_create_local_datareader_crypto_tokens_fini(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + if (remote_writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, remote_writer_crypto, &exception); + reset_exception(&exception); + } + if (local_reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_reader_crypto, &exception); + reset_exception(&exception); + } + if (remote_particpant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_particpant_crypto, &exception); + reset_exception(&exception); + } + if (local_particpant_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_particpant_crypto, &exception); + reset_exception(&exception); + } + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static bool data_not_empty(unsigned char *data, uint32_t length) +{ + uint32_t i; + for (i = 0; i < length; i++) + { + if (data[i]) + return true; + } + return false; +} + +static bool check_key_material(DDS_Security_OctetSeq *data) +{ + bool status = true; + DDS_Security_Deserializer deserializer; + DDS_Security_KeyMaterial_AES_GCM_GMAC key_mat; + + deserializer = DDS_Security_Deserializer_new(data->_buffer, data->_length); + if (DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC(deserializer, &key_mat)) + { + if (CRYPTO_TRANSFORM_KIND(key_mat.transformation_kind) == CRYPTO_TRANSFORMATION_KIND_AES256_GCM) + { + printf("check_key_material: incorrect transformation_kind\n"); + status = false; + } + else if (CRYPTO_TRANSFORM_ID(key_mat.sender_key_id) == 0) + { + printf("check_key_material: incorrect sender_key_id\n"); + status = false; + } + else if (key_mat.master_salt._length != DDS_SECURITY_MASTER_SALT_SIZE_256) + { + printf("check_key_material: incorrect master_salt\n"); + status = false; + } + else if (!key_mat.master_salt._buffer) + { + printf("check_key_material: incorrect master_salt\n"); + status = false; + } + else if (!data_not_empty(key_mat.master_salt._buffer, key_mat.master_salt._length)) + { + printf("check_key_material: incorrect master_salt\n"); + status = false; + } + else if (key_mat.master_sender_key._length != DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256) + { + printf("check_key_material: incorrect master_sender_key\n"); + status = false; + } + else if (!key_mat.master_salt._buffer) + { + printf("check_key_material: incorrect master_sender_key\n"); + status = false; + } + else if (!data_not_empty(key_mat.master_sender_key._buffer, key_mat.master_sender_key._length)) + { + printf("check_key_material: incorrect master_sender_key\n"); + status = false; + } + } + else + { + status = false; + } + + DDS_Security_Deserializer_free(deserializer); + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&key_mat); + + return status; +} + +static bool check_token_validity(const DDS_Security_DatawriterCryptoTokenSeq *tokens) +{ + bool status = true; + uint32_t i; + + if (tokens->_length != 1 || tokens->_buffer == NULL) + { + status = false; + } + + for (i = 0; status && (i < tokens->_length); i++) + { + status = (tokens->_buffer[i].class_id != NULL) && + (strcmp(CRYPTO_TOKEN_CLASS_ID, tokens->_buffer[i].class_id) == 0) && + (tokens->_buffer[i].binary_properties._length == 1) && + (tokens->_buffer[i].binary_properties._buffer != NULL) && + (tokens->_buffer[i].binary_properties._buffer[0].name != NULL) && + (strcmp(CRYPTO_TOKEN_PROPERTY_NAME, tokens->_buffer[i].binary_properties._buffer[0].name) == 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._length > 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._buffer != NULL); + + if (status) + { + status = check_key_material(&tokens->_buffer[i].binary_properties._buffer[0].value); + } + } + + return status; +} + +CU_Test(ddssec_builtin_create_local_datareader_crypto_tokens, happy_day, .init = suite_create_local_datareader_crypto_tokens_init, .fini = suite_create_local_datareader_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_datareader_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("create_local_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + CU_ASSERT(check_token_validity(&tokens)); + + result = crypto->crypto_key_exchange->return_crypto_tokens(crypto->crypto_key_exchange, &tokens, &exception); + + if (!result) + { + printf("return_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_create_local_datareader_crypto_tokens, invalid_args, .init = suite_create_local_datareader_crypto_tokens_init, .fini = suite_create_local_datareader_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_datareader_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + /* invalid token seq = NULL */ + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + NULL, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("create_local_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + 0, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("create_local_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid remote_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_reader_crypto, + 0, + &exception); + + if (!result) + { + printf("create_local_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + 1, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("create_local_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid remote_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_reader_crypto, + 1, + &exception); + + if (!result) + { + printf("create_local_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); +} diff --git a/src/security/builtin_plugins/tests/create_local_datawriter_crypto_tokens/src/create_local_datawriter_crypto_tokens_utests.c b/src/security/builtin_plugins/tests/create_local_datawriter_crypto_tokens/src/create_local_datawriter_crypto_tokens_utests.c new file mode 100644 index 0000000..e29ab77 --- /dev/null +++ b/src/security/builtin_plugins/tests/create_local_datawriter_crypto_tokens/src/create_local_datawriter_crypto_tokens_utests.c @@ -0,0 +1,501 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +#define CRYPTO_TRANSFORM_KIND(k) (*(uint32_t *)&((k)[0])) +#define CRYPTO_TRANSFORM_ID(k) (*(uint32_t *)&((k)[0])) + +static const char *CRYPTO_TOKEN_CLASS_ID = "DDS:Crypto:AES_GCM_GMAC"; +static const char *CRYPTO_TOKEN_PROPERTY_NAME = "dds.cryp.keymat"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_particpant_crypto = 0; +static DDS_Security_ParticipantCryptoHandle remote_particpant_crypto = 0; +static DDS_Security_DatawriterCryptoHandle local_writer_crypto = 0; +static DDS_Security_DatareaderCryptoHandle remote_reader_crypto = 0; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + local_particpant_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_particpant_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_particpant_crypto ? 0 : -1; +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_particpant_crypto = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_particpant_crypto, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_particpant_crypto == 0) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_particpant_crypto ? 0 : -1; +} + +static void prepare_endpoint_security_attributes(DDS_Security_EndpointSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; +} + +static int register_local_datawriter(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + prepare_endpoint_security_attributes(&datawriter_security_attributes); + datawriter_security_attributes.is_payload_protected = true; + datawriter_security_attributes.plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + + local_writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_particpant_crypto, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + if (local_writer_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_writer_crypto ? 0 : -1; +} + +static int register_remote_datareader(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + remote_reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_crypto, + remote_particpant_crypto, + shared_secret_handle, + true, + &exception); + + if (remote_reader_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_reader_crypto ? 0 : -1; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void suite_create_local_datawriter_crypto_tokens_init(void) +{ + allocate_shared_secret(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_local_datawriter(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_datareader(), 0); +} + +static void suite_create_local_datawriter_crypto_tokens_fini(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + if (remote_reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, remote_reader_crypto, &exception); + reset_exception(&exception); + } + if (local_writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, local_writer_crypto, &exception); + reset_exception(&exception); + } + if (remote_particpant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_particpant_crypto, &exception); + reset_exception(&exception); + } + if (local_particpant_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_particpant_crypto, &exception); + reset_exception(&exception); + } + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static bool data_not_empty(unsigned char *data, uint32_t length) +{ + uint32_t i; + for (i = 0; i < length; i++) + { + if (data[i]) + return true; + } + return false; +} + +static bool check_key_material(DDS_Security_OctetSeq *data) +{ + bool status = true; + DDS_Security_Deserializer deserializer; + DDS_Security_KeyMaterial_AES_GCM_GMAC key_mat; + + deserializer = DDS_Security_Deserializer_new(data->_buffer, data->_length); + if (DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC(deserializer, &key_mat)) + { + if (CRYPTO_TRANSFORM_KIND(key_mat.transformation_kind) == CRYPTO_TRANSFORMATION_KIND_AES256_GCM) + { + printf("check_key_material: incorrect transformation_kind\n"); + status = false; + } + else if (CRYPTO_TRANSFORM_ID(key_mat.sender_key_id) == 0) + { + printf("check_key_material: incorrect sender_key_id\n"); + status = false; + } + else if (key_mat.master_salt._length != DDS_SECURITY_MASTER_SALT_SIZE_256) + { + printf("check_key_material: incorrect master_salt\n"); + status = false; + } + else if (!key_mat.master_salt._buffer) + { + printf("check_key_material: incorrect master_salt\n"); + status = false; + } + else if (!data_not_empty(key_mat.master_salt._buffer, key_mat.master_salt._length)) + { + printf("check_key_material: incorrect master_salt\n"); + status = false; + } + else if (key_mat.master_sender_key._length != DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256) + { + printf("check_key_material: incorrect master_sender_key\n"); + status = false; + } + else if (!key_mat.master_salt._buffer) + { + printf("check_key_material: incorrect master_sender_key\n"); + status = false; + } + else if (!data_not_empty(key_mat.master_sender_key._buffer, key_mat.master_sender_key._length)) + { + printf("check_key_material: incorrect master_sender_key\n"); + status = false; + } + } + else + { + status = false; + } + + DDS_Security_Deserializer_free(deserializer); + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&key_mat); + + return status; +} + +static bool check_token_validity(const DDS_Security_DatawriterCryptoTokenSeq *tokens) +{ + bool status = true; + uint32_t i; + + if (tokens->_length != 2 || tokens->_buffer == NULL) + { + status = false; + } + + for (i = 0; status && (i < tokens->_length); i++) + { + status = (tokens->_buffer[i].class_id != NULL) && + (strcmp(CRYPTO_TOKEN_CLASS_ID, tokens->_buffer[i].class_id) == 0) && + (tokens->_buffer[i].binary_properties._length == 1) && + (tokens->_buffer[i].binary_properties._buffer != NULL) && + (tokens->_buffer[i].binary_properties._buffer[0].name != NULL) && + (strcmp(CRYPTO_TOKEN_PROPERTY_NAME, tokens->_buffer[i].binary_properties._buffer[0].name) == 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._length > 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._buffer != NULL); + + if (status) + { + status = check_key_material(&tokens->_buffer[i].binary_properties._buffer[0].value); + } + } + + return status; +} + +CU_Test(ddssec_builtin_create_local_datawriter_crypto_tokens, happy_day, .init = suite_create_local_datawriter_crypto_tokens_init, .fini = suite_create_local_datawriter_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("create_local_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + CU_ASSERT(check_token_validity(&tokens)); + + result = crypto->crypto_key_exchange->return_crypto_tokens(crypto->crypto_key_exchange, &tokens, &exception); + + if (!result) + { + printf("return_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_create_local_datawriter_crypto_tokens, invalid_args, .init = suite_create_local_datawriter_crypto_tokens_init, .fini = suite_create_local_datawriter_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + /* invalid token seq = NULL */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + NULL, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("create_local_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + 0, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("create_local_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid remote_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_writer_crypto, + 0, + &exception); + + if (!result) + { + printf("create_local_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + 1, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("create_local_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid remote_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_writer_crypto, + 1, + &exception); + + if (!result) + { + printf("create_local_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); +} + diff --git a/src/security/builtin_plugins/tests/create_local_participant_crypto_tokens/src/create_local_participant_crypto_tokens_utests.c b/src/security/builtin_plugins/tests/create_local_participant_crypto_tokens/src/create_local_participant_crypto_tokens_utests.c new file mode 100644 index 0000000..f06138f --- /dev/null +++ b/src/security/builtin_plugins/tests/create_local_participant_crypto_tokens/src/create_local_participant_crypto_tokens_utests.c @@ -0,0 +1,358 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static const char *CRYPTO_TOKEN_CLASS_ID = "DDS:Crypto:AES_GCM_GMAC"; +static const char *CRYPTO_TOKEN_PROPERTY_NAME = "dds.cryp.keymat"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_ParticipantCryptoHandle local_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle = DDS_SECURITY_HANDLE_NIL; + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(DDS_Security_octet)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int register_participants(void) +{ + int r = 0; + DDS_Security_IdentityHandle participant_identity = 5; /* valid dummy value */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; /* valid but dummy value */ + DDS_Security_PermissionsHandle remote_participant_permissions = 5; /*valid dummy value */ + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + local_crypto_handle = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_crypto_handle == DDS_SECURITY_HANDLE_NIL) + { + r = -1; + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + if (r == 0) + { + remote_crypto_handle = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_crypto_handle, + participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + if (remote_crypto_handle == DDS_SECURITY_HANDLE_NIL) + { + r = -1; + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + } + + return r; +} + +static void unregister_participants(void) +{ + DDS_Security_boolean status; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + if (local_crypto_handle) + { + status = crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_crypto_handle, &exception); + if (!status) + { + printf("unregister_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + } + + if (remote_crypto_handle) + { + status = crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_crypto_handle, &exception); + if (!status) + { + printf("unregister_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + } +} + +static void suite_create_local_participant_crypto_tokens_init(void) +{ + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + allocate_shared_secret(); + CU_ASSERT_EQUAL_FATAL (register_participants(), 0); +} + +static void suite_create_local_participant_crypto_tokens_fini(void) +{ + unregister_participants(); + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static DDS_Security_boolean check_token_validity(const DDS_Security_ParticipantCryptoTokenSeq *tokens) +{ + DDS_Security_boolean status = true; + uint32_t i; + + if (tokens->_length == 0 || tokens->_buffer == NULL) + { + status = false; + } + + for (i = 0; status && (i < tokens->_length); i++) + { + status = (tokens->_buffer[i].class_id != NULL) && + (strcmp(CRYPTO_TOKEN_CLASS_ID, tokens->_buffer[i].class_id) == 0) && + (tokens->_buffer[i].binary_properties._length == 1) && + (tokens->_buffer[i].binary_properties._buffer != NULL) && + (tokens->_buffer[i].binary_properties._buffer[0].name != NULL) && + (strcmp(CRYPTO_TOKEN_PROPERTY_NAME, tokens->_buffer[i].binary_properties._buffer[0].name) == 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._length > 0) && + (tokens->_buffer[i].binary_properties._buffer[0].value._buffer != NULL); + } + + return status; +} + +CU_Test(ddssec_builtin_create_local_participant_crypto_tokens, happy_day, .init = suite_create_local_participant_crypto_tokens_init, .fini = suite_create_local_participant_crypto_tokens_fini) +{ + DDS_Security_boolean result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_ParticipantCryptoTokenSeq tokens; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_participant_crypto_tokens != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_crypto_handle, + remote_crypto_handle, + &exception); + if (!result) + { + printf("create_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + CU_ASSERT(check_token_validity(&tokens)); + + result = crypto->crypto_key_exchange->return_crypto_tokens(crypto->crypto_key_exchange, &tokens, &exception); + + if (!result) + { + printf("return_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_create_local_participant_crypto_tokens, invalid_args, .init = suite_create_local_participant_crypto_tokens_init, .fini = suite_create_local_participant_crypto_tokens_fini) +{ + DDS_Security_boolean result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_ParticipantCryptoTokenSeq tokens; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_participant_crypto_tokens != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&tokens, 0, sizeof(tokens)); + + /* invalid token seq = NULL */ + result = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + NULL, + local_crypto_handle, + remote_crypto_handle, + &exception); + if (!result) + { + printf("create_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + 0, + remote_crypto_handle, + &exception); + if (!result) + { + printf("create_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid remote_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_crypto_handle, + 0, + &exception); + if (!result) + { + printf("create_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + 1, + remote_crypto_handle, + &exception); + if (!result) + { + printf("create_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid remote_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_crypto_handle, + 1, + &exception); + if (!result) + { + printf("create_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); +} diff --git a/src/security/builtin_plugins/tests/decode_datareader_submessage/src/decode_datareader_submessage_utests.c b/src/security/builtin_plugins/tests/decode_datareader_submessage/src/decode_datareader_submessage_utests.c new file mode 100644 index 0000000..d3e1972 --- /dev/null +++ b/src/security/builtin_plugins/tests/decode_datareader_submessage/src/decode_datareader_submessage_utests.c @@ -0,0 +1,1745 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_participant_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_handle = DDS_SECURITY_HANDLE_NIL; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +struct submsg_header +{ + unsigned char id; + unsigned char flags; + uint16_t length; +}; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[4]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + unsigned char length[4]; +}; + +#if 0 +struct receiver_specific_mac +{ + DDS_Security_CryptoTransformKeyId receiver_mac_key_id; + unsigned char receiver_mac[CRYPTO_HMAC_SIZE]; +}; +#endif + +struct seq_number +{ + int high; + unsigned low; +}; + +struct heartbeat +{ + struct submsg_header smhdr; + uint32_t readerId; + uint32_t writerId; + struct seq_number firstSN; + struct seq_number lastSN; + int count; +}; + +static struct heartbeat heartbeat; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void initialize_heartbeat(void) +{ + heartbeat.smhdr.id = 0x07; + heartbeat.smhdr.flags = 1; + heartbeat.smhdr.length = sizeof(heartbeat) - sizeof(struct submsg_header); + heartbeat.readerId = 0xA1B2C3D4; + heartbeat.writerId = 0xE5F6A7B0; + heartbeat.firstSN.high = 0; + heartbeat.firstSN.low = 1; + heartbeat.lastSN.high = 20; + heartbeat.lastSN.low = 500; + heartbeat.count = 1021; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + memset(&participant_security_attributes, 0, sizeof(participant_security_attributes)); + + local_participant_handle = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_participant_handle ? 0 : -1; +} + +static void unregister_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (local_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_participant_handle, &exception); + local_participant_handle = DDS_SECURITY_HANDLE_NIL; + reset_exception(&exception); + } +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_participant_handle = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_handle, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_participant_handle ? 0 : -1; +} + +static void unregister_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (remote_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_participant_handle, &exception); + remote_participant_handle = DDS_SECURITY_HANDLE_NIL; + reset_exception(&exception); + } +} + +static void prepare_endpoint_security_attributes_and_properties(DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_PropertySeq *properties, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + bool is_origin_authenticated) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + + attributes->is_discovery_protected = true; + + if (properties != NULL) + { + memset(properties, 0, sizeof(DDS_Security_PropertySeq)); + properties->_maximum = properties->_length = 1; + properties->_buffer = ddsrt_malloc(sizeof(DDS_Security_Property_t)); + + properties->_buffer[0].name = ddsrt_strdup("dds.sec.crypto.keysize"); + + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC) + { + properties->_buffer[0].value = ddsrt_strdup("128"); + } + else + { + properties->_buffer[0].value = ddsrt_strdup("256"); + } + } + + switch (transformation_kind) + { + case CRYPTO_TRANSFORMATION_KIND_AES128_GCM: + case CRYPTO_TRANSFORMATION_KIND_AES256_GCM: + attributes->is_submessage_protected = true; + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + case CRYPTO_TRANSFORMATION_KIND_AES256_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES128_GMAC: + attributes->is_submessage_protected = true; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + default: + assert(0); + break; + } +} + +static DDS_Security_DatawriterCryptoHandle register_local_datawriter(DDS_Security_EndpointSecurityAttributes *datawriter_security_attributes, DDS_Security_PropertySeq *datawriter_properties) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_handle, + datawriter_properties, + datawriter_security_attributes, + &exception); + + if (writer_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static DDS_Security_DatawriterCryptoHandle register_remote_datawriter(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + reader_crypto, + remote_participant_handle, + shared_secret_handle, + &exception); + + if (writer_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static void unregister_datawriter(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, writer_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatareaderCryptoHandle register_local_datareader(DDS_Security_EndpointSecurityAttributes *datareader_security_attributes, DDS_Security_PropertySeq *datareader_properties) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + datareader_properties, + datareader_security_attributes, + &exception); + + if (reader_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static DDS_Security_DatareaderCryptoHandle register_remote_datareader(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + writer_crypto, + remote_participant_handle, + shared_secret_handle, + true, + &exception); + + if (reader_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static void unregister_datareader(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, reader_crypto, &exception); + reset_exception(&exception); + } +} + +static bool set_remote_datareader_tokens( + DDS_Security_DatareaderCryptoHandle nodeA_local_reader_crypto, + DDS_Security_DatawriterCryptoHandle nodeA_remote_writer_crypto, + DDS_Security_DatawriterCryptoHandle nodeB_local_writer_crypto, + DDS_Security_DatareaderCryptoHandle nodeB_remote_reader_crypto) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoTokenSeq tokens; + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + nodeA_local_reader_crypto, + nodeA_remote_writer_crypto, + &exception); + + if (result) + { + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + nodeB_local_writer_crypto, + nodeB_remote_reader_crypto, + &tokens, + &exception); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); + + if (result) + { + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + nodeB_local_writer_crypto, + nodeB_remote_reader_crypto, + &exception); + } + + if (result) + { + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + nodeA_local_reader_crypto, + nodeA_remote_writer_crypto, + &tokens, + &exception); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); + + return (bool)result; +} + +static void suite_decode_datareader_submessage_init(void) +{ + allocate_shared_secret(); + initialize_heartbeat(); + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); +} + +static void suite_decode_datareader_submessage_fini(void) +{ + unregister_local_participant(); + unregister_remote_participant(); + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void initialize_data_submessage(DDS_Security_OctetSeq *submsg) +{ + uint32_t length = sizeof(struct heartbeat); + unsigned char *buffer; + + buffer = ddsrt_malloc(length); + + memcpy(buffer, &heartbeat, length); + + submsg->_length = submsg->_maximum = length; + submsg->_buffer = buffer; +} + +static void set_submsg_header(struct submsg_header *submsg, unsigned char id, unsigned char flags, uint16_t length) +{ + submsg->id = id; + submsg->flags = flags; + submsg->length = length; +} + +static struct submsg_header * get_submsg(unsigned char *data, int num) +{ + struct submsg_header *submsg; + int i; + + submsg = (struct submsg_header *)data; + for (i = 0; i < num - 1; i++) + { + uint32_t hlen = submsg->length; + data += sizeof(struct submsg_header) + hlen; + submsg = (struct submsg_header *)data; + } + + return submsg; +} + +static struct crypto_header * get_crypto_header(unsigned char *data) +{ + return (struct crypto_header *)(data + sizeof(struct submsg_header)); +} + +static struct crypto_footer * get_crypto_footer(unsigned char *data) +{ + struct submsg_header *submsg; + submsg = get_submsg(data, 3); + return (struct crypto_footer *)(submsg + 1); +} + +static void decode_datareader_submessage_not_signed( + DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandle nodeA_local_reader_crypto; + DDS_Security_DatawriterCryptoHandle nodeB_local_writer_crypto; + DDS_Security_DatareaderCryptoHandle nodeB_remote_reader_crypto; + DDS_Security_DatawriterCryptoHandle nodeA_remote_writer_crypto; + DDS_Security_DatawriterCryptoHandleSeq writer_list; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datareader_submessage != NULL); + + initialize_data_submessage(&plain_buffer); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, transformation_kind, false); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, transformation_kind, false); + + nodeA_local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(nodeA_local_reader_crypto != 0); + + nodeB_local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(nodeB_local_writer_crypto != 0); + + nodeA_remote_writer_crypto = register_remote_datawriter(nodeA_local_reader_crypto); + CU_ASSERT_FATAL(nodeA_remote_writer_crypto != 0); + + nodeB_remote_reader_crypto = register_remote_datareader(nodeB_local_writer_crypto); + CU_ASSERT_FATAL(nodeB_remote_reader_crypto != 0); + + result = set_remote_datareader_tokens(nodeA_local_reader_crypto, nodeA_remote_writer_crypto, nodeB_local_writer_crypto, nodeB_remote_reader_crypto); + CU_ASSERT_FATAL(result); + + writer_list._length = writer_list._maximum = 1; + writer_list._buffer = DDS_Security_DatawriterCryptoHandleSeq_allocbuf(1); + writer_list._buffer[0] = nodeA_remote_writer_crypto; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + nodeA_local_reader_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Decrypt the datareader submessage */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + nodeB_local_writer_crypto, + nodeB_remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + if (exception.message) + { + printf("Decoding failed: %s\n", exception.message); + } + CU_ASSERT_FATAL(result); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + reset_exception(&exception); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + } + + unregister_datawriter(nodeA_remote_writer_crypto); + unregister_datareader(nodeB_remote_reader_crypto); + unregister_datareader(nodeA_local_reader_crypto); + unregister_datawriter(nodeB_local_writer_crypto); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&writer_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, encoded_256, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, encoded_128, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, not_encoded_256, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, not_encoded_128, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +static void decode_datareader_submessage_signed( + DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + const uint32_t LIST_SIZE = 4u; + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandleSeq local_writer_list; + DDS_Security_DatareaderCryptoHandleSeq remote_reader_list; + DDS_Security_DatawriterCryptoHandleSeq remote_writer_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + uint32_t i; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datareader_submessage != NULL); + + initialize_data_submessage(&plain_buffer); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, transformation_kind, true); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, transformation_kind, true); + + local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + local_writer_list._length = local_writer_list._maximum = LIST_SIZE; + local_writer_list._buffer = DDS_Security_DatawriterCryptoHandleSeq_allocbuf(LIST_SIZE); + + remote_reader_list._length = remote_reader_list._maximum = LIST_SIZE; + remote_reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(LIST_SIZE); + + remote_writer_list._length = remote_writer_list._maximum = LIST_SIZE; + remote_writer_list._buffer = DDS_Security_DatawriterCryptoHandleSeq_allocbuf(LIST_SIZE); + + for (i = 0; i < LIST_SIZE; i++) + { + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + + local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + result = set_remote_datareader_tokens(local_reader_crypto, remote_writer_crypto, local_writer_crypto, remote_reader_crypto); + CU_ASSERT_FATAL(result); + + local_writer_list._buffer[i] = local_writer_crypto; + remote_reader_list._buffer[i] = remote_reader_crypto; + remote_writer_list._buffer[i] = remote_writer_crypto; + } + + /* Encrypt the datareader submessage. */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_reader_crypto, + &remote_writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Decrypt the datareader submessage */ + for (i = 0; i < LIST_SIZE; i++) + { + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_writer_list._buffer[i], + remote_reader_list._buffer[i], + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + } + + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + } + + for (i = 0; i < LIST_SIZE; i++) + { + unregister_datareader(remote_reader_list._buffer[i]); + unregister_datawriter(remote_writer_list._buffer[i]); + unregister_datawriter(local_writer_list._buffer[i]); + local_writer_list._buffer[i] = 0; + remote_reader_list._buffer[i] = 0; + remote_writer_list._buffer[i] = 0; + } + unregister_datareader(local_reader_crypto); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&local_writer_list); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&remote_reader_list); + DDS_Security_DatawriterCryptoHandleSeq_deinit(&remote_writer_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, signed_256, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, signed_128, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, only_signed_256, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, only_signed_128, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + decode_datareader_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, invalid_args, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatawriterCryptoHandleSeq writer_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq empty_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datareader_submessage != NULL); + + initialize_data_submessage(&plain_buffer); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, false); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, false); + + memset(&empty_buffer, 0, sizeof(empty_buffer)); + + local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + result = set_remote_datareader_tokens(local_reader_crypto, remote_writer_crypto, local_writer_crypto, remote_reader_crypto); + CU_ASSERT_FATAL(result); + + writer_list._length = writer_list._maximum = 1; + writer_list._buffer = DDS_Security_DatawriterCryptoHandleSeq_allocbuf(1); + writer_list._buffer[0] = remote_writer_crypto; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_reader_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* decoded buffer NULL */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + NULL, + &encoded_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* encoded buffer NULL */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + NULL, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* empty encoded buffer */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &empty_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* local writer crypto 0 */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + 0, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* local writer crypto unknown */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + 1, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* remote reader crypto 0 */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_writer_crypto, + 0, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* remote reader crypto unknown */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_writer_crypto, + 1, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + unregister_datawriter(writer_list._buffer[0]); + writer_list._buffer[0] = 0; + unregister_datareader(remote_reader_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + reset_exception(&exception); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&writer_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&empty_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, invalid_data, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatawriterCryptoHandleSeq writer_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq corrupt_buffer = {0, 0, NULL}; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datareader_submessage != NULL); + + initialize_data_submessage(&plain_buffer); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + + local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + result = set_remote_datareader_tokens(local_reader_crypto, remote_writer_crypto, local_writer_crypto, remote_reader_crypto); + CU_ASSERT_FATAL(result); + + writer_list._length = writer_list._maximum = 1; + writer_list._buffer = DDS_Security_DatawriterCryptoHandleSeq_allocbuf(1); + writer_list._buffer[0] = remote_writer_crypto; + + /* Encrypt the datareader submessage. */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_reader_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Incorrect prefix id */ + { + struct submsg_header *prefix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + prefix = get_submsg(corrupt_buffer._buffer, 1); + + set_submsg_header(prefix, 0x15, prefix->flags, prefix->length); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect prefix length */ + { + struct submsg_header *prefix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + prefix = get_submsg(corrupt_buffer._buffer, 1); + + set_submsg_header(prefix, prefix->id, 0, prefix->length); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect body id */ + { + struct submsg_header *body; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer, 2); + + set_submsg_header(body, 0x15, body->flags, body->length); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect body length */ + { + struct submsg_header *body; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer, 2); + + set_submsg_header(body, body->id, body->flags, 1000); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix id */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer, 3); + + set_submsg_header(postfix, 0x15, postfix->flags, postfix->length); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix length */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer, 3); + + set_submsg_header(postfix, postfix->id, postfix->flags, 1000); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix length */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer, 3); + + set_submsg_header(postfix, postfix->id, postfix->flags, (uint16_t)(postfix->length - 20)); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect transformation kind */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer); + header->transform_identifier.transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect session id */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer); + header->session_id[0] = (unsigned char)(header->session_id[0] + 1); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect init vector suffix */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer); + header->init_vector_suffix[0] = (unsigned char)(header->init_vector_suffix[0] + 1); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect encoded data */ + { + struct submsg_header *body; + unsigned char *data; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer, 2); + data = (unsigned char *)(body + 1); + data[0] = (unsigned char)(data[0] + 1); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect common mac */ + { + struct crypto_footer *footer; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + footer->common_mac[0]++; + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer missing reader_specific mac */ + { + struct crypto_footer *footer; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + memset(footer->length, 0, 4); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect reader_specific mac id */ + { + struct crypto_footer *footer; + struct receiver_specific_mac *rmac; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + + rmac = (struct receiver_specific_mac *)(footer + 1); + rmac->receiver_mac_key_id[0] = (unsigned char)(rmac->receiver_mac_key_id[0] + 1); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect reader_specific mac */ + { + struct crypto_footer *footer; + struct receiver_specific_mac *rmac; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + + rmac = (struct receiver_specific_mac *)(footer + 1); + rmac->receiver_mac.data[0] = (unsigned char)(rmac->receiver_mac.data[0] + 1); + + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + unregister_datawriter(writer_list._buffer[0]); + writer_list._buffer[0] = 0; + unregister_datareader(remote_reader_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + reset_exception(&exception); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&writer_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datareader_submessage, volatile_sec, .init = suite_decode_datareader_submessage_init, .fini = suite_decode_datareader_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatawriterCryptoHandleSeq writer_list; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datareader_submessage != NULL); + + initialize_data_submessage(&plain_buffer); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, NULL, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, false); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, NULL, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, false); + + datareader_properties._length = datareader_properties._maximum = 1; + datareader_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datareader_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datareader_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureReader"); + datareader_properties._buffer[0].propagate = false; + + datawriter_properties._length = datawriter_properties._maximum = 1; + datawriter_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datawriter_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datawriter_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureWriter"); + datawriter_properties._buffer[0].propagate = false; + + local_writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + local_reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_crypto, + remote_participant_handle, + shared_secret_handle, + &exception); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + remote_reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_crypto, + remote_participant_handle, + shared_secret_handle, + true, + &exception); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + writer_list._length = writer_list._maximum = 1; + writer_list._buffer = DDS_Security_DatawriterCryptoHandleSeq_allocbuf(1); + writer_list._buffer[0] = remote_writer_crypto; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_reader_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Decrypt the datareader submessage */ + result = crypto->crypto_transform->decode_datareader_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (!result) + { + printf("decode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + reset_exception(&exception); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + } + + unregister_datawriter(writer_list._buffer[0]); + writer_list._buffer[0] = 0; + unregister_datareader(remote_reader_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + reset_exception(&exception); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&writer_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + + DDS_Security_PropertySeq_deinit(&datawriter_properties); + DDS_Security_PropertySeq_deinit(&datareader_properties); +} + diff --git a/src/security/builtin_plugins/tests/decode_datawriter_submessage/src/decode_datawriter_submessage_utests.c b/src/security/builtin_plugins/tests/decode_datawriter_submessage/src/decode_datawriter_submessage_utests.c new file mode 100644 index 0000000..15e1139 --- /dev/null +++ b/src/security/builtin_plugins/tests/decode_datawriter_submessage/src/decode_datawriter_submessage_utests.c @@ -0,0 +1,1770 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_participant_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_handle = DDS_SECURITY_HANDLE_NIL; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static const char *sample_test_data = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy"; + +struct submsg_header +{ + unsigned char id; + unsigned char flags; + uint16_t length; +}; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[4]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + unsigned char length[4]; +}; + +#if 0 +struct receiver_specific_mac +{ + DDS_Security_CryptoTransformKeyId receiver_mac_key_id; + unsigned char receiver_mac[CRYPTO_HMAC_SIZE]; +}; +#endif + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + memset(&participant_security_attributes, 0, sizeof(participant_security_attributes)); + + local_participant_handle = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_participant_handle ? 0 : -1; +} + +static void prepare_endpoint_security_attributes_and_properties(DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_PropertySeq *properties, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + bool is_origin_authenticated) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + + attributes->is_discovery_protected = true; + + if (properties != NULL) + { + memset(properties, 0, sizeof(DDS_Security_PropertySeq)); + properties->_maximum = properties->_length = 1; + properties->_buffer = ddsrt_malloc(sizeof(DDS_Security_Property_t)); + + properties->_buffer[0].name = ddsrt_strdup("dds.sec.crypto.keysize"); + + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC) + { + properties->_buffer[0].value = ddsrt_strdup("128"); + } + else + { + properties->_buffer[0].value = ddsrt_strdup("256"); + } + } + + switch (transformation_kind) + { + case CRYPTO_TRANSFORMATION_KIND_AES128_GCM: + case CRYPTO_TRANSFORMATION_KIND_AES256_GCM: + attributes->is_submessage_protected = true; + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + case CRYPTO_TRANSFORMATION_KIND_AES256_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES128_GMAC: + attributes->is_submessage_protected = true; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + default: + assert(0); + break; + } +} + +static void unregister_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (local_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_participant_handle, &exception); + reset_exception(&exception); + } +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_participant_handle = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_handle, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_participant_handle ? 0 : -1; +} + +static void unregister_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (remote_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_participant_handle, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatawriterCryptoHandle register_local_datawriter(DDS_Security_EndpointSecurityAttributes *attributes, DDS_Security_PropertySeq *properties) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_handle, + properties, + attributes, + &exception); + + if (writer_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static DDS_Security_DatawriterCryptoHandle register_remote_datawriter(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + reader_crypto, + remote_participant_handle, + shared_secret_handle, + &exception); + + if (writer_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static void unregister_datawriter(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, writer_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatareaderCryptoHandle register_local_datareader(DDS_Security_EndpointSecurityAttributes *attributes, DDS_Security_PropertySeq *properties) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + properties, + attributes, + &exception); + + if (reader_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static DDS_Security_DatareaderCryptoHandle register_remote_datareader(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + writer_crypto, + remote_participant_handle, + shared_secret_handle, + true, + &exception); + + if (reader_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static void unregister_datareader(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, reader_crypto, &exception); + reset_exception(&exception); + } +} + +static bool set_remote_datawriter_tokens( + DDS_Security_DatawriterCryptoHandle nodeA_local_writer_crypto, + DDS_Security_DatareaderCryptoHandle nodeA_remote_reader_crypto, + DDS_Security_DatareaderCryptoHandle nodeB_local_reader_crypto, + DDS_Security_DatawriterCryptoHandle nodeB_remote_writer_crypto) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + nodeA_local_writer_crypto, + nodeA_remote_reader_crypto, + &exception); + + if (result) + { + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + nodeB_local_reader_crypto, + nodeB_remote_writer_crypto, + &tokens, + &exception); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); + + if (result) + { + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + nodeB_local_reader_crypto, + nodeB_remote_writer_crypto, + &exception); + } + + if (result) + { + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + nodeA_local_writer_crypto, + nodeA_remote_reader_crypto, + &tokens, + &exception); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); + + return (bool)result; +} + +static void suite_decode_datawriter_submessage_init(void) +{ + allocate_shared_secret(); + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); +} + +static void suite_decode_datawriter_submessage_fini(void) +{ + unregister_local_participant(); + unregister_remote_participant(); + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void initialize_data_submessage(DDS_Security_OctetSeq *submsg, bool be) +{ + size_t length = strlen(sample_test_data) + 1; + struct submsg_header *header; + int swap; + unsigned char *buffer, *ptr; + + if (be) + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + + buffer = ddsrt_malloc(length + sizeof(struct submsg_header)); + header = (struct submsg_header *)buffer; + header->id = 0x15; + header->flags = be ? 0x00 : 0x01; + header->length = swap ? ddsrt_bswap2u((uint16_t)length) : (uint16_t)length; + ptr = (unsigned char *)(header + 1); + + memcpy((char *)ptr, sample_test_data, length); + + submsg->_length = submsg->_maximum = (uint32_t)(length + sizeof(struct submsg_header)); + submsg->_buffer = buffer; +} + +static void set_submsg_header(struct submsg_header *submsg, unsigned char id, unsigned char flags, uint16_t length) +{ + submsg->id = id; + submsg->flags = flags; + submsg->length = length; +} + +static struct submsg_header * get_submsg(unsigned char *data, int num) +{ + struct submsg_header *submsg; + int i; + + submsg = (struct submsg_header *)data; + for (i = 0; i < num - 1; i++) + { + uint32_t hlen = submsg->length; + data += sizeof(struct submsg_header) + hlen; + submsg = (struct submsg_header *)data; + } + + return submsg; +} + +static struct crypto_header * get_crypto_header(unsigned char *data) +{ + return (struct crypto_header *)(data + sizeof(struct submsg_header)); +} + +static struct crypto_footer * get_crypto_footer(unsigned char *data) +{ + struct submsg_header *submsg; + submsg = get_submsg(data, 3); + return (struct crypto_footer *)(submsg + 1); +} + +static void decode_datawriter_submessage_not_signed(DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + int32_t index; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datawriter_submessage != NULL); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, transformation_kind, false); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, transformation_kind, false); + + initialize_data_submessage(&plain_buffer, false); + + local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + result = set_remote_datawriter_tokens(local_writer_crypto, remote_reader_crypto, local_reader_crypto, remote_writer_crypto); + CU_ASSERT_FATAL(result); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_reader_crypto; + index = 0; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Decrypt the datawriter submessage */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + reset_exception(&exception); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + } + + unregister_datareader(reader_list._buffer[0]); + reader_list._buffer[0] = 0; + + unregister_datawriter(remote_writer_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, encoded_256, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, encoded_128, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, not_encoded_256, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, not_encoded_128, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +static void decode_datawriter_submessage_signed(DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + const uint32_t LIST_SIZE = 4u; + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandleSeq local_reader_list; + DDS_Security_DatawriterCryptoHandleSeq remote_writer_list; + DDS_Security_DatareaderCryptoHandleSeq remote_reader_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq *buffer; + int32_t index; + uint32_t i; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datawriter_submessage != NULL); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, transformation_kind, true); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, transformation_kind, true); + + initialize_data_submessage(&plain_buffer, false); + + local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + local_reader_list._length = local_reader_list._maximum = LIST_SIZE; + local_reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(LIST_SIZE); + + remote_writer_list._length = remote_writer_list._maximum = LIST_SIZE; + remote_writer_list._buffer = DDS_Security_DatawriterCryptoHandleSeq_allocbuf(LIST_SIZE); + + remote_reader_list._length = remote_reader_list._maximum = LIST_SIZE; + remote_reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(LIST_SIZE); + + for (i = 0; i < LIST_SIZE; i++) + { + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + + local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + result = set_remote_datawriter_tokens(local_writer_crypto, remote_reader_crypto, local_reader_crypto, remote_writer_crypto); + CU_ASSERT_FATAL(result); + + local_reader_list._buffer[i] = local_reader_crypto; + remote_writer_list._buffer[i] = remote_writer_crypto; + remote_reader_list._buffer[i] = remote_reader_crypto; + } + + index = 0; + + /* Encrypt the datawriter submessage. */ + buffer = &plain_buffer; + while ((uint32_t)index != LIST_SIZE) + { + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + buffer, + local_writer_crypto, + &remote_reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + buffer = NULL; + } + + /* Decrypt the datawriter submessage */ + + for (i = 0; i < LIST_SIZE; i++) + { + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_reader_list._buffer[i], + remote_writer_list._buffer[i], + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + } + + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + } + + for (i = 0; i < LIST_SIZE; i++) + { + unregister_datareader(remote_reader_list._buffer[i]); + unregister_datawriter(remote_writer_list._buffer[i]); + unregister_datareader(local_reader_list._buffer[i]); + local_reader_list._buffer[i] = 0; + remote_reader_list._buffer[i] = 0; + remote_writer_list._buffer[i] = 0; + } + unregister_datawriter(local_writer_crypto); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&local_reader_list); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&remote_reader_list); + DDS_Security_DatawriterCryptoHandleSeq_deinit(&remote_writer_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, signed_256, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, signed_128, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, only_signed_256, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, only_signed_128, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + decode_datawriter_submessage_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, invalid_args, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq empty_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + int32_t index; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datawriter_submessage != NULL); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + + initialize_data_submessage(&plain_buffer, false); + + memset(&empty_buffer, 0, sizeof(empty_buffer)); + + local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + result = set_remote_datawriter_tokens(local_writer_crypto, remote_reader_crypto, local_reader_crypto, remote_writer_crypto); + CU_ASSERT_FATAL(result); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_reader_crypto; + index = 0; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + +#if 0 + /* */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); +#endif + + /* decoded buffer NULL */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + NULL, + &encoded_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* encoded buffer NULL */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + NULL, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* empty encoded buffer */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &empty_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* local reader crypto 0 */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + 0, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* local reader crypto unknown */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + 1, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* remote writer crypto 0 */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_reader_crypto, + 0, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* remote writer crypto unknown */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_reader_crypto, + 1, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + unregister_datareader(reader_list._buffer[0]); + reader_list._buffer[0] = 0; + unregister_datawriter(remote_writer_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + reset_exception(&exception); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&empty_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, invalid_data, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq corrupt_buffer = {0, 0, NULL}; + int32_t index; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datawriter_submessage != NULL); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + + initialize_data_submessage(&plain_buffer, false); + + local_writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + local_reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + result = set_remote_datawriter_tokens(local_writer_crypto, remote_reader_crypto, local_reader_crypto, remote_writer_crypto); + CU_ASSERT_FATAL(result); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_reader_crypto; + index = 0; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Incorrect prefix id */ + { + struct submsg_header *prefix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + prefix = get_submsg(corrupt_buffer._buffer, 1); + + set_submsg_header(prefix, 0x15, prefix->flags, prefix->length); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect prefix length */ + { + struct submsg_header *prefix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + prefix = get_submsg(corrupt_buffer._buffer, 1); + + set_submsg_header(prefix, prefix->id, 0, prefix->length); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect body id */ + { + struct submsg_header *body; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer, 2); + + set_submsg_header(body, 0x15, body->flags, body->length); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect body length */ + { + struct submsg_header *body; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer, 2); + + set_submsg_header(body, body->id, body->flags, 1000); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix id */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer, 3); + + set_submsg_header(postfix, 0x15, postfix->flags, postfix->length); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix length */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer, 3); + + set_submsg_header(postfix, postfix->id, postfix->flags, 1000); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix length */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer, 3); + + set_submsg_header(postfix, postfix->id, postfix->flags, (uint16_t)(postfix->length - 20)); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect transformation kind */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer); + header->transform_identifier.transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect session id */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer); + header->session_id[0] = (unsigned char)(header->session_id[0] + 1); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect init vector suffix */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer); + header->init_vector_suffix[0] = (unsigned char)(header->init_vector_suffix[0] + 1); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect encoded data */ + { + struct submsg_header *body; + unsigned char *data; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer, 2); + data = (unsigned char *)(body + 1); + data[0] = (unsigned char)(data[0] + 1); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect common mac */ + { + struct crypto_footer *footer; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + footer->common_mac[0] = (unsigned char)(footer->common_mac[0] + 1); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer missing reader_specific mac */ + { + struct crypto_footer *footer; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + memset(footer->length, 0, 4); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect reader_specific mac id */ + { + struct crypto_footer *footer; + struct receiver_specific_mac *rmac; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + + rmac = (struct receiver_specific_mac *)(footer + 1); + rmac->receiver_mac_key_id[0] = (unsigned char)(rmac->receiver_mac_key_id[0] + 1); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect reader_specific mac */ + { + struct crypto_footer *footer; + struct receiver_specific_mac *rmac; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + + rmac = (struct receiver_specific_mac *)(footer + 1); + rmac->receiver_mac.data[0] = (unsigned char)(rmac->receiver_mac.data[0] + 1); + + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + unregister_datareader(reader_list._buffer[0]); + reader_list._buffer[0] = 0; + unregister_datawriter(remote_writer_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + reset_exception(&exception); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_decode_datawriter_submessage, volatile_sec, .init = suite_decode_datawriter_submessage_init, .fini = suite_decode_datawriter_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + int32_t index; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datareader_properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_datawriter_submessage != NULL); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, NULL, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, false); + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, NULL, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, false); + + initialize_data_submessage(&plain_buffer, false); + + datareader_properties._length = datareader_properties._maximum = 1; + datareader_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datareader_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datareader_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureReader"); + datareader_properties._buffer[0].propagate = false; + + datawriter_properties._length = datawriter_properties._maximum = 1; + datawriter_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datawriter_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datawriter_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureWriter"); + datawriter_properties._buffer[0].propagate = false; + + local_writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + local_reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_crypto, + remote_participant_handle, + shared_secret_handle, + &exception); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + remote_reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_crypto, + remote_participant_handle, + shared_secret_handle, + true, + &exception); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_reader_crypto; + index = 0; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Decrypt the datawriter submessage */ + result = crypto->crypto_transform->decode_datawriter_submessage( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + reset_exception(&exception); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + } + + unregister_datareader(reader_list._buffer[0]); + reader_list._buffer[0] = 0; + unregister_datawriter(remote_writer_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + reset_exception(&exception); + + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + + DDS_Security_OctetSeq_deinit(&plain_buffer); + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + + DDS_Security_PropertySeq_deinit(&datawriter_properties); + DDS_Security_PropertySeq_deinit(&datareader_properties); +} + diff --git a/src/security/builtin_plugins/tests/decode_rtps_message/src/decode_rtps_message_utests.c b/src/security/builtin_plugins/tests/decode_rtps_message/src/decode_rtps_message_utests.c new file mode 100644 index 0000000..778701b --- /dev/null +++ b/src/security/builtin_plugins/tests/decode_rtps_message/src/decode_rtps_message_utests.c @@ -0,0 +1,1491 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participantA_identity = 1; +static DDS_Security_IdentityHandle local_participantB_identity = 2; +static DDS_Security_IdentityHandle remote_identities[] = {2, 3, 4, 5}; + +static DDS_Security_ParticipantCryptoHandle local_participantA_crypto = 0; +static DDS_Security_ParticipantCryptoHandle local_participantB_crypto = 0; +static DDS_Security_ParticipantCryptoHandle remote_particpantA_crypto; +static DDS_Security_ParticipantCryptoHandle remote_cryptos[4]; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static const char *sample_test_data = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy"; + +static const char *RTPS_HEADER = "RTPS abcdefghijklmno"; + +struct submsg_header +{ + unsigned char id; + unsigned char flags; + uint16_t length; +}; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[4]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + unsigned char length[4]; +}; + +#if 0 +struct receiver_specific_mac +{ + DDS_Security_CryptoTransformKeyId receiver_mac_key_id; + unsigned char receiver_mac[CRYPTO_HMAC_SIZE]; +}; +#endif + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void print_octets(const char *msg, const unsigned char *data, uint32_t sz) +{ + uint32_t i; + printf("%s: ", msg); + for (i = 0; i < sz; i++) + { + printf("%02x", data[i]); + } + printf("\n"); +} + +static void prepare_participant_security_attributes_and_properties(DDS_Security_ParticipantSecurityAttributes *attributes, + DDS_Security_PropertySeq *properties, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + bool is_origin_authenticated) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + + attributes->is_discovery_protected = true; + + if (properties != NULL) + { + memset(properties, 0, sizeof(DDS_Security_PropertySeq)); + properties->_maximum = properties->_length = 1; + properties->_buffer = ddsrt_malloc(sizeof(DDS_Security_Property_t)); + + properties->_buffer[0].name = ddsrt_strdup("dds.sec.crypto.keysize"); + + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC) + { + properties->_buffer[0].value = ddsrt_strdup("128"); + } + else + { + properties->_buffer[0].value = ddsrt_strdup("256"); + } + } + + switch (transformation_kind) + { + case CRYPTO_TRANSFORMATION_KIND_AES128_GCM: + case CRYPTO_TRANSFORMATION_KIND_AES256_GCM: + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; + if (is_origin_authenticated) + { + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED; + } + break; + + case CRYPTO_TRANSFORMATION_KIND_AES256_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES128_GMAC: + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->is_rtps_protected = true; + if (is_origin_authenticated) + { + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED; + } + break; + + default: + assert(0); + break; + } +} + +static int register_local_participants(DDS_Security_ParticipantSecurityAttributes *participant_security_attributes, DDS_Security_PropertySeq *participant_properties) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + + local_participantA_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participantA_identity, + participant_permissions, + participant_properties, + participant_security_attributes, + &exception); + + if (local_participantA_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + local_participantB_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participantB_identity, + participant_permissions, + participant_properties, + participant_security_attributes, + &exception); + + if (local_participantA_crypto == 0 || local_participantB_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_participantA_crypto && local_participantB_crypto ? 0 : -1; +} + +static void unregister_local_participants(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (local_participantA_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_participantA_crypto, &exception); + reset_exception(&exception); + } + if (local_participantB_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_participantB_crypto, &exception); + reset_exception(&exception); + } +} + +static int register_remote_participants(DDS_Security_ParticipantCryptoHandle local_id, + DDS_Security_IdentityHandle remote_ids[4], + DDS_Security_ParticipantCryptoHandle participant_cryptos[4]) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + unsigned i; + int result = 0; + + for (i = 0; i < 4; ++i) + { + participant_cryptos[i] = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_id, + remote_ids[i], + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (participant_cryptos[i] == 0) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + result = 1; + break; + } + } + + return result; +} + +static void unregister_remote_participants(void) +{ + unsigned i; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + for (i = 0; i < 4; ++i) + { + if (remote_cryptos[i]) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_cryptos[i], &exception); + reset_exception(&exception); + } + } +} + +static int register_remote_participant_for_participantB( + DDS_Security_ParticipantCryptoHandle local_id, + DDS_Security_IdentityHandle remote_identity, + DDS_Security_ParticipantCryptoHandle *remote_participant_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + int result = 0; + + *remote_participant_crypto = crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, local_id, remote_identity, + remote_participant_permissions, shared_secret_handle, &exception); + + if (*remote_participant_crypto == 0) + { + printf("register_matched_remote_participant: %s\n", + exception.message ? exception.message : "Error message missing"); + result = 1; + } + + return result; +} + +static void unregister_remote_participant_of_participantB(DDS_Security_ParticipantCryptoHandle remote_participant_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (remote_participant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_participant_crypto, &exception); + reset_exception(&exception); + } +} + +static void set_protection_kind(DDS_Security_ParticipantCryptoHandle participant_crypto, DDS_Security_ProtectionKind protection_kind) +{ + local_participant_crypto *paricipant_crypto_impl = (local_participant_crypto *)participant_crypto; + + paricipant_crypto_impl->rtps_protection_kind = protection_kind; +} + +static bool set_remote_participant_tokens( + DDS_Security_ParticipantCryptoHandle local_participantA_crypto_handle, + DDS_Security_ParticipantCryptoHandle remote_participantB_crypto_handle, + DDS_Security_ParticipantCryptoHandle local_participantB_crypto_handle, + DDS_Security_ParticipantCryptoHandle remote_participantA_crypto_handle) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + + result = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_participantA_crypto_handle, + remote_participantB_crypto_handle, + &exception); + + if (result) + { + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_participantB_crypto_handle, + remote_participantA_crypto_handle, + &tokens, + &exception); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); + + return (bool)result; +} + +static session_key_material * get_local_participant_session(DDS_Security_ParticipantCryptoHandle participant_crypto) +{ + local_participant_crypto *participant_crypto_impl = (local_participant_crypto *)participant_crypto; + return participant_crypto_impl->session; +} + +static void suite_decode_rtps_message_init(void) +{ + allocate_shared_secret(); + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); +} + +static void suite_decode_rtps_message_fini(void) +{ + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void initialize_rtps_message(DDS_Security_OctetSeq *submsg, bool be) +{ + size_t length = strlen(sample_test_data) + 1; + struct submsg_header *header; + int swap; + unsigned char *buffer, *ptr; + + if (be) + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + + buffer = ddsrt_malloc(length + 20 + sizeof(struct submsg_header)); + memcpy(buffer, RTPS_HEADER, 20); + + header = (struct submsg_header *)(buffer + 20); + header->id = 0x15; + header->flags = be ? 0x00 : 0x01; + header->length = swap ? ddsrt_bswap2u((uint16_t)length) : (uint16_t)length; + + ptr = (unsigned char *)(header + 1); + memcpy((char *)ptr, sample_test_data, length); + + submsg->_length = submsg->_maximum = (uint32_t)(20 + length + sizeof(struct submsg_header)); + submsg->_buffer = buffer; +} + +static void set_submsg_header(struct submsg_header *submsg, unsigned char id, unsigned char flags, uint16_t length) +{ + submsg->id = id; + submsg->flags = flags; + submsg->length = length; +} + +static struct submsg_header * get_submsg(unsigned char *data, int num) +{ + struct submsg_header *submsg; + int i; + + submsg = (struct submsg_header *)data; + for (i = 0; i < num - 1; i++) + { + uint32_t hlen = submsg->length; + data += sizeof(struct submsg_header) + hlen; + submsg = (struct submsg_header *)data; + } + + return submsg; +} + +static struct crypto_header * get_crypto_header(unsigned char *data) +{ + return (struct crypto_header *)(data + sizeof(struct submsg_header)); +} + +static struct crypto_footer * get_crypto_footer(unsigned char *data) +{ + struct submsg_header *submsg; + submsg = get_submsg(data + 20, 3); + return (struct crypto_footer *)(submsg + 1); +} + +static void decode_rtps_message_not_authenticated(DDS_Security_CryptoTransformKind_Enum transformation_kind, uint32_t key_size) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + session_key_material *session_keys; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + int32_t index; + DDS_Security_ParticipantSecurityAttributes attributes; + DDS_Security_PropertySeq properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_rtps_message != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_rtps_message != NULL); + + prepare_participant_security_attributes_and_properties(&attributes, &properties, transformation_kind, true); + register_local_participants(&attributes, &properties); + + initialize_rtps_message(&plain_buffer, false); + + session_keys = get_local_participant_session(local_participantA_crypto); + session_keys->master_key_material->transformation_kind = transformation_kind; + session_keys->key_size = key_size; + + register_remote_participants(local_participantA_crypto, remote_identities, remote_cryptos); + + /* Now remote participant cypto is in remote_cryptos[0] */ + + register_remote_participant_for_participantB(local_participantB_crypto, local_participantA_identity, &remote_particpantA_crypto); + + result = set_remote_participant_tokens(local_participantA_crypto, remote_cryptos[0], local_participantB_crypto, remote_particpantA_crypto); + CU_ASSERT_FATAL(result); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_ParticipantCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_cryptos[0]; + index = 0; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_participantA_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Decrypt the datawriter submessage */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + reset_exception(&exception); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + print_octets("decoded_buffer", decoded_buffer._buffer, plain_buffer._length); + print_octets("plain_buffer", plain_buffer._buffer, plain_buffer._length); + } + + unregister_remote_participant_of_participantB(remote_particpantA_crypto); + unregister_remote_participants(); + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + DDS_Security_PropertySeq_deinit(&properties); + + unregister_local_participants(); +} + +CU_Test(ddssec_builtin_decode_rtps_message, encoded_256, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES256_GCM, 256); +} + +CU_Test(ddssec_builtin_decode_rtps_message, encoded_128, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES128_GCM, 128); +} + +CU_Test(ddssec_builtin_decode_rtps_message, not_encrypted_256, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, 256); +} + +CU_Test(ddssec_builtin_decode_rtps_message, not_encrypted_128, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC, 128); +} + +static void decode_rtps_message_authenticated(DDS_Security_CryptoTransformKind_Enum transformation_kind, uint32_t key_size, DDS_Security_ProtectionKind protection_kind) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_ParticipantCryptoHandleSeq remote_reader_list; + session_key_material *session_keys; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq *buffer; + DDS_Security_ParticipantSecurityAttributes attributes; + DDS_Security_PropertySeq properties; + int i, index; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_rtps_message != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_rtps_message != NULL); + + prepare_participant_security_attributes_and_properties(&attributes, &properties, transformation_kind, true); + register_local_participants(&attributes, &properties); + + initialize_rtps_message(&plain_buffer, false); + + session_keys = get_local_participant_session(local_participantA_crypto); + session_keys->master_key_material->transformation_kind = transformation_kind; + session_keys->key_size = key_size; + + set_protection_kind(local_participantA_crypto, protection_kind); + + register_remote_participants(local_participantA_crypto, remote_identities, remote_cryptos); + + set_protection_kind(local_participantB_crypto, protection_kind); + + register_remote_participant_for_participantB(local_participantB_crypto, local_participantA_identity, &remote_particpantA_crypto); + + result = set_remote_participant_tokens(local_participantA_crypto, remote_cryptos[0], local_participantB_crypto, remote_particpantA_crypto); + CU_ASSERT_FATAL(result); + + remote_reader_list._length = remote_reader_list._maximum = 4; + remote_reader_list._buffer = DDS_Security_ParticipantCryptoHandleSeq_allocbuf(4); + + for (i = 0; i < 4; i++) + { + remote_reader_list._buffer[i] = remote_cryptos[i]; + } + + index = 0; + + /* Encrypt the datawriter submessage. */ + buffer = &plain_buffer; + while (index != 4) + { + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + buffer, + local_participantA_crypto, + &remote_reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + buffer = NULL; + } + + /* Decrypt the datawriter submessage */ + + for (i = 0; i < 4; i++) + { + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT_FATAL(decoded_buffer._length == plain_buffer._length); + + if (memcmp(decoded_buffer._buffer, plain_buffer._buffer, plain_buffer._length) != 0) + { + CU_FAIL("decode submessage is not equal to original"); + print_octets("decoded_buffer", decoded_buffer._buffer, plain_buffer._length); + print_octets("plain_buffer", plain_buffer._buffer, plain_buffer._length); + } + + reset_exception(&exception); + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + } + + unregister_remote_participant_of_participantB(remote_particpantA_crypto); + unregister_remote_participants(); + reset_exception(&exception); + + DDS_Security_PropertySeq_deinit(&properties); + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&remote_reader_list); +} + +CU_Test(ddssec_builtin_decode_rtps_message, authenticated_256, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_authenticated(CRYPTO_TRANSFORMATION_KIND_AES256_GCM, 256, DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION); +} + +CU_Test(ddssec_builtin_decode_rtps_message, authenticated_128, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_authenticated(CRYPTO_TRANSFORMATION_KIND_AES128_GCM, 128, DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION); +} + +CU_Test(ddssec_builtin_decode_rtps_message, only_authenticated_256, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_authenticated(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, 256, DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION); +} + +CU_Test(ddssec_builtin_decode_rtps_message, only_authenticated_128, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + decode_rtps_message_authenticated(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC, 128, DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION); +} + +CU_Test(ddssec_builtin_decode_rtps_message, invalid_args, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq empty_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + int32_t index; + DDS_Security_ParticipantSecurityAttributes attributes; + DDS_Security_PropertySeq properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_rtps_message != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_rtps_message != NULL); + + prepare_participant_security_attributes_and_properties(&attributes, &properties, CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, false); + register_local_participants(&attributes, &properties); + + initialize_rtps_message(&plain_buffer, false); + + register_remote_participants(local_participantA_crypto, remote_identities, remote_cryptos); + + /* Now remote participant cypto is in remote_cryptos[0] */ + + register_remote_participant_for_participantB(local_participantB_crypto, local_participantA_identity, &remote_particpantA_crypto); + + result = set_remote_participant_tokens(local_participantA_crypto, remote_cryptos[0], local_participantB_crypto, remote_particpantA_crypto); + CU_ASSERT_FATAL(result); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_ParticipantCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_cryptos[0]; + index = 0; + + /* Encrypt */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_participantA_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* decoded buffer NULL */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + NULL, + &encoded_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* encoded buffer NULL */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + NULL, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* empty encoded buffer */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &empty_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* local reader crypto 0 */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + 0, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* local reader crypto unknown */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + 1, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* remote writer crypto 0 */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_participantB_crypto, + 0, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* remote writer crypto unknown */ + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + local_participantB_crypto, + 1, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + unregister_remote_participant_of_participantB(remote_particpantA_crypto); + unregister_remote_participants(); + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + DDS_Security_PropertySeq_deinit(&properties); + unregister_local_participants(); +} + +CU_Test(ddssec_builtin_decode_rtps_message, invalid_data, .init = suite_decode_rtps_message_init, .fini = suite_decode_rtps_message_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + DDS_Security_OctetSeq plain_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq corrupt_buffer = {0, 0, NULL}; + session_key_material *session_keys; + int32_t index; + DDS_Security_ParticipantSecurityAttributes attributes; + DDS_Security_PropertySeq properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_rtps_message != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_rtps_message != NULL); + + prepare_participant_security_attributes_and_properties(&attributes, &properties, CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, false); + register_local_participants(&attributes, &properties); + initialize_rtps_message(&plain_buffer, false); + + session_keys = get_local_participant_session(local_participantA_crypto); + session_keys->master_key_material->transformation_kind = CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + session_keys->key_size = 256; + + set_protection_kind(local_participantA_crypto, DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION); + + register_remote_participants(local_participantA_crypto, remote_identities, remote_cryptos); + + set_protection_kind(local_participantB_crypto, DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION); + + register_remote_participant_for_participantB(local_participantB_crypto, local_participantA_identity, &remote_particpantA_crypto); + + result = set_remote_participant_tokens(local_participantA_crypto, remote_cryptos[0], local_participantB_crypto, remote_particpantA_crypto); + CU_ASSERT_FATAL(result); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_ParticipantCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_cryptos[0]; + index = 0; + + /* Encrypt the datawriter submessage. */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_participantA_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Incorrect prefix id */ + { + struct submsg_header *prefix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + prefix = get_submsg(corrupt_buffer._buffer + 20, 1); + + set_submsg_header(prefix, 0x15, prefix->flags, prefix->length); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect prefix length */ + { + struct submsg_header *prefix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + prefix = get_submsg(corrupt_buffer._buffer + 20, 1); + + set_submsg_header(prefix, prefix->id, 0, prefix->length); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect body id */ + { + struct submsg_header *body; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer + 20, 2); + + set_submsg_header(body, 0x15, body->flags, body->length); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect body length */ + { + struct submsg_header *body; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer + 20, 2); + + set_submsg_header(body, body->id, body->flags, 1000); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix id */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer + 20, 3); + + set_submsg_header(postfix, 0x15, postfix->flags, postfix->length); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix length */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer + 20, 3); + + set_submsg_header(postfix, postfix->id, postfix->flags, 1000); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* Incorrect postfix length */ + { + struct submsg_header *postfix; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + postfix = get_submsg(corrupt_buffer._buffer + 20, 3); + + set_submsg_header(postfix, postfix->id, postfix->flags, (uint16_t)(postfix->length - 20)); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect transformation kind */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer + 20); + header->transform_identifier.transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect session id */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer + 20); + header->session_id[0] = (unsigned char)(header->session_id[0] + 1); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect init vector suffix */ + { + struct crypto_header *header; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + header = get_crypto_header(corrupt_buffer._buffer + 20); + header->init_vector_suffix[0] = (unsigned char)(header->init_vector_suffix[0] + 1); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* incorrect encoded data */ + { + struct submsg_header *body; + unsigned char *data; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + body = get_submsg(corrupt_buffer._buffer + 20, 2); + data = (unsigned char *)(body + 1); + data[0] = (unsigned char)(data[0] + 1); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect common mac */ + { + struct crypto_footer *footer; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + footer->common_mac[0] = (unsigned char)(footer->common_mac[0] + 1); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer missing reader_specific mac */ + { + struct crypto_footer *footer; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + memset(footer->length, 0, 4); + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) + { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + +#if 0 + /* footer incorrect reader_specific mac id */ + { + struct crypto_footer *footer; + struct receiver_specific_mac *rmac; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + + rmac = (struct receiver_specific_mac *)(footer + 1); + rmac->receiver_mac_key_id[0] += 1; + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } + + /* footer incorrect reader_specific mac */ + { + struct crypto_footer *footer; + struct receiver_specific_mac *rmac; + uint32_t len; + + memset(&corrupt_buffer, 0, sizeof(corrupt_buffer)); + DDS_Security_OctetSeq_copy(&corrupt_buffer, &encoded_buffer); + + footer = get_crypto_footer(corrupt_buffer._buffer); + len = ddsrt_bswap4u(*(uint32_t *)footer->length); + CU_ASSERT(len == 1); + + rmac = (struct receiver_specific_mac *)(footer + 1); + rmac->receiver_mac[0] += 1; + + result = crypto->crypto_transform->decode_rtps_message( + crypto->crypto_transform, + &decoded_buffer, + &corrupt_buffer, + local_participantB_crypto, + remote_particpantA_crypto, + &exception); + + if (!result) { + printf("decode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit(&corrupt_buffer); + } +#endif + + unregister_remote_participant_of_participantB(remote_particpantA_crypto); + unregister_remote_participants(); + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + DDS_Security_PropertySeq_deinit(&properties); + unregister_local_participants(); +} + diff --git a/src/security/builtin_plugins/tests/decode_serialized_payload/src/decode_serialized_payload_utests.c b/src/security/builtin_plugins/tests/decode_serialized_payload/src/decode_serialized_payload_utests.c new file mode 100644 index 0000000..85a3c2d --- /dev/null +++ b/src/security/builtin_plugins/tests/decode_serialized_payload/src/decode_serialized_payload_utests.c @@ -0,0 +1,1121 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_participant_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_handle = DDS_SECURITY_HANDLE_NIL; + +static DDS_Security_SharedSecretHandle shared_secret_handle = DDS_SECURITY_HANDLE_NIL; + +static const char *sample_test_data = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy"; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[4]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + unsigned char length[4]; +}; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = (DDS_Security_SharedSecretHandleImpl *)shared_secret_handle; + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + local_participant_handle = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_participant_handle ? 0 : -1; +} + +static void unregister_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (local_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_participant_handle, &exception); + reset_exception(&exception); + } +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_participant_handle = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_handle, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_participant_handle ? 0 : -1; +} + +static void unregister_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (remote_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_participant_handle, &exception); + reset_exception(&exception); + } +} + +static void prepare_endpoint_security_attributes(DDS_Security_EndpointSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; +} + +static DDS_Security_DatawriterCryptoHandle register_local_datawriter(bool encrypted) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + prepare_endpoint_security_attributes(&datawriter_security_attributes); + + datawriter_security_attributes.is_payload_protected = true; + if (encrypted) + { + datawriter_security_attributes.plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + } + + writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + if (writer_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + assert (writer_crypto != 0); + return writer_crypto; +} + +static DDS_Security_DatawriterCryptoHandle register_remote_datawriter(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + reader_crypto, + remote_participant_handle, + shared_secret_handle, + &exception); + + if (writer_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + assert (writer_crypto != 0); + return writer_crypto; +} + +static void unregister_datawriter(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, writer_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatareaderCryptoHandle register_local_datareader(bool encrypted) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + memset(&datareader_properties, 0, sizeof(datareader_properties)); + memset(&datareader_security_attributes, 0, sizeof(datareader_security_attributes)); + datareader_security_attributes.is_payload_protected = true; + if (encrypted) + { + datareader_security_attributes.plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + } + + reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + + if (reader_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static DDS_Security_DatareaderCryptoHandle register_remote_datareader(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + writer_crypto, + remote_participant_handle, + shared_secret_handle, + true, + &exception); + + if (reader_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static void unregister_datareader(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, reader_crypto, &exception); + reset_exception(&exception); + } +} + +static bool +set_remote_datawriter_tokens( + DDS_Security_DatawriterCryptoHandle local_writer_crypto, + DDS_Security_DatareaderCryptoHandle remote_reader_crypto, + DDS_Security_DatareaderCryptoHandle local_reader_crypto, + DDS_Security_DatawriterCryptoHandle remote_writer_crypto) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (result) + { + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + (void)crypto->crypto_key_exchange->return_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + &exception); + } + + return (bool)result; +} + +static session_key_material * get_datawriter_session(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + local_datawriter_crypto *writer_crypto_impl = (local_datawriter_crypto *)writer_crypto; + + return writer_crypto_impl->writer_session_message; +} + +static bool check_writer_protection_kind(DDS_Security_DatawriterCryptoHandle writer_crypto, DDS_Security_BasicProtectionKind protection_kind) +{ + local_datawriter_crypto *writer_crypto_impl = (local_datawriter_crypto *)writer_crypto; + return (writer_crypto_impl->data_protectionKind == protection_kind); +} + +static uint32_t get_transformation_kind(uint32_t key_size, bool encoded) +{ + uint32_t kind = CRYPTO_TRANSFORMATION_KIND_INVALID; + if (key_size == 128) + { + kind = encoded ? CRYPTO_TRANSFORMATION_KIND_AES128_GCM : CRYPTO_TRANSFORMATION_KIND_AES128_GMAC; + } + else if (key_size == 256) + { + kind = encoded ? CRYPTO_TRANSFORMATION_KIND_AES256_GCM : CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; + } + CU_ASSERT_FATAL(kind != CRYPTO_TRANSFORMATION_KIND_INVALID); + return kind; +} + +static void suite_decode_serialized_payload_init(void) +{ + allocate_shared_secret(); + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); +} + +static void suite_decode_serialized_payload_fini(void) +{ + unregister_remote_participant(); + unregister_local_participant(); + unload_plugins(plugins); + deallocate_shared_secret(); +} + +static bool split_encoded_data(unsigned char *data, size_t size, struct crypto_header **header, unsigned char **contents, uint32_t *length, struct crypto_footer **footer) +{ + unsigned char *ptr; + + if (size < sizeof(struct crypto_header) + 4) + return false; + + *header = (struct crypto_header *)data; + ptr = data + sizeof(struct crypto_header); + *length = ddsrt_fromBE4u(*(uint32_t *)ptr); + + size -= sizeof(struct crypto_header) + 4; + + /* remain should contain the ecrypted data + the footer (common_mac (16) + length (4)) */ + if (size < (*length) + 20) + return false; + + ptr += 4; + *contents = ptr; + ptr += *length; + + /* The length is the length of the encrypted data and the common_mac of the footer + * For the serialized payload the footer consists of the common_mac and the length + * of the receiver_specific_mac which is set to 0 + */ + *footer = (struct crypto_footer *)ptr; + + return true; +} + +static void decode_serialized_payload_check(uint32_t key_size, bool encrypted) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq extra_inline_qos; + DDS_Security_OctetSeq plain_buffer; + session_key_material *session_keys; + size_t length; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_serialized_payload != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->decode_serialized_payload != NULL); + + memset(&extra_inline_qos, 0, sizeof(extra_inline_qos)); + + length = strlen(sample_test_data) + 1; + plain_buffer._length = plain_buffer._maximum = (uint32_t) length; + plain_buffer._buffer = DDS_Security_OctetSeq_allocbuf((uint32_t)length); + memcpy((char *)plain_buffer._buffer, sample_test_data, length); + + local_writer_crypto = register_local_datawriter(encrypted); + CU_ASSERT_FATAL(local_writer_crypto != 0); + CU_ASSERT(check_writer_protection_kind(local_writer_crypto, encrypted ? DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT : DDS_SECURITY_BASICPROTECTION_KIND_SIGN)); + + session_keys = get_datawriter_session(local_writer_crypto); + session_keys->master_key_material->transformation_kind = get_transformation_kind(key_size, encrypted); + session_keys->key_size = key_size; + + local_reader_crypto = register_local_datareader(encrypted); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + result = set_remote_datawriter_tokens(local_writer_crypto, remote_reader_crypto, local_reader_crypto, remote_writer_crypto); + CU_ASSERT_FATAL(result); + + /* Encrypt the data. */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + &plain_buffer, + local_writer_crypto, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* Decrypt the data */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + unregister_datareader(remote_reader_crypto); + unregister_datawriter(remote_writer_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + DDS_Security_OctetSeq_deinit(&plain_buffer); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_decode_serialized_payload, decrypt_128, .init = suite_decode_serialized_payload_init, .fini = suite_decode_serialized_payload_fini) +{ + decode_serialized_payload_check(128, true); +} + +CU_Test(ddssec_builtin_decode_serialized_payload, decrypt_256, .init = suite_decode_serialized_payload_init, .fini = suite_decode_serialized_payload_fini) +{ + decode_serialized_payload_check(256, true); +} + +CU_Test(ddssec_builtin_decode_serialized_payload, signcheck_128, .init = suite_decode_serialized_payload_init, .fini = suite_decode_serialized_payload_fini) +{ + decode_serialized_payload_check(128, false); +} + +CU_Test(ddssec_builtin_decode_serialized_payload, signcheck_256, .init = suite_decode_serialized_payload_init, .fini = suite_decode_serialized_payload_fini) +{ + decode_serialized_payload_check(256, false); +} + +CU_Test(ddssec_builtin_decode_serialized_payload, invalid_args, .init = suite_decode_serialized_payload_init, .fini = suite_decode_serialized_payload_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq extra_inline_qos; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq empty_buffer; + session_key_material *session_keys; + size_t length; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_serialized_payload != NULL); + + memset(&extra_inline_qos, 0, sizeof(extra_inline_qos)); + memset(&empty_buffer, 0, sizeof(empty_buffer)); + + length = strlen(sample_test_data) + 1; + plain_buffer._length = plain_buffer._maximum = (uint32_t)length; + plain_buffer._buffer = DDS_Security_OctetSeq_allocbuf((uint32_t)length); + memcpy((char *)plain_buffer._buffer, sample_test_data, length); + + local_writer_crypto = register_local_datawriter(true); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + session_keys = get_datawriter_session(local_writer_crypto); + session_keys->master_key_material->transformation_kind = CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + session_keys->key_size = 256; + + local_reader_crypto = register_local_datareader(true); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + result = set_remote_datawriter_tokens(local_writer_crypto, remote_reader_crypto, local_reader_crypto, remote_writer_crypto); + CU_ASSERT_FATAL(result); + + /* encrypt the data */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + &plain_buffer, + local_writer_crypto, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + /* no decoded data buffer specified */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + NULL, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* no encrypted data buffer specified */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + NULL, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* empty encrypted data buffer specified */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &empty_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* unknown local reader crypto handle specified */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + 0, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local reader crypto handle specified */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + remote_writer_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* unknown remote writer crypto handle specified */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + 0, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid remote writer crypto handle specified */ + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + local_reader_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + unregister_datareader(remote_reader_crypto); + unregister_datawriter(remote_writer_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&plain_buffer); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_decode_serialized_payload, invalid_data, .init = suite_decode_serialized_payload_init, .fini = suite_decode_serialized_payload_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle local_writer_crypto; + DDS_Security_DatareaderCryptoHandle local_reader_crypto; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq decoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq extra_inline_qos; + DDS_Security_OctetSeq plain_buffer; + session_key_material *session_keys; + size_t length; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + unsigned char *contents = NULL; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_serialized_payload != NULL); + + memset(&extra_inline_qos, 0, sizeof(extra_inline_qos)); + + length = strlen(sample_test_data) + 1; + plain_buffer._length = plain_buffer._maximum = (uint32_t) length; + plain_buffer._buffer = DDS_Security_OctetSeq_allocbuf((uint32_t) length); + memcpy((char *)plain_buffer._buffer, sample_test_data, length); + + local_writer_crypto = register_local_datawriter(true); + CU_ASSERT_FATAL(local_writer_crypto != 0); + + session_keys = get_datawriter_session(local_writer_crypto); + session_keys->master_key_material->transformation_kind = CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + session_keys->key_size = 256; + + local_reader_crypto = register_local_datareader(true); + CU_ASSERT_FATAL(local_reader_crypto != 0); + + remote_reader_crypto = register_remote_datareader(local_writer_crypto); + CU_ASSERT_FATAL(remote_reader_crypto != 0); + + remote_writer_crypto = register_remote_datawriter(local_reader_crypto); + CU_ASSERT_FATAL(remote_writer_crypto != 0); + + result = set_remote_datawriter_tokens(local_writer_crypto, remote_reader_crypto, local_reader_crypto, remote_writer_crypto); + CU_ASSERT_FATAL(result); + + /* Encrypt the data. */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + &plain_buffer, + local_writer_crypto, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + assert(result); // for Clang's static analyzer + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + result = split_encoded_data(encoded_buffer._buffer, encoded_buffer._length, &header, &contents, (uint32_t *) &length, &footer); + CU_ASSERT_FATAL(result); + assert(result); // for Clang's static analyzer + + /* use incorrect transformation kind */ + { + DDS_Security_CryptoTransformKind_Enum kind = header->transform_identifier.transformation_kind[3]; + header->transform_identifier.transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + header->transform_identifier.transformation_kind[3] = (unsigned char) kind; + } + + /* use incorrect transformation key id */ + { + unsigned char key[4]; + uint32_t val = (uint32_t) rand(); + + memcpy(key, header->transform_identifier.transformation_key_id, 4); + memcpy(header->transform_identifier.transformation_key_id, &val, 4); + + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + memcpy(header->transform_identifier.transformation_key_id, key, 4); + } + + /* use incorrect session id*/ + { + unsigned char sid[4]; + uint32_t val = (uint32_t) rand(); + + memcpy(sid, header->session_id, 4); + memcpy(header->session_id, &val, 4); + + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + memcpy(header->session_id, sid, 4); + } + + /* use incorrect init vector suffix*/ + { + unsigned char iv[8]; + struct + { + uint32_t h; + uint32_t l; + } val; + + val.h = (uint32_t) rand(); + val.l = (uint32_t) rand(); + + memcpy(iv, header->init_vector_suffix, 8); + memcpy(header->init_vector_suffix, &val, 8); + + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + memcpy(header->init_vector_suffix, iv, 8); + } + + /* use incorrect data length */ + { + uint32_t saved, len; + unsigned char *ptr; + + ptr = encoded_buffer._buffer + sizeof(struct crypto_header); + + memcpy(&saved, ptr, 4); + + len = ddsrt_toBE4u(saved); + len += 4; + len = ddsrt_fromBE4u(len); + + memcpy(ptr, &len, 4); + + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + memcpy(ptr, &saved, 4); + } + + /* use incorrect data */ + { + unsigned char saved[10]; + unsigned char *ptr; + + ptr = contents + 20; + + memcpy(&saved, ptr, 10); + memset(ptr, 0xFF, 10); + + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + memcpy(ptr, &saved, 10); + } + + /* use incorrect hmac */ + { + unsigned char hmac[16]; + uint32_t i, j; + + memcpy(hmac, footer->common_mac, 16); + for (i = 0, j = 15; i < 8; ++i, --j) + { + unsigned char c = footer->common_mac[j]; + footer->common_mac[j] = footer->common_mac[i]; + footer->common_mac[i] = c; + } + + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + memcpy(footer->common_mac, &hmac, 16); + } + + /* use incorrect footer*/ + { + footer->length[0] = 1; + + result = crypto->crypto_transform->decode_serialized_payload( + crypto->crypto_transform, + &decoded_buffer, + &encoded_buffer, + &extra_inline_qos, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (!result) + { + printf("decode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + footer->length[0] = 0; + } + + unregister_datareader(remote_reader_crypto); + unregister_datawriter(remote_writer_crypto); + unregister_datareader(local_reader_crypto); + unregister_datawriter(local_writer_crypto); + + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&plain_buffer); +} + diff --git a/src/security/builtin_plugins/tests/encode_datareader_submessage/src/encode_datareader_submessage_utests.c b/src/security/builtin_plugins/tests/encode_datareader_submessage/src/encode_datareader_submessage_utests.c new file mode 100644 index 0000000..2924299 --- /dev/null +++ b/src/security/builtin_plugins/tests/encode_datareader_submessage/src/encode_datareader_submessage_utests.c @@ -0,0 +1,1281 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_objects.h" +#include "crypto_utils.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_participant_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_handle = DDS_SECURITY_HANDLE_NIL; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +struct submsg_header +{ + unsigned char id; + unsigned char flags; + uint16_t length; +}; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[4]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + uint32_t length; +}; + +#if 0 +struct receiver_specific_mac +{ + DDS_Security_CryptoTransformKeyId receiver_mac_key_id; + unsigned char receiver_mac[CRYPTO_HMAC_SIZE]; +}; +#endif + +struct encrypted_data +{ + uint32_t length; + unsigned char data[]; +}; + +struct seq_number +{ + int high; + unsigned low; +}; + +struct heartbeat +{ + struct submsg_header smhdr; + uint32_t readerId; + uint32_t writerId; + struct seq_number firstSN; + struct seq_number lastSN; + int count; +}; + +static struct heartbeat heartbeat; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void initialize_heartbeat(void) +{ + heartbeat.smhdr.id = 0x07; + heartbeat.smhdr.flags = 1; + heartbeat.smhdr.length = sizeof(heartbeat) - sizeof(struct submsg_header); + heartbeat.readerId = 0xA1B2C3D4; + heartbeat.writerId = 0xE5F6A7B0; + heartbeat.firstSN.high = 0; + heartbeat.firstSN.low = 1; + heartbeat.lastSN.high = 20; + heartbeat.lastSN.low = 500; + heartbeat.count = 1021; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + memset(&participant_security_attributes, 0, sizeof(participant_security_attributes)); + + local_participant_handle = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_participant_handle ? 0 : -1; +} + +static void unregister_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (local_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_participant_handle, &exception); + reset_exception(&exception); + } +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_participant_handle = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_handle, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_participant_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_participant_handle ? 0 : -1; +} + +static void unregister_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (remote_participant_handle) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_participant_handle, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatareaderCryptoHandle register_local_datareader(DDS_Security_EndpointSecurityAttributes *datareader_security_attributes, DDS_Security_PropertySeq *datareader_properties) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + datareader_properties, + datareader_security_attributes, + &exception); + + if (reader_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static void unregister_datareader(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, reader_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatawriterCryptoHandle register_remote_datawriter(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + reader_crypto, + remote_participant_handle, + shared_secret_handle, + &exception); + + if (writer_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static void unregister_datawriter(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, writer_crypto, &exception); + reset_exception(&exception); + } +} + +static bool read_prefix(unsigned char **ptr, uint32_t *remain) +{ + struct submsg_header *prefix; + uint32_t hlen; + int swap; + + if (*remain < sizeof(struct submsg_header)) + { + printf("check_encoded_data: prefix missing\n"); + return false; + } + + prefix = (struct submsg_header *)(*ptr); + + if (prefix->id != SMID_SEC_PREFIX_KIND) + { + printf("check_encoded_data: prefix incorrect smid 0x%x02\n", prefix->id); + return false; + } + + if (prefix->flags & 0x01) + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + + hlen = swap ? ddsrt_bswap2u(prefix->length) : prefix->length; + + if (hlen != sizeof(struct crypto_header)) + { + printf("check_encoded_data: crypto_header missing\n"); + return false; + } + + *ptr += sizeof(struct submsg_header); + *remain -= (uint32_t)sizeof(struct submsg_header); + + return true; +} + +static bool read_header(struct crypto_header **header, unsigned char **ptr, uint32_t *remain) +{ + if (*remain < sizeof(struct crypto_header)) + { + printf("check_encoded_data: crypto_header too short\n"); + return false; + } + + *header = ddsrt_malloc(sizeof(struct crypto_header)); + memcpy(*header, *ptr, sizeof(struct crypto_header)); + + *ptr += sizeof(struct crypto_header); + *remain -= (uint32_t)sizeof(struct crypto_header); + + return true; +} + +static bool read_body(DDS_Security_OctetSeq *contents, bool encrypted, unsigned char **ptr, uint32_t *remain) +{ + struct submsg_header *body; + uint32_t hlen, clen; + int swap; + + if (*remain < sizeof(struct submsg_header)) + { + return false; + } + + body = (struct submsg_header *)(*ptr); + + if (body->flags & 0x01) + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + + hlen = swap ? ddsrt_bswap2u(body->length) : body->length; + + if (encrypted) + { + struct encrypted_data *enc; + + if (body->id != SMID_SEC_BODY_KIND) + { + printf("check_encoded_data: submessage SEC_BODY missing\n"); + return false; + } + enc = (struct encrypted_data *)(body + 1); + clen = ddsrt_fromBE4u(enc->length); + + contents->_length = contents->_maximum = clen; + contents->_buffer = &enc->data[0]; + } + else + { + if (body->id == SMID_SEC_BODY_KIND) + { + printf("check_encoded_data: submessage SEC_BODY not expected\n"); + return false; + } + clen = swap ? ddsrt_bswap2u(body->length) : body->length; + clen += (uint32_t)sizeof(struct submsg_header); + + contents->_length = contents->_maximum = clen; + contents->_buffer = *ptr; + } + *ptr += sizeof(struct submsg_header) + hlen; + *remain -= (uint32_t)sizeof(struct submsg_header) + hlen; + + return true; +} + +static bool read_postfix(unsigned char **ptr, uint32_t *remain) +{ + struct submsg_header *postfix; + + if (*remain < sizeof(struct submsg_header)) + { + printf("check_encoded_data: postfix missing\n"); + return false; + } + + postfix = (struct submsg_header *)(*ptr); + + if (postfix->id != SMID_SEC_POSTFIX_KIND) + { + printf("check_encoded_data: postfix invalid smid\n"); + return false; + } + + *ptr += sizeof(struct submsg_header); + *remain -= (uint32_t)sizeof(struct submsg_header); + + return true; +} + +static bool read_footer(struct crypto_footer **footer, unsigned char **ptr, uint32_t *remain) +{ + if (*remain < CRYPTO_HMAC_SIZE + sizeof(uint32_t)) + { + printf("check_encoded_data: crypto_footer incorrect size\n"); + return false; + } + + *footer = ddsrt_malloc(*remain); + memcpy(*footer, *ptr, *remain); + + /* length of reader specific macs is in BIG-ENDIAN format */ + (*footer)->length = ddsrt_fromBE4u((*footer)->length); + + return true; +} + +static bool check_encoded_data(DDS_Security_OctetSeq *data, bool encrypted, struct crypto_header **header, struct crypto_footer **footer, DDS_Security_OctetSeq *contents) +{ + bool result = true; + unsigned char *ptr = data->_buffer; + uint32_t remain = data->_length; + + result = read_prefix(&ptr, &remain); + if (result) + result = read_header(header, &ptr, &remain); + if (result) + result = read_body(contents, encrypted, &ptr, &remain); + if (result) + result = read_postfix(&ptr, &remain); + if (result) + result = read_footer(footer, &ptr, &remain); + + return result; +} + +static bool cipher_sign_data(const unsigned char *session_key, uint32_t key_size, const unsigned char *iv, const unsigned char *data, uint32_t data_len, unsigned char *tag) +{ + EVP_CIPHER_CTX *ctx; + unsigned char temp[32]; + int len; + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + { + ERR_print_errors_fp(stderr); + goto fail_ctx_new; + } + + /* initialize the cipher and set to AES GCM */ + if (key_size == 128) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + } + else if (key_size == 256) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + } + + /* Initialise key and IV */ + if (!EVP_EncryptInit_ex(ctx, NULL, NULL, session_key, iv)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + if (!EVP_EncryptUpdate(ctx, NULL, &len, data, (int) data_len)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + if (!EVP_EncryptFinal_ex(ctx, temp, &len)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + /* get the tag */ + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, CRYPTO_HMAC_SIZE, tag)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + /* clean up */ + EVP_CIPHER_CTX_free(ctx); + + return true; + +fail_encrypt: + EVP_CIPHER_CTX_free(ctx); +fail_ctx_new: + return false; +} + +static bool crypto_decrypt_data(uint32_t session_id, unsigned char *iv, DDS_Security_CryptoTransformKind transformation_kind, master_key_material *key_material, DDS_Security_OctetSeq *encrypted, DDS_Security_OctetSeq *decoded, unsigned char *tag) +{ + bool result = true; + EVP_CIPHER_CTX *ctx; + crypto_session_key_t session_key; + uint32_t key_size = crypto_get_key_size(CRYPTO_TRANSFORM_KIND(transformation_kind)); + int len = 0; + + if (!crypto_calculate_session_key_test(&session_key, session_id, key_material->master_salt, key_material->master_sender_key, key_material->transformation_kind)) + return false; + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (ctx) + { + if (key_size == 128) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else if (key_size == 256) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (result) + { + if (!EVP_DecryptInit_ex(ctx, NULL, NULL, session_key.data, iv)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptUpdate(ctx, decoded->_buffer, &len, encrypted->_buffer, (int) encrypted->_length)) + { + decoded->_length = (uint32_t) len; + } + else + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + if (!EVP_DecryptUpdate(ctx, NULL, &len, encrypted->_buffer, (int) encrypted->_length)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (result) + { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, CRYPTO_HMAC_SIZE, tag)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptFinal_ex(ctx, decoded->_buffer + len, &len)) + { + decoded->_length += (uint32_t) len; + } + else + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + unsigned char temp[32]; + if (!EVP_DecryptFinal_ex(ctx, temp, &len)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (ctx) + EVP_CIPHER_CTX_free(ctx); + + return result; +} + +static void prepare_endpoint_security_attributes_and_properties(DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_PropertySeq *properties, + uint32_t transformation_kind, + bool is_origin_authenticated) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + memset(properties, 0, sizeof(DDS_Security_PropertySeq)); + + attributes->is_discovery_protected = true; + + properties->_maximum = properties->_length = 1; + properties->_buffer = ddsrt_malloc(sizeof(DDS_Security_Property_t)); + + properties->_buffer[0].name = ddsrt_strdup("dds.sec.crypto.keysize"); + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC) + { + properties->_buffer[0].value = ddsrt_strdup("128"); + } + else + { + properties->_buffer[0].value = ddsrt_strdup("256"); + } + + switch (transformation_kind) + { + case CRYPTO_TRANSFORMATION_KIND_AES128_GCM: + case CRYPTO_TRANSFORMATION_KIND_AES256_GCM: + attributes->is_submessage_protected = true; + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + case CRYPTO_TRANSFORMATION_KIND_AES256_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES128_GMAC: + attributes->is_submessage_protected = true; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + default: + assert(0); + break; + } +} + +static session_key_material * get_datareader_session(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + local_datareader_crypto *reader_crypto_impl = (local_datareader_crypto *)reader_crypto; + return reader_crypto_impl->reader_session; +} + +static master_key_material * get_datawriter_key_material(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + remote_datawriter_crypto *writer_crypto_impl = (remote_datawriter_crypto *)writer_crypto; + return writer_crypto_impl->reader2writer_key_material; +} + +static void initialize_data_submessage(DDS_Security_OctetSeq *submsg) +{ + uint32_t length = sizeof(struct heartbeat); + unsigned char *buffer; + + buffer = ddsrt_malloc(length); + + memcpy(buffer, &heartbeat, length); + + submsg->_length = submsg->_maximum = length; + submsg->_buffer = buffer; +} + +static bool check_writer_sign(DDS_Security_DatareaderCryptoHandle writer_crypto, uint32_t session_id, uint32_t key_id, uint32_t key_size, unsigned char *init_vector, unsigned char *common_mac, unsigned char *hmac) +{ + master_key_material *keymat; + crypto_session_key_t key; + unsigned char md[CRYPTO_HMAC_SIZE]; + + keymat = get_datawriter_key_material(writer_crypto); + if (key_id != keymat->receiver_specific_key_id) + { + printf("check_writer_sign: key_id does not match\n"); + return false; + } + else if (!calculate_receiver_specific_key_test(&key, session_id, keymat->master_salt, keymat->master_receiver_specific_key, keymat->transformation_kind)) + { + printf("check_writer_sign: calculate key failed\n"); + return false; + } + else if (!cipher_sign_data(key.data, key_size, init_vector, common_mac, CRYPTO_HMAC_SIZE, md)) + { + return false; + } + else if (memcmp(hmac, md, CRYPTO_HMAC_SIZE) != 0) + { + printf("check_writer_sign: hmac incorrect\n"); + return false; + } + + return true; +} + +static bool check_writer_signing(DDS_Security_DatareaderCryptoHandleSeq *list, struct crypto_footer *footer, uint32_t session_id, unsigned char *init_vector, uint32_t key_size) +{ + struct receiver_specific_mac *rmac; + uint32_t key_id; + uint32_t i; + + if (footer->length != list->_length) + { + return false; + } + + rmac = (struct receiver_specific_mac *)(footer + 1); + + for (i = 0; i < list->_length; i++) + { + key_id = ddsrt_bswap4u(*(uint32_t *)rmac[i].receiver_mac_key_id); + if (!check_writer_sign(list->_buffer[i], session_id, key_id, key_size, init_vector, footer->common_mac, rmac[i].receiver_mac.data)) + { + return false; + } + } + + return true; +} + +static void suite_encode_datareader_submessage_init(void) +{ + allocate_shared_secret(); + initialize_heartbeat(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); +} + +static void suite_encode_datareader_submessage_fini(void) +{ + unregister_remote_participant(); + unregister_local_participant(); + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void encode_datareader_submessage_not_signed(uint32_t transformation_kind) +{ + DDS_Security_boolean result; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatawriterCryptoHandleSeq writer_list; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + DDS_Security_OctetSeq data; + session_key_material *session_keys; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + uint32_t session_id; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + bool is_encrypted; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + + is_encrypted = (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES256_GCM); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, transformation_kind, false); + + initialize_data_submessage(&plain_buffer); + + reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(reader_crypto != 0); + assert(reader_crypto != 0); // for Clang's static analyzer + + session_keys = get_datareader_session(reader_crypto); + + writer_crypto = register_remote_datawriter(reader_crypto); + CU_ASSERT_FATAL(writer_crypto != 0); + + writer_list._length = writer_list._maximum = 1; + writer_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + writer_list._buffer[0] = writer_crypto; + + /* Now call the function. */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + reader_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + assert(result); // for Clang's static analyzer + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + result = check_encoded_data(&encoded_buffer, is_encrypted, &header, &footer, &data); + CU_ASSERT_FATAL(result); + assert(result); // for Clang's static analyzer + + CU_ASSERT(header->transform_identifier.transformation_kind[3] == transformation_kind); + + session_id = ddsrt_bswap4u(*(uint32_t *)header->session_id); + + if (is_encrypted) + { + decoded_buffer._buffer = ddsrt_malloc(plain_buffer._length); + decoded_buffer._length = 0; + decoded_buffer._maximum = plain_buffer._length; + + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, &decoded_buffer, footer->common_mac); + + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + CU_ASSERT(memcmp(plain_buffer._buffer, decoded_buffer._buffer, plain_buffer._length) == 0); + + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + } + else + { + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, NULL, footer->common_mac); + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + CU_ASSERT(memcmp(plain_buffer._buffer, data._buffer, plain_buffer._length) == 0); + } + + unregister_datawriter(writer_list._buffer[0]); + writer_list._buffer[0] = 0; + + unregister_datareader(reader_crypto); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatawriterCryptoHandleSeq_deinit(&writer_list); + + ddsrt_free(footer); + ddsrt_free(header); + + DDS_Security_PropertySeq_deinit(&datareader_properties); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, encode_256, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, encode_128, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, no_encode_256, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, no_encode_128, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +static void encode_datareader_submessage_sign(uint32_t transformation_kind) +{ + const uint32_t WRITERS_CNT = 4u; + DDS_Security_boolean result; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatawriterCryptoHandleSeq writer_list; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + DDS_Security_OctetSeq data; + DDS_Security_OctetSeq *buffer; + session_key_material *session_keys; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + uint32_t session_id; + uint32_t i; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + bool is_encrypted; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES256_GCM) + { + is_encrypted = true; + } + else + { + is_encrypted = false; + } + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, transformation_kind, true); + + initialize_data_submessage(&plain_buffer); + + reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(reader_crypto != 0); + assert(reader_crypto != 0); // for Clang's static analyzer + + session_keys = get_datareader_session(reader_crypto); + + writer_list._length = writer_list._maximum = WRITERS_CNT; + writer_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(4); + for (i = 0; i < WRITERS_CNT; i++) + { + writer_crypto = register_remote_datawriter(reader_crypto); + CU_ASSERT_FATAL(writer_crypto != 0); + assert(writer_crypto != 0); // for Clang's static analyzer + writer_list._buffer[i] = writer_crypto; + } + + /* Now call the function. */ + + buffer = &plain_buffer; + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + buffer, + reader_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("writer_crypto: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + assert(result); // for Clang's static analyzer + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + buffer = NULL; + + result = check_encoded_data(&encoded_buffer, is_encrypted, &header, &footer, &data); + CU_ASSERT_FATAL(result); + assert(result); // for Clang's static analyzer + + CU_ASSERT(header->transform_identifier.transformation_kind[3] == transformation_kind); + + session_id = ddsrt_bswap4u(*(uint32_t *)header->session_id); + + if (is_encrypted) + { + decoded_buffer._buffer = ddsrt_malloc(plain_buffer._length); + decoded_buffer._length = 0; + decoded_buffer._maximum = plain_buffer._length; + + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, &decoded_buffer, footer->common_mac); + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + CU_ASSERT(memcmp(plain_buffer._buffer, decoded_buffer._buffer, plain_buffer._length) == 0); + + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + } + else + { + result = crypto_decrypt_data(session_id, header->session_id, header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, NULL, footer->common_mac); + + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(memcmp(plain_buffer._buffer, data._buffer, plain_buffer._length) == 0); + } + + printf("num hmacs = %u\n", footer->length); + + CU_ASSERT(check_writer_signing(&writer_list, footer, session_id, header->session_id, session_keys->key_size)); + + for (i = 0; i < WRITERS_CNT; i++) + { + unregister_datawriter(writer_list._buffer[i]); + writer_list._buffer[i] = 0; + } + + unregister_datareader(reader_crypto); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&writer_list); + + ddsrt_free(footer); + ddsrt_free(header); + + DDS_Security_PropertySeq_deinit(&datareader_properties); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, encode_sign_256, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, encode_sign_128, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, no_encode_sign_256, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, no_encode_sign_128, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + encode_datareader_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +CU_Test(ddssec_builtin_encode_datareader_submessage, invalid_args, .init = suite_encode_datareader_submessage_init, .fini = suite_encode_datareader_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_DatawriterCryptoHandle reader_crypto; + DDS_Security_DatareaderCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandleSeq writer_list; + DDS_Security_DatareaderCryptoHandleSeq empty_writer_list; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datareader_submessage != NULL); + + prepare_endpoint_security_attributes_and_properties(&datareader_security_attributes, &datareader_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + + initialize_data_submessage(&plain_buffer); + + memset(&empty_writer_list, 0, sizeof(empty_writer_list)); + + reader_crypto = register_local_datareader(&datareader_security_attributes, &datareader_properties); + CU_ASSERT_FATAL(reader_crypto != 0); + + writer_crypto = register_remote_datawriter(reader_crypto); + CU_ASSERT_FATAL(writer_crypto != 0); + + writer_list._length = writer_list._maximum = 1; + writer_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + writer_list._buffer[0] = writer_crypto; + + /* encoded_buffer NULL */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + NULL, + &plain_buffer, + reader_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* plain_buffer NULL */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + NULL, + writer_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto 0 */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + 0, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto unknown */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + 1, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* reader crypto list NULL*/ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + NULL, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* empty reader crypto list */ + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &empty_writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto list with invalid writer crypto */ + writer_list._buffer[0] = 0; + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto list with unknown writer crypto*/ + writer_list._buffer[0] = 1; + result = crypto->crypto_transform->encode_datareader_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &writer_list, + &exception); + + if (!result) + { + printf("encode_datareader_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + unregister_datawriter(writer_list._buffer[0]); + writer_list._buffer[0] = 0; + + unregister_datareader(reader_crypto); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_DatawriterCryptoHandleSeq_deinit(&writer_list); + DDS_Security_PropertySeq_deinit(&datareader_properties); +} + diff --git a/src/security/builtin_plugins/tests/encode_datawriter_submessage/src/encode_datawriter_submessage_utests.c b/src/security/builtin_plugins/tests/encode_datawriter_submessage/src/encode_datawriter_submessage_utests.c new file mode 100644 index 0000000..389c27c --- /dev/null +++ b/src/security/builtin_plugins/tests/encode_datawriter_submessage/src/encode_datawriter_submessage_utests.c @@ -0,0 +1,1356 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_objects.h" +#include "crypto_utils.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_particpant_crypto = 0; +static DDS_Security_ParticipantCryptoHandle remote_particpant_crypto = 0; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static const char *sample_test_data = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy"; + +struct submsg_header +{ + unsigned char id; + unsigned char flags; + uint16_t length; +}; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[4]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + uint32_t length; +}; + +#if 0 +struct receiver_specific_mac +{ + DDS_Security_CryptoTransformKeyId receiver_mac_key_id; + unsigned char receiver_mac[CRYPTO_HMAC_SIZE]; +}; +#endif + +struct encrypted_data +{ + uint32_t length; + unsigned char data[]; +}; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + memset(&participant_security_attributes, 0, sizeof(participant_security_attributes)); + + local_particpant_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_particpant_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_particpant_crypto ? 0 : -1; +} + +static void unregister_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (local_particpant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_particpant_crypto, &exception); + reset_exception(&exception); + } +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_particpant_crypto = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_particpant_crypto, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_particpant_crypto == 0) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_particpant_crypto ? 0 : -1; +} + +static void prepare_endpoint_security_attributes_and_properties(DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_PropertySeq *properties, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + bool is_origin_authenticated) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + memset(properties, 0, sizeof(DDS_Security_PropertySeq)); + + attributes->is_discovery_protected = true; + + properties->_maximum = properties->_length = 1; + properties->_buffer = ddsrt_malloc(sizeof(DDS_Security_Property_t)); + + properties->_buffer[0].name = ddsrt_strdup("dds.sec.crypto.keysize"); + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC) + { + properties->_buffer[0].value = ddsrt_strdup("128"); + } + else + { + properties->_buffer[0].value = ddsrt_strdup("256"); + } + + switch (transformation_kind) + { + case CRYPTO_TRANSFORMATION_KIND_AES128_GCM: + case CRYPTO_TRANSFORMATION_KIND_AES256_GCM: + attributes->is_submessage_protected = true; + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + case CRYPTO_TRANSFORMATION_KIND_AES256_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES128_GMAC: + attributes->is_submessage_protected = true; + if (is_origin_authenticated) + { + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + break; + + default: + assert(0); + break; + } +} + +static void unregister_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (remote_particpant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_particpant_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatawriterCryptoHandle register_local_datawriter(DDS_Security_EndpointSecurityAttributes *datawriter_security_attributes, DDS_Security_PropertySeq *datawriter_properties) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_particpant_crypto, + datawriter_properties, + datawriter_security_attributes, + &exception); + + if (writer_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static void unregister_datawriter(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, writer_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatareaderCryptoHandle register_remote_datareader(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + writer_crypto, + remote_particpant_crypto, + shared_secret_handle, + true, + &exception); + + if (reader_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static void unregister_datareader(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, reader_crypto, &exception); + reset_exception(&exception); + } +} + +static bool read_prefix(unsigned char **ptr, uint32_t *remain) +{ + struct submsg_header *prefix; + uint32_t hlen; + int swap; + + if (*remain < sizeof(struct submsg_header)) + { + printf("check_encoded_data: prefix missing\n"); + return false; + } + + prefix = (struct submsg_header *)(*ptr); + + if (prefix->id != SMID_SEC_PREFIX_KIND) + { + printf("check_encoded_data: prefix incorrect smid 0x%x02\n", prefix->id); + return false; + } + + if (prefix->flags & 0x01) + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + + hlen = swap ? ddsrt_bswap2u(prefix->length) : prefix->length; + + if (hlen != sizeof(struct crypto_header)) + { + printf("check_encoded_data: crypto_header missing\n"); + return false; + } + + *ptr += sizeof(struct submsg_header); + *remain -= (uint32_t)sizeof(struct submsg_header); + + return true; +} + +static bool read_header(struct crypto_header **header, unsigned char **ptr, uint32_t *remain) +{ + if (*remain < sizeof(struct crypto_header)) + { + printf("check_encoded_data: crypto_header too short\n"); + return false; + } + + *header = ddsrt_malloc(sizeof(struct crypto_header)); + memcpy(*header, *ptr, sizeof(struct crypto_header)); + + *ptr += sizeof(struct crypto_header); + *remain -= (uint32_t)sizeof(struct crypto_header); + + return true; +} + +static bool read_body(DDS_Security_OctetSeq *contents, bool encrypted, unsigned char **ptr, uint32_t *remain) +{ + struct submsg_header *body; + uint32_t hlen, clen; + int swap; + + if (*remain < sizeof(struct submsg_header)) + { + return false; + } + + body = (struct submsg_header *)(*ptr); + + if (body->flags & 0x01) + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + + hlen = swap ? ddsrt_bswap2u(body->length) : body->length; + + if (encrypted) + { + struct encrypted_data *enc; + + if (body->id != SMID_SEC_BODY_KIND) + { + printf("check_encoded_data: submessage SEC_BODY missing\n"); + return false; + } + enc = (struct encrypted_data *)(body + 1); + clen = ddsrt_fromBE4u(enc->length); + + contents->_length = contents->_maximum = clen; + contents->_buffer = &enc->data[0]; + } + else + { + if (body->id == SMID_SEC_BODY_KIND) + { + printf("check_encoded_data: submessage SEC_BODY not expected\n"); + return false; + } + clen = swap ? ddsrt_bswap2u(body->length) : body->length; + clen += (uint32_t)sizeof(struct submsg_header); + + contents->_length = contents->_maximum = clen; + contents->_buffer = *ptr; + } + *ptr += sizeof(struct submsg_header) + hlen; + *remain -= (uint32_t)sizeof(struct submsg_header) + hlen; + + return true; +} + +static bool read_postfix(unsigned char **ptr,uint32_t *remain) +{ + struct submsg_header *postfix; + + if (*remain < sizeof(struct submsg_header)) + { + printf("check_encoded_data: postfix missing\n"); + return false; + } + + postfix = (struct submsg_header *)(*ptr); + + if (postfix->id != SMID_SEC_POSTFIX_KIND) + { + printf("check_encoded_data: postfix invalid smid\n"); + return false; + } + + *ptr += sizeof(struct submsg_header); + *remain -= (uint32_t)sizeof(struct submsg_header); + + return true; +} + +static bool read_footer(struct crypto_footer **footer, unsigned char **ptr, uint32_t *remain) +{ + if (*remain < CRYPTO_HMAC_SIZE + sizeof(uint32_t)) + { + printf("check_encoded_data: crypto_footer incorrect size\n"); + return false; + } + + *footer = ddsrt_malloc(*remain); + memcpy(*footer, *ptr, *remain); + + /* length of reader specific macs is in BIG-ENDIAN format */ + (*footer)->length = ddsrt_fromBE4u((*footer)->length); + + return true; +} + +static bool check_encoded_data(DDS_Security_OctetSeq *data, bool encrypted, struct crypto_header **header, struct crypto_footer **footer, DDS_Security_OctetSeq *contents) +{ + bool result = true; + unsigned char *ptr = data->_buffer; + uint32_t remain = data->_length; + + result = read_prefix(&ptr, &remain); + if (result) + result = read_header(header, &ptr, &remain); + if (result) + result = read_body(contents, encrypted, &ptr, &remain); + if (result) + result = read_postfix(&ptr, &remain); + if (result) + result = read_footer(footer, &ptr, &remain); + + return result; +} + +static bool cipher_sign_data(const unsigned char *session_key, uint32_t key_size, const unsigned char *iv, const unsigned char *data, uint32_t data_len, unsigned char *tag) +{ + EVP_CIPHER_CTX *ctx; + unsigned char temp[32]; + int len; + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + { + ERR_print_errors_fp(stderr); + goto fail_ctx_new; + } + + /* initialize the cipher and set to AES GCM */ + if (key_size == 128) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + } + else if (key_size == 256) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + } + + /* Initialise key and IV */ + if (!EVP_EncryptInit_ex(ctx, NULL, NULL, session_key, iv)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + if (!EVP_EncryptUpdate(ctx, NULL, &len, data, (int)data_len)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + if (!EVP_EncryptFinal_ex(ctx, temp, &len)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + /* get the tag */ + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, CRYPTO_HMAC_SIZE, tag)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + /* clean up */ + EVP_CIPHER_CTX_free(ctx); + + return true; + +fail_encrypt: + EVP_CIPHER_CTX_free(ctx); +fail_ctx_new: + return false; +} + +static bool crypto_decrypt_data(uint32_t session_id, unsigned char *iv, DDS_Security_CryptoTransformKind transformation_kind, master_key_material *key_material, DDS_Security_OctetSeq *encrypted, DDS_Security_OctetSeq *decoded, unsigned char *tag) +{ + bool result = true; + EVP_CIPHER_CTX *ctx; + crypto_session_key_t session_key; + uint32_t key_size = crypto_get_key_size(CRYPTO_TRANSFORM_KIND(transformation_kind)); + int len = 0; + + if (!crypto_calculate_session_key_test(&session_key, session_id, key_material->master_salt, key_material->master_sender_key, key_material->transformation_kind)) + return false; + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (ctx) + { + if (key_size == 128) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else if (key_size == 256) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (result) + { + if (!EVP_DecryptInit_ex(ctx, NULL, NULL, session_key.data, iv)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptUpdate(ctx, decoded->_buffer, &len, encrypted->_buffer, (int)encrypted->_length)) + { + decoded->_length = (uint32_t) len; + } + else + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + if (!EVP_DecryptUpdate(ctx, NULL, &len, encrypted->_buffer, (int) encrypted->_length)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (result) + { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, CRYPTO_HMAC_SIZE, tag)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptFinal_ex(ctx, decoded->_buffer + len, &len)) + { + decoded->_length += (uint32_t) len; + } + else + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + unsigned char temp[32]; + if (!EVP_DecryptFinal_ex(ctx, temp, &len)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (ctx) + EVP_CIPHER_CTX_free(ctx); + + return result; +} + +static session_key_material * get_datawriter_session(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + local_datawriter_crypto *writer_crypto_impl = (local_datawriter_crypto *)writer_crypto; + return writer_crypto_impl->writer_session_message; +} + +static master_key_material * get_datareader_key_material(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + remote_datareader_crypto *reader_crypto_impl = (remote_datareader_crypto *)reader_crypto; + return reader_crypto_impl->writer2reader_key_material_message; +} + +static void initialize_data_submessage(DDS_Security_OctetSeq *submsg, bool be) +{ + size_t length = strlen(sample_test_data) + 1; + struct submsg_header *header; + int swap; + unsigned char *buffer, *ptr; + + if (be) + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + + buffer = ddsrt_malloc(length + sizeof(struct submsg_header)); + header = (struct submsg_header *)buffer; + header->id = 0x15; + header->flags = be ? 0x00 : 0x01; + header->length = swap ? ddsrt_bswap2u((uint16_t)length) : (uint16_t)length; + ptr = (unsigned char *)(header + 1); + + memcpy((char *)ptr, sample_test_data, length); + + submsg->_length = submsg->_maximum = (uint32_t)(length + sizeof(struct submsg_header)); + submsg->_buffer = buffer; +} + +static bool check_reader_sign( + DDS_Security_DatareaderCryptoHandle reader_crypto, + uint32_t session_id, + uint32_t key_id, + uint32_t key_size, + unsigned char *init_vector, + unsigned char *common_mac, + unsigned char *hmac) +{ + master_key_material *keymat; + crypto_session_key_t key; + unsigned char md[CRYPTO_HMAC_SIZE]; + + keymat = get_datareader_key_material(reader_crypto); + + if (key_id != keymat->receiver_specific_key_id) + { + printf("check_reader_sign: key_id does not match\n"); + return false; + } + else if (!calculate_receiver_specific_key_test(&key, session_id, keymat->master_salt, keymat->master_receiver_specific_key, keymat->transformation_kind)) + { + printf("check_reader_sign: calculate key failed\n"); + return false; + } + else if (!cipher_sign_data(key.data, key_size, init_vector, common_mac, CRYPTO_HMAC_SIZE, md)) + { + return false; + } + else if (memcmp(hmac, md, CRYPTO_HMAC_SIZE) != 0) + { + printf("check_reader_sign: hmac incorrect\n"); + return false; + } + + return true; +} + +static bool check_reader_signing(DDS_Security_DatareaderCryptoHandleSeq *list, struct crypto_footer *footer, uint32_t session_id, unsigned char *init_vector, uint32_t key_size) +{ + struct receiver_specific_mac *rmac; + uint32_t key_id; + uint32_t i; + + if (footer->length != list->_length) + { + return false; + } + + rmac = (struct receiver_specific_mac *)(footer + 1); + + for (i = 0; i < list->_length; i++) + { + key_id = ddsrt_bswap4u(*(uint32_t *)rmac[i].receiver_mac_key_id); + if (!check_reader_sign(list->_buffer[i], session_id, key_id, key_size, init_vector, footer->common_mac, rmac[i].receiver_mac.data)) + { + return false; + } + } + + return true; +} + +static void suite_encode_datawriter_submessage_init(void) +{ + allocate_shared_secret(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); +} + +static void suite_encode_datawriter_submessage_fini(void) +{ + unregister_remote_participant(); + unregister_local_participant(); + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void encode_datawriter_submessage_not_signed(DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + DDS_Security_boolean result; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + int32_t index; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + DDS_Security_OctetSeq data; + + session_key_material *session_keys; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + uint32_t session_id; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + bool is_encrypted; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES256_GCM) + { + is_encrypted = true; + } + else + { + is_encrypted = false; + } + + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, transformation_kind, false); + + initialize_data_submessage(&plain_buffer, false); + + writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(writer_crypto != 0); + assert(writer_crypto != 0); // for Clang's static analyzer + + session_keys = get_datawriter_session(writer_crypto); + + reader_crypto = register_remote_datareader(writer_crypto); + CU_ASSERT_FATAL(reader_crypto != 0); + assert(reader_crypto != 0); // for Clang's static analyzer + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = reader_crypto; + index = 0; + + /* Now call the function. */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + assert(result != 0); // for Clang's static analyzer + + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + result = check_encoded_data(&encoded_buffer, is_encrypted, &header, &footer, &data); + CU_ASSERT_FATAL(result); + assert(result); // for Clang's static analyzer + + CU_ASSERT(header->transform_identifier.transformation_kind[3] == transformation_kind); + + session_id = ddsrt_bswap4u(*(uint32_t *)header->session_id); + + if (is_encrypted) + { + decoded_buffer._buffer = ddsrt_malloc(plain_buffer._length); + decoded_buffer._length = 0; + decoded_buffer._maximum = plain_buffer._length; + + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, &decoded_buffer, footer->common_mac); + + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + CU_ASSERT(memcmp(plain_buffer._buffer, decoded_buffer._buffer, plain_buffer._length) == 0); + + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + } + else + { + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, NULL, footer->common_mac); + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + CU_ASSERT(memcmp(plain_buffer._buffer, data._buffer, plain_buffer._length) == 0); + } + + unregister_datareader(reader_list._buffer[0]); + reader_list._buffer[0] = 0; + + unregister_datawriter(writer_crypto); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + + ddsrt_free(datawriter_properties._buffer[0].name); + ddsrt_free(datawriter_properties._buffer[0].value); + ddsrt_free(datawriter_properties._buffer); + ddsrt_free(footer); + ddsrt_free(header); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, encode_256, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, encode_128, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, no_encode_256, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, no_encode_128, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_not_signed(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +static void encode_datawriter_submessage_sign(DDS_Security_CryptoTransformKind_Enum transformation_kind) +{ + const uint32_t READERS_CNT = 4u; + DDS_Security_boolean result; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + int32_t index; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + DDS_Security_OctetSeq data; + DDS_Security_OctetSeq *buffer; + session_key_material *session_keys; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + uint32_t session_id; + uint32_t i; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + bool is_encrypted; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES256_GCM) + { + is_encrypted = true; + } + else + { + is_encrypted = false; + } + + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, transformation_kind, true); + + initialize_data_submessage(&plain_buffer, false); + + writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(writer_crypto != 0); + assert(writer_crypto != 0); // for Clang's static analyzer + + session_keys = get_datawriter_session(writer_crypto); + + reader_list._length = reader_list._maximum = READERS_CNT; + reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(4); + for (i = 0; i < READERS_CNT; i++) + { + reader_crypto = register_remote_datareader(writer_crypto); + CU_ASSERT_FATAL(reader_crypto != 0); + assert(reader_crypto != 0); // for Clang's static analyzer + reader_list._buffer[i] = reader_crypto; + } + index = 0; + + /* Now call the function. */ + + buffer = &plain_buffer; + while (index != (int32_t)READERS_CNT) + { + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + buffer, + writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + assert(result); // for Clang's static analyzer + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + buffer = NULL; + } + + result = check_encoded_data(&encoded_buffer, is_encrypted, &header, &footer, &data); + CU_ASSERT_FATAL(result); + assert(result); // for Clang's static analyzer + + CU_ASSERT(header->transform_identifier.transformation_kind[3] == transformation_kind); + + session_id = ddsrt_bswap4u(*(uint32_t *)header->session_id); + + if (is_encrypted) + { + decoded_buffer._buffer = ddsrt_malloc(plain_buffer._length); + decoded_buffer._length = 0; + decoded_buffer._maximum = plain_buffer._length; + + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, &decoded_buffer, footer->common_mac); + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + CU_ASSERT(memcmp(plain_buffer._buffer, decoded_buffer._buffer, plain_buffer._length) == 0); + + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + } + else + { + result = crypto_decrypt_data(session_id, header->session_id, header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, NULL, footer->common_mac); + + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(memcmp(plain_buffer._buffer, data._buffer, plain_buffer._length) == 0); + } + + printf("num hmacs = %u\n", footer->length); + + CU_ASSERT(check_reader_signing(&reader_list, footer, session_id, header->session_id, session_keys->key_size)); + + for (i = 0; i < READERS_CNT; i++) + { + unregister_datareader(reader_list._buffer[i]); + reader_list._buffer[i] = 0; + } + + unregister_datawriter(writer_crypto); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + + ddsrt_free(datawriter_properties._buffer[0].name); + ddsrt_free(datawriter_properties._buffer[0].value); + ddsrt_free(datawriter_properties._buffer); + ddsrt_free(footer); + ddsrt_free(header); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, encode_sign_256, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES256_GCM); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, encode_sign_128, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES128_GCM); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, no_encode_sign_256, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, no_encode_sign_128, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + encode_datawriter_submessage_sign(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC); +} + +CU_Test(ddssec_builtin_encode_datawriter_submessage, invalid_args, .init = suite_encode_datawriter_submessage_init, .fini = suite_encode_datawriter_submessage_fini) +{ + DDS_Security_boolean result; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + DDS_Security_DatareaderCryptoHandleSeq empty_reader_list; + int32_t index; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_datawriter_submessage != NULL); + + prepare_endpoint_security_attributes_and_properties(&datawriter_security_attributes, &datawriter_properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + + initialize_data_submessage(&plain_buffer, false); + memset(&empty_reader_list, 0, sizeof(empty_reader_list)); + + writer_crypto = register_local_datawriter(&datawriter_security_attributes, &datawriter_properties); + CU_ASSERT_FATAL(writer_crypto != 0); + + //set_protection_kind(writer_crypto, DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION); + + reader_crypto = register_remote_datareader(writer_crypto); + CU_ASSERT_FATAL(reader_crypto != 0); + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_DatareaderCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = reader_crypto; + index = 0; + + /* encoded_buffer NULL */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + NULL, + &plain_buffer, + writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* plain_buffer NULL */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + NULL, + writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto 0 */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + 0, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto unknown */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + 1, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* reader crypto list NULL*/ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + NULL, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* empty reader crypto list */ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &empty_reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* reader crypto list with invalid reader crypto */ + reader_list._buffer[0] = 0; + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* reader crypto list with unknown reader crypto*/ + reader_list._buffer[0] = 1; + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + reader_list._buffer[0] = reader_crypto; + + /* index NULL*/ + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &reader_list, + NULL, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid index */ + index = 2; + result = crypto->crypto_transform->encode_datawriter_submessage( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + writer_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_datawriter_submessage: %s\n", exception.message ? exception.message : "Error message missing"); + } + + unregister_datareader(reader_list._buffer[0]); + reader_list._buffer[0] = 0; + + unregister_datawriter(writer_crypto); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + ddsrt_free(datawriter_properties._buffer[0].name); + ddsrt_free(datawriter_properties._buffer[0].value); + ddsrt_free(datawriter_properties._buffer); + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); +} + diff --git a/src/security/builtin_plugins/tests/encode_rtps_message/src/encode_rtps_message_utests.c b/src/security/builtin_plugins/tests/encode_rtps_message/src/encode_rtps_message_utests.c new file mode 100644 index 0000000..c6d6244 --- /dev/null +++ b/src/security/builtin_plugins/tests/encode_rtps_message/src/encode_rtps_message_utests.c @@ -0,0 +1,1304 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_key_factory.h" +#include "crypto_objects.h" +#include "crypto_utils.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identities[] = {2, 3, 4, 5}; + +static DDS_Security_ParticipantCryptoHandle local_particpant_crypto = 0; +static DDS_Security_ParticipantCryptoHandle remote_particpant_cryptos[sizeof(remote_participant_identities) / sizeof(remote_participant_identities[0])]; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static const char *sample_test_data = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy"; + +static const char *RTPS_HEADER = "RTPS abcdefghijklmno"; + +struct submsg_header +{ + unsigned char id; + unsigned char flags; + uint16_t length; +}; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[sizeof(remote_participant_identities) / sizeof(remote_participant_identities[0])]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + uint32_t length; +}; + +#if 0 +struct receiver_specific_mac +{ + DDS_Security_CryptoTransformKeyId receiver_mac_key_id; + unsigned char receiver_mac[CRYPTO_HMAC_SIZE]; +}; +#endif + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void print_octets(const char *msg, const unsigned char *data, uint32_t sz) +{ + uint32_t i; + printf("%s: ", msg); + for (i = 0; i < sz; i++) + { + printf("%02x", data[i]); + } + printf("\n"); +} + +static int register_local_participant(DDS_Security_ParticipantSecurityAttributes *participant_security_attributes, DDS_Security_PropertySeq *participant_properties) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 2; /* dummy but valid */ + + local_particpant_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + participant_properties, + participant_security_attributes, + &exception); + + if (local_particpant_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_particpant_crypto ? 0 : -1; +} + +static void unregister_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (local_particpant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_particpant_crypto, &exception); + reset_exception(&exception); + } +} + +static int register_remote_participants(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + unsigned i; + int result = 0; + + for (i = 0; i < sizeof(remote_particpant_cryptos) / sizeof(remote_particpant_cryptos[0]); ++i) + { + remote_particpant_cryptos[i] = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_particpant_crypto, + remote_participant_identities[i], + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_particpant_cryptos[i] == 0) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + result = 1; + break; + } + } + + return result; +} + +static void +unregister_remote_participants(void) +{ + unsigned i; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + for (i = 0; i < sizeof(remote_particpant_cryptos) / sizeof(remote_particpant_cryptos[0]); ++i) + { + if (remote_particpant_cryptos[i]) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_particpant_cryptos[i], &exception); + reset_exception(&exception); + } + } +} + +static bool check_encoded_data(DDS_Security_OctetSeq *data, bool encrypted, struct crypto_header **header, struct crypto_footer **footer, DDS_Security_OctetSeq *contents) +{ + struct submsg_header *prefix; + struct submsg_header *postfix; + struct submsg_header *body; + unsigned char *ptr = data->_buffer; + uint32_t remain = data->_length; + uint32_t hlen, clen, dlen; + int swap; + + if (remain < 20) + { + printf("check_encoded_data: RTPS header missing\n"); + goto fail_prefix; + } + + /* rtps header first */ + if (memcmp(ptr, RTPS_HEADER, strlen(RTPS_HEADER)) != 0) + { + printf("check_encoded_data: RTPS header invalid\n"); + goto fail_prefix; + } + + if (remain < sizeof(struct submsg_header)) + { + printf("check_encoded_data: prefix missing\n"); + goto fail_prefix; + } + + remain -= 20; /* rtps header */ + ptr += 20; + + prefix = (struct submsg_header *)ptr; + + if (prefix->id != SMID_SRTPS_PREFIX_KIND) + { + printf("check_encoded_data: prefix incorrect smid 0x%x02\n", prefix->id); + goto fail_prefix; + } + + if (prefix->flags & 0x01) + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + + hlen = swap ? ddsrt_bswap2u(prefix->length) : prefix->length; + + if (hlen != sizeof(struct crypto_header)) + { + printf("check_encoded_data: crypto_header missing\n"); + goto fail_prefix; + } + + ptr += sizeof(struct submsg_header); + remain -= (uint32_t)sizeof(struct submsg_header); + + if (remain < sizeof(struct crypto_header)) + { + printf("check_encoded_data: crypto_header too short\n"); + goto fail_prefix; + } + + *header = ddsrt_malloc(sizeof(struct crypto_header)); + memcpy(*header, ptr, sizeof(struct crypto_header)); + + ptr += sizeof(struct crypto_header); + remain -= (uint32_t)sizeof(struct crypto_header); + + if (remain < sizeof(struct submsg_header)) + { + goto fail_body; + } + + if (encrypted) + { + body = (struct submsg_header *)ptr; + if (body->id != SMID_SEC_BODY_KIND) + { + printf("check_encoded_data: submessage SEC_BODY missing\n"); + goto fail_body; + } + ptr += sizeof(struct submsg_header); + remain -= (uint32_t)sizeof(struct submsg_header); + + dlen = ddsrt_fromBE4u(*(uint32_t *)ptr); + + clen = swap ? ddsrt_bswap2u(body->length) : body->length; + if (dlen > clen) + { + printf("check_encoded_data: encrypted body length incorrect\n"); + goto fail_body; + } + + ptr += sizeof(uint32_t); + remain -= (uint32_t)sizeof(uint32_t); + + contents->_length = contents->_maximum = dlen; + contents->_buffer = ptr; + + ptr += clen - sizeof(uint32_t); + } + else + { + body = (struct submsg_header *)(ptr + 24); /* header after info_src */ + if (body->id == SMID_SEC_BODY_KIND) + { + printf("check_encoded_data: submessage SEC_BODY not expected\n"); + goto fail_body; + } + clen = swap ? ddsrt_bswap2u(body->length) : body->length; + clen += (uint32_t)sizeof(struct submsg_header) + 24; + + contents->_length = contents->_maximum = clen; + contents->_buffer = ptr; + + ptr += clen; + } + + if (clen > remain) + { + printf("check_encoded_data: payload invalid size\n"); + goto fail_body; + } + + remain -= contents->_length; + + if (remain < sizeof(struct submsg_header)) + { + printf("check_encoded_data: postfix missing\n"); + goto fail_postfix; + } + + postfix = (struct submsg_header *)ptr; + + if (postfix->id != SMID_SRTPS_POSTFIX_KIND) + { + printf("check_encoded_data: postfix invalid smid\n"); + goto fail_postfix; + } + + ptr += sizeof(struct submsg_header); + remain -= (uint32_t)sizeof(struct submsg_header); + + if (remain < CRYPTO_HMAC_SIZE + sizeof(uint32_t)) + { + printf("check_encoded_data: crypto_footer incorrect size\n"); + goto fail_postfix; + } + + *footer = ddsrt_malloc(remain); + memcpy(*footer, ptr, remain); + + /* length of reader specific macs is in BIG-ENDIAN format */ + (*footer)->length = ddsrt_fromBE4u((*footer)->length); + + return true; + +fail_postfix: +fail_body: + ddsrt_free(*header); +fail_prefix: + return false; +} + +static bool +cipher_sign_data( + const unsigned char *session_key, + uint32_t key_size, + const unsigned char *iv, + const unsigned char *data, + uint32_t data_len, + unsigned char *tag) +{ + EVP_CIPHER_CTX *ctx; + unsigned char temp[32]; + int len; + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (!ctx) + { + ERR_print_errors_fp(stderr); + goto fail_ctx_new; + } + + /* initialize the cipher and set to AES GCM */ + if (key_size == 128) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + } + else if (key_size == 256) + { + if (!EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + } + + /* Initialise key and IV */ + if (!EVP_EncryptInit_ex(ctx, NULL, NULL, session_key, iv)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + if (!EVP_EncryptUpdate(ctx, NULL, &len, data, (int) data_len)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + if (!EVP_EncryptFinal_ex(ctx, temp, &len)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + /* get the tag */ + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, CRYPTO_HMAC_SIZE, tag)) + { + ERR_print_errors_fp(stderr); + goto fail_encrypt; + } + + /* clean up */ + EVP_CIPHER_CTX_free(ctx); + + return true; + +fail_encrypt: + EVP_CIPHER_CTX_free(ctx); +fail_ctx_new: + return false; +} + +static bool +crypto_decrypt_data( + uint32_t session_id, + unsigned char *iv, + DDS_Security_CryptoTransformKind transformation_kind, + master_key_material *key_material, + DDS_Security_OctetSeq *encrypted, + DDS_Security_OctetSeq *decoded, + unsigned char *tag) +{ + bool result = true; + EVP_CIPHER_CTX *ctx; + crypto_session_key_t session_key; + uint32_t key_size = crypto_get_key_size(CRYPTO_TRANSFORM_KIND(transformation_kind)); + int len = 0; + + if (!crypto_calculate_session_key_test(&session_key, session_id, key_material->master_salt, key_material->master_sender_key, key_material->transformation_kind)) + return false; + + printf("SessionId: %08x\n", session_id); + print_octets("SessionKey", (const unsigned char *)session_key.data, key_size >> 3); + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (ctx) + { + if (key_size == 128) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else if (key_size == 256) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (result) + { + if (!EVP_DecryptInit_ex(ctx, NULL, NULL, session_key.data, iv)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptUpdate(ctx, decoded->_buffer, &len, encrypted->_buffer, (int) encrypted->_length)) + { + decoded->_length = (uint32_t) len; + } + else + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + if (!EVP_DecryptUpdate(ctx, NULL, &len, encrypted->_buffer, (int) encrypted->_length)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (result) + { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, CRYPTO_HMAC_SIZE, tag)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptFinal_ex(ctx, decoded->_buffer + len, &len)) + { + decoded->_length += (uint32_t) len; + } + else + { + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + unsigned char temp[32]; + if (!EVP_DecryptFinal_ex(ctx, temp, &len)) + { + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (ctx) + EVP_CIPHER_CTX_free(ctx); + + return result; +} + +static session_key_material * get_local_participant_session(DDS_Security_ParticipantCryptoHandle participant_crypto) +{ + local_participant_crypto *participant_crypto_impl = (local_participant_crypto *)participant_crypto; + return participant_crypto_impl->session; +} + +static master_key_material * get_remote_participant_key_material(DDS_Security_ParticipantCryptoHandle participant_crypto) +{ + return crypto_factory_get_master_key_material_for_test(crypto->crypto_key_factory, local_particpant_crypto, participant_crypto); +} + +static void set_protection_kind(DDS_Security_ParticipantCryptoHandle participant_crypto, DDS_Security_ProtectionKind protection_kind) +{ + local_participant_crypto *paricipant_crypto_impl = (local_participant_crypto *)participant_crypto; + paricipant_crypto_impl->rtps_protection_kind = protection_kind; +} + +static void set_remote_participant_protection_kind(DDS_Security_ParticipantCryptoHandle participant_crypto, DDS_Security_ProtectionKind protection_kind) +{ + remote_participant_crypto *paricipant_crypto_impl = (remote_participant_crypto *)participant_crypto; + paricipant_crypto_impl->rtps_protection_kind = protection_kind; +} + +static void initialize_rtps_message(DDS_Security_OctetSeq *submsg, bool be) +{ + size_t length = strlen(sample_test_data) + 1; + struct submsg_header *header; + int swap; + unsigned char *buffer, *ptr; + + if (be) + swap = (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN); + else + swap = (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + + buffer = ddsrt_malloc(length + 20 + sizeof(struct submsg_header)); + memcpy(buffer, RTPS_HEADER, 20); + + header = (struct submsg_header *)(buffer + 20); + header->id = 0x15; + header->flags = be ? 0x00 : 0x01; + header->length = swap ? ddsrt_bswap2u((uint16_t) length) : (uint16_t) length; + + ptr = (unsigned char *)(header + 1); + memcpy((char *)ptr, sample_test_data, length); + + submsg->_length = submsg->_maximum = (uint32_t) (20 + length + sizeof(struct submsg_header)); + submsg->_buffer = buffer; +} + +static bool check_sign(DDS_Security_ParticipantCryptoHandle participant_crypto, uint32_t session_id, uint32_t key_id, uint32_t key_size, unsigned char *init_vector, unsigned char *common_mac, unsigned char *hmac) +{ + master_key_material *keymat; + crypto_session_key_t key; + unsigned char md[CRYPTO_HMAC_SIZE]; + + memset(md, 0, CRYPTO_HMAC_SIZE); + + keymat = get_remote_participant_key_material(participant_crypto); + if (key_id != keymat->receiver_specific_key_id) + { + printf("check_sign: key_id(%d) does not match key_mat(%d)\n", (int)key_id, (int)keymat->receiver_specific_key_id); + return false; + } + else if (!calculate_receiver_specific_key_test(&key, session_id, keymat->master_salt, keymat->master_receiver_specific_key, keymat->transformation_kind)) + { + printf("check_sign: calculate key failed\n"); + return false; + } + else if (!cipher_sign_data(key.data, key_size, init_vector, common_mac, CRYPTO_HMAC_SIZE, md)) + { + return false; + } + else if (memcmp(hmac, md, CRYPTO_HMAC_SIZE) != 0) + { + printf("check_sign: hmac incorrect\n"); + + //print_octets("Reader Specific Key:", key, CRYPTO_KEY_SIZE); + //print_octets("Common:", common_mac, CRYPTO_HMAC_SIZE); + //print_octets("Hmac:", hmac, CRYPTO_HMAC_SIZE); + //print_octets("MD:", md, CRYPTO_HMAC_SIZE); + return false; + } + + return true; +} + +static bool check_signing( + DDS_Security_ParticipantCryptoHandleSeq *list, + struct crypto_footer *footer, + uint32_t session_id, + unsigned char *init_vector, + uint32_t key_size) +{ + struct receiver_specific_mac *rmac; + uint32_t key_id; + uint32_t i; + + if (footer->length != list->_length) + { + return false; + } + + rmac = (struct receiver_specific_mac *)(footer + 1); + + for (i = 0; i < list->_length; i++) + { + key_id = ddsrt_bswap4u(*(uint32_t *)rmac[i].receiver_mac_key_id); + if (!check_sign(list->_buffer[i], session_id, key_id, key_size, init_vector, footer->common_mac, rmac[i].receiver_mac.data)) + { + return false; + } + } + + return true; +} + +static void suite_encode_rtps_message_init(void) +{ + allocate_shared_secret(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); +} + +static void suite_encode_rtps_message_fini(void) +{ + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void prepare_participant_security_attributes_and_properties( + DDS_Security_ParticipantSecurityAttributes *attributes, + DDS_Security_PropertySeq *properties, + DDS_Security_CryptoTransformKind_Enum transformation_kind, + bool is_origin_authenticated) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + memset(properties, 0, sizeof(DDS_Security_PropertySeq)); + + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + + properties->_maximum = properties->_length = 1; + properties->_buffer = ddsrt_malloc(sizeof(DDS_Security_Property_t)); + + properties->_buffer[0].name = ddsrt_strdup("dds.sec.crypto.keysize"); + if (transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GCM || transformation_kind == CRYPTO_TRANSFORMATION_KIND_AES128_GMAC) + { + properties->_buffer[0].value = ddsrt_strdup("128"); + } + else + { + properties->_buffer[0].value = ddsrt_strdup("256"); + } + + switch (transformation_kind) + { + case CRYPTO_TRANSFORMATION_KIND_AES128_GCM: + case CRYPTO_TRANSFORMATION_KIND_AES256_GCM: + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; + if (is_origin_authenticated) + { + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED; + } + break; + + case CRYPTO_TRANSFORMATION_KIND_AES256_GMAC: + case CRYPTO_TRANSFORMATION_KIND_AES128_GMAC: + attributes->is_rtps_protected = true; + if (is_origin_authenticated) + { + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED; + } + break; + + default: + assert(0); + break; + } +} + +static void encode_rtps_message_not_authenticated(DDS_Security_CryptoTransformKind_Enum transformation_kind, uint32_t key_size, bool encrypted) +{ + DDS_Security_boolean result; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + int32_t index; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + DDS_Security_OctetSeq data; + session_key_material *session_keys; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + uint32_t session_id; + DDS_Security_ParticipantSecurityAttributes attributes; + DDS_Security_PropertySeq properties; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_rtps_message != NULL); + + prepare_participant_security_attributes_and_properties(&attributes, &properties, transformation_kind, false); + + register_local_participant(&attributes, &properties); + + initialize_rtps_message(&plain_buffer, false); + + session_keys = get_local_participant_session(local_particpant_crypto); + + session_keys->master_key_material->transformation_kind = transformation_kind; + session_keys->key_size = key_size; + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_ParticipantCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_particpant_cryptos[0]; + index = 0; + + /* Now call the function. */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_particpant_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + assert(result); // for Clang's static analyzer + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + + result = check_encoded_data(&encoded_buffer, encrypted, &header, &footer, &data); + CU_ASSERT_FATAL(result); + assert(result); // for Clang's static analyzer + + CU_ASSERT(header->transform_identifier.transformation_kind[3] == transformation_kind); + + session_id = ddsrt_bswap4u(*(uint32_t *)header->session_id); + + if (encrypted) + { + decoded_buffer._buffer = ddsrt_malloc(plain_buffer._length + 24); /* info_src is added */ + decoded_buffer._length = 0; + decoded_buffer._maximum = plain_buffer._length + 24; /* info_src is added */ + + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, &decoded_buffer, footer->common_mac); + + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + //print_octets( "PLAIN RTPS:",plain_buffer._buffer+4, plain_buffer._length-4); + //print_octets( "DECODED RTPS:",decoded_buffer._buffer+8, decoded_buffer._length-8); + + CU_ASSERT_FATAL(memcmp(plain_buffer._buffer + 4, decoded_buffer._buffer + 8, plain_buffer._length - 4) == 0); + + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + } + else + { + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, NULL, footer->common_mac); + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + CU_ASSERT_FATAL(memcmp(plain_buffer._buffer + 4, data._buffer + 8, plain_buffer._length - 4) == 0); + } + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + + ddsrt_free(footer); + ddsrt_free(header); + + DDS_Security_PropertySeq_deinit(&properties); + unregister_local_participant(); +} + +CU_Test(ddssec_builtin_encode_rtps_message, encrypt_256, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES256_GCM, 256, true); +} + +CU_Test(ddssec_builtin_encode_rtps_message, encrypt_128, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES128_GCM, 128, true); +} + +CU_Test(ddssec_builtin_encode_rtps_message, no_encrypt_256, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, 256, false); +} + +CU_Test(ddssec_builtin_encode_rtps_message, no_encrypt_128, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_not_authenticated(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC, 128, false); +} + +static void encode_rtps_message_sign(DDS_Security_CryptoTransformKind_Enum transformation_kind, uint32_t key_size, DDS_Security_ProtectionKind protection_kind, bool encoded) +{ + DDS_Security_boolean result; + DDS_Security_DatareaderCryptoHandleSeq reader_list; + int32_t index; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_OctetSeq decoded_buffer; + DDS_Security_OctetSeq data; + DDS_Security_OctetSeq *buffer; + session_key_material *session_keys; + DDS_Security_ParticipantSecurityAttributes attributes; + DDS_Security_PropertySeq properties; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + uint32_t session_id; + size_t i; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_rtps_message != NULL); + + prepare_participant_security_attributes_and_properties(&attributes, &properties, transformation_kind, true); + + register_local_participant(&attributes, &properties); + + initialize_rtps_message(&plain_buffer, false); + + CU_ASSERT_FATAL(local_particpant_crypto != 0); + + session_keys = get_local_participant_session(local_particpant_crypto); + session_keys->master_key_material->transformation_kind = transformation_kind; + session_keys->key_size = key_size; + set_protection_kind(local_particpant_crypto, protection_kind); + + register_remote_participants(); + + reader_list._length = reader_list._maximum = (uint32_t) (sizeof(remote_particpant_cryptos) / sizeof(remote_particpant_cryptos[0])); + reader_list._buffer = DDS_Security_ParticipantCryptoHandleSeq_allocbuf(reader_list._maximum); + for (i = 0; i < sizeof(remote_particpant_cryptos) / sizeof(remote_particpant_cryptos[0]); i++) + { + set_remote_participant_protection_kind(remote_particpant_cryptos[i], protection_kind); + reader_list._buffer[i] = remote_particpant_cryptos[i]; + } + index = 0; + + /* Now call the function. */ + + buffer = &plain_buffer; + while ((uint32_t) index != reader_list._length) + { + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + buffer, + local_particpant_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); + buffer = NULL; + } + + result = check_encoded_data(&encoded_buffer, encoded, &header, &footer, &data); + CU_ASSERT_FATAL(result); + + CU_ASSERT(header->transform_identifier.transformation_kind[3] == transformation_kind); + + session_id = ddsrt_bswap4u(*(uint32_t *)header->session_id); + + if (encoded) + { + decoded_buffer._buffer = ddsrt_malloc(plain_buffer._length + 24); /* info_src is added */ + decoded_buffer._length = 0; + decoded_buffer._maximum = plain_buffer._length + 24; /* info_src is added */ + + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, &decoded_buffer, footer->common_mac); + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + + /*TODO: this should consider INFO_SRC */ + CU_ASSERT(memcmp(plain_buffer._buffer + 4, decoded_buffer._buffer + 8, plain_buffer._length - 4) == 0); + + DDS_Security_OctetSeq_deinit((&decoded_buffer)); + } + else + { + result = crypto_decrypt_data(session_id, header->session_id, header->transform_identifier.transformation_kind, + session_keys->master_key_material, &data, NULL, footer->common_mac); + + if (!result) + { + printf("Decode failed\n"); + } + + CU_ASSERT_FATAL(result); + CU_ASSERT(memcmp(plain_buffer._buffer + 4, data._buffer + 8, plain_buffer._length - 4) == 0); + } + + printf("num hmacs = %u\n", footer->length); + + CU_ASSERT(check_signing(&reader_list, footer, session_id, header->session_id, session_keys->key_size)); + + unregister_remote_participants(); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_OctetSeq_deinit((&encoded_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + DDS_Security_PropertySeq_deinit(&properties); + + ddsrt_free(footer); + ddsrt_free(header); + + unregister_local_participant(); +} + +CU_Test(ddssec_builtin_encode_rtps_message, encrypt_sign_256, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_sign(CRYPTO_TRANSFORMATION_KIND_AES256_GCM, 256, DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION, true); +} + +CU_Test(ddssec_builtin_encode_rtps_message, encrypt_sign_128, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_sign(CRYPTO_TRANSFORMATION_KIND_AES128_GCM, 128, DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION, true); +} + +CU_Test(ddssec_builtin_encode_rtps_message, no_encrypt_sign_256, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_sign(CRYPTO_TRANSFORMATION_KIND_AES256_GMAC, 256, DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION, false); +} + +CU_Test(ddssec_builtin_encode_rtps_message, no_encrypt_sign_128, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + encode_rtps_message_sign(CRYPTO_TRANSFORMATION_KIND_AES128_GMAC, 128, DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION, false); +} + +CU_Test(ddssec_builtin_encode_rtps_message, invalid_args, .init = suite_encode_rtps_message_init, .fini = suite_encode_rtps_message_fini) +{ + DDS_Security_boolean result; + DDS_Security_ParticipantCryptoHandleSeq reader_list; + DDS_Security_ParticipantCryptoHandleSeq empty_reader_list; + int32_t index; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq encoded_buffer; + DDS_Security_ParticipantSecurityAttributes attributes; + DDS_Security_PropertySeq properties; + unsigned i; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_rtps_message != NULL); + + prepare_participant_security_attributes_and_properties(&attributes, &properties, CRYPTO_TRANSFORMATION_KIND_AES256_GCM, true); + + register_local_participant(&attributes, &properties); + + initialize_rtps_message(&plain_buffer, false); + memset(&empty_reader_list, 0, sizeof(empty_reader_list)); + + CU_ASSERT_FATAL(local_particpant_crypto != 0); + assert(local_particpant_crypto != 0); // for Clang's static analyzer + + register_remote_participants(); + for (i = 0; i < sizeof (remote_particpant_cryptos) / sizeof (remote_particpant_cryptos[0]); i++) + { + assert (remote_particpant_cryptos[i]); // for Clang's static analyzer + set_remote_participant_protection_kind(remote_particpant_cryptos[i], DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION); + } + + CU_ASSERT_FATAL(remote_particpant_cryptos[0] != 0); + assert(remote_particpant_cryptos[0] != 0); // for Clang's static analyzer + + reader_list._length = reader_list._maximum = 1; + reader_list._buffer = DDS_Security_ParticipantCryptoHandleSeq_allocbuf(1); + reader_list._buffer[0] = remote_particpant_cryptos[0]; + index = 0; + + /* encoded_buffer NULL */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + NULL, + &plain_buffer, + local_particpant_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* plain_buffer NULL */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + NULL, + local_particpant_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto 0 */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + 0, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* writer crypto unknown */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + 1, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* reader crypto list NULL*/ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_particpant_crypto, + NULL, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* empty reader crypto list */ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_particpant_crypto, + &empty_reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* reader crypto list with invalid reader crypto */ + reader_list._buffer[0] = 0; + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_particpant_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* reader crypto list with unknown reader crypto*/ + reader_list._buffer[0] = 1; + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_particpant_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + reader_list._buffer[0] = local_particpant_crypto; + + /* index NULL*/ + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_particpant_crypto, + &reader_list, + NULL, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid index */ + index = 2; + result = crypto->crypto_transform->encode_rtps_message( + crypto->crypto_transform, + &encoded_buffer, + &plain_buffer, + local_particpant_crypto, + &reader_list, + &index, + &exception); + + if (!result) + { + printf("encode_rtps_message: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + unregister_remote_participants(); + + reset_exception(&exception); + + DDS_Security_OctetSeq_deinit((&plain_buffer)); + DDS_Security_DatareaderCryptoHandleSeq_deinit(&reader_list); + DDS_Security_PropertySeq_deinit(&properties); + + unregister_local_participant(); +} + diff --git a/src/security/builtin_plugins/tests/encode_serialized_payload/src/encode_serialized_payload_utests.c b/src/security/builtin_plugins/tests/encode_serialized_payload/src/encode_serialized_payload_utests.c new file mode 100644 index 0000000..302972b --- /dev/null +++ b/src/security/builtin_plugins/tests/encode_serialized_payload/src/encode_serialized_payload_utests.c @@ -0,0 +1,787 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_objects.h" +#include "crypto_utils.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle g_local_participant_identity = 1; +static DDS_Security_IdentityHandle g_remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle g_local_participant_crypto = 0; +static DDS_Security_ParticipantCryptoHandle g_remote_participant_crypto = 0; + +static DDS_Security_SharedSecretHandle g_shared_secret_handle = DDS_SECURITY_HANDLE_NIL; + +static const char *SAMPLE_TEST_DATA = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxy"; + +struct crypto_header +{ + struct CryptoTransformIdentifier transform_identifier; + unsigned char session_id[4]; + unsigned char init_vector_suffix[8]; +}; + +struct crypto_footer +{ + unsigned char common_mac[16]; + uint32_t length; +}; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void allocate_shared_secret(void) +{ + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + g_shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = (DDS_Security_SharedSecretHandleImpl *)g_shared_secret_handle; + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + g_local_participant_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + g_local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (g_local_participant_crypto == 0) + { + printf("[ERROR] register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return g_local_participant_crypto ? 0 : -1; +} + +static void unregister_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (g_local_participant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, g_local_participant_crypto, &exception); + reset_exception(&exception); + } +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + g_remote_participant_crypto = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + g_local_participant_crypto, + g_remote_participant_identity, + remote_participant_permissions, + g_shared_secret_handle, + &exception); + + if (g_remote_participant_crypto == 0) + { + printf("[ERROR] register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return g_remote_participant_crypto ? 0 : -1; +} + +static void unregister_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (g_remote_participant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, g_remote_participant_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatawriterCryptoHandle register_local_datawriter(bool encrypted) +{ + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + memset(&datawriter_security_attributes, 0, sizeof(datawriter_security_attributes)); + datawriter_security_attributes.is_payload_protected = true; + if (encrypted) + { + datawriter_security_attributes.plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + } + + writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + g_local_participant_crypto, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + if (writer_crypto == 0) + { + printf("[ERROR] register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return writer_crypto; +} + +static void unregister_local_datawriter(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, writer_crypto, &exception); + reset_exception(&exception); + } +} + +static DDS_Security_DatareaderCryptoHandle register_remote_datareader(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + writer_crypto, + g_remote_participant_crypto, + g_shared_secret_handle, + true, + &exception); + + if (reader_crypto == 0) + { + printf("[ERROR] register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return reader_crypto; +} + +static void unregister_remote_datareader(DDS_Security_DatareaderCryptoHandle reader_crypto) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + if (reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, reader_crypto, &exception); + reset_exception(&exception); + } +} + +static bool split_encoded_data(unsigned char *data, uint32_t size, struct crypto_header **header, DDS_Security_OctetSeq *payload, struct crypto_footer **footer, bool encrypted) +{ + /* The length is the length of the encrypted data and the common_mac of the footer + * For the serialized payload the footer consists of the common_mac and the length + * of the receiver_specific_mac which is set to 0 */ + static const uint32_t FOOTER_SIZE = 20; + unsigned char *header_ptr; + unsigned char *payload_ptr; + unsigned char *footer_ptr; + uint32_t payload_size; + + if (size < (sizeof(struct crypto_header) + FOOTER_SIZE)) + { + return false; + } + + header_ptr = data; + payload_ptr = data + sizeof(struct crypto_header); + footer_ptr = data + size - FOOTER_SIZE; + + /* Get header. */ + *header = (struct crypto_header *)header_ptr; + + /* Get payload */ + payload_size = (uint32_t)(footer_ptr - payload_ptr); + if (encrypted) + { + /* CryptoContent starts with 4 bytes length. */ + if (payload_size < 4) + { + return false; + } + payload->_length = ddsrt_fromBE4u(*(uint32_t *)payload_ptr); + payload->_buffer = payload_ptr + 4; + if ((payload_size - 4) != payload->_length) + { + return false; + } + } + else + { + /* Just the clear payload */ + payload->_length = payload_size; + payload->_buffer = payload_ptr; + } + payload->_maximum = payload->_length; + + /* Get footer. */ + *footer = (struct crypto_footer *)footer_ptr; + + return true; +} + +static bool crypto_decrypt_data(uint32_t session_id, unsigned char *iv, DDS_Security_CryptoTransformKind transformation_kind, master_key_material *key_material, DDS_Security_OctetSeq *encrypted, DDS_Security_OctetSeq *decoded, unsigned char *tag) +{ + bool result = true; + EVP_CIPHER_CTX *ctx; + crypto_session_key_t session_key; + uint32_t key_size = crypto_get_key_size(CRYPTO_TRANSFORM_KIND(transformation_kind)); + int len = 0; + + if (!crypto_calculate_session_key_test(&session_key, session_id, key_material->master_salt, key_material->master_sender_key, key_material->transformation_kind)) + { + printf("[ERROR] (%d) crypto_decrypt_data: could not calculate session key!\n", __LINE__); + return false; + } + + /* create the cipher context */ + ctx = EVP_CIPHER_CTX_new(); + if (ctx) + { + if (key_size == 128) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) + { + printf("[ERROR] (%d) crypto_decrypt_data: could not get init CIPHER_CTX (128)\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + else if (key_size == 256) + { + if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) + { + printf("[ERROR] (%d) crypto_decrypt_data: could not get init CIPHER_CTX (256)\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + printf("[ERROR] (%d) crypto_decrypt_data: could not determine keysize\n", __LINE__); + result = false; + } + } + else + { + printf("[ERROR] (%d) crypto_decrypt_data: could not get new CIPHER_CTX\n", __LINE__); + result = false; + } + + if (result) + { + if (!EVP_DecryptInit_ex(ctx, NULL, NULL, session_key.data, iv)) + { + printf("[ERROR] (%d) crypto_decrypt_data: could not init Decrypt\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptUpdate(ctx, decoded->_buffer, &len, encrypted->_buffer, (int) encrypted->_length)) + { + decoded->_length = (uint32_t) len; + } + else + { + printf("[ERROR] (%d) crypto_decrypt_data: could not update Decrypt (decoded)\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + if (!EVP_DecryptUpdate(ctx, NULL, &len, encrypted->_buffer, (int) encrypted->_length)) + { + printf("[ERROR] (%d) crypto_decrypt_data: could not update Decrypt (!decoded)\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (result) + { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, CRYPTO_HMAC_SIZE, tag)) + { + printf("[ERROR] (%d) crypto_decrypt_data: could not ctrl CIPHER_CTX\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + + if (result) + { + if (decoded) + { + if (EVP_DecryptFinal_ex(ctx, decoded->_buffer + len, &len)) + { + decoded->_length += (uint32_t) len; + } + else + { + printf("[ERROR] (%d) crypto_decrypt_data: could not finalize Decrypt (decoded)\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + else + { + unsigned char temp[32]; + if (!EVP_DecryptFinal_ex(ctx, temp, &len)) + { + printf("[ERROR] (%d) crypto_decrypt_data: could not finalize Decrypt (!decoded)\n", __LINE__); + ERR_print_errors_fp(stderr); + result = false; + } + } + } + + if (ctx) + EVP_CIPHER_CTX_free(ctx); + + return result; +} + +static session_key_material * get_datawriter_session(DDS_Security_DatawriterCryptoHandle writer_crypto) +{ + local_datawriter_crypto *writer_crypto_impl = (local_datawriter_crypto *)writer_crypto; + return writer_crypto_impl->writer_session_payload; +} + +static bool check_protection_kind(DDS_Security_DatawriterCryptoHandle writer_crypto, DDS_Security_BasicProtectionKind protection_kind) +{ + local_datawriter_crypto *writer_crypto_impl = (local_datawriter_crypto *)writer_crypto; + return (writer_crypto_impl->data_protectionKind == protection_kind); +} + +static void suite_encode_serialized_payload_init(void) +{ + allocate_shared_secret(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); +} + +static void suite_encode_serialized_payload_fini(void) +{ + unregister_remote_participant(); + unregister_local_participant(); + unload_plugins(plugins); + deallocate_shared_secret(); +} + +static uint32_t get_transformation_kind(uint32_t key_size, bool encrypted) +{ + uint32_t kind = CRYPTO_TRANSFORMATION_KIND_INVALID; + if (key_size == 128) + { + kind = encrypted ? CRYPTO_TRANSFORMATION_KIND_AES128_GCM : CRYPTO_TRANSFORMATION_KIND_AES128_GMAC; + } + else if (key_size == 256) + { + kind = encrypted ? CRYPTO_TRANSFORMATION_KIND_AES256_GCM : CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; + } + CU_ASSERT_FATAL(kind != CRYPTO_TRANSFORMATION_KIND_INVALID); + return kind; +} + +static bool seq_equal(DDS_Security_OctetSeq *seq1, DDS_Security_OctetSeq *seq2) +{ + bool ok = false; + if (seq1->_length == seq2->_length) + { + if (memcmp(seq1->_buffer, seq2->_buffer, seq1->_length) == 0) + { + ok = true; + } + } + return ok; +} + +static bool check_payload_signed(DDS_Security_OctetSeq *payload, DDS_Security_OctetSeq *plain_buffer) +{ + /* When only signed, the payload should not have changed. */ + return seq_equal(payload, plain_buffer); +} + +static bool check_payload_encrypted(DDS_Security_OctetSeq *payload, DDS_Security_OctetSeq *plain_buffer) +{ + bool ok = false; + /* When encrypted, the payload should differ from the original data. */ + if (payload->_length >= plain_buffer->_length) + { + if (memcmp(payload->_buffer, plain_buffer->_buffer, plain_buffer->_length) != 0) + { + ok = true; + } + } + return ok; +} + +static bool check_payload_encoded(DDS_Security_OctetSeq *payload, DDS_Security_OctetSeq *plain_buffer, bool encrypted) +{ + bool ok; + if (encrypted) + { + ok = check_payload_encrypted(payload, plain_buffer); + } + else + { + ok = check_payload_signed(payload, plain_buffer); + } + return ok; +} + +static bool check_payload_decoded(DDS_Security_OctetSeq *payload, DDS_Security_OctetSeq *plain_buffer) +{ + /* After decoding, the payload should match the orignal. */ + return seq_equal(payload, plain_buffer); +} + +static void encode_serialized_payload_check(uint32_t key_size, bool encrypted) +{ + DDS_Security_boolean result; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq extra_inline_qos; + DDS_Security_OctetSeq encoded_payload; + DDS_Security_OctetSeq plain_buffer; + session_key_material *session_keys; + struct crypto_header *header = NULL; + struct crypto_footer *footer = NULL; + uint32_t session_id; + size_t length; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_serialized_payload != NULL); + + memset(&extra_inline_qos, 0, sizeof(extra_inline_qos)); + + length = strlen(SAMPLE_TEST_DATA) + 1; + plain_buffer._length = plain_buffer._maximum = (uint32_t) length; + plain_buffer._buffer = DDS_Security_OctetSeq_allocbuf((uint32_t) length); + memcpy((char *)plain_buffer._buffer, SAMPLE_TEST_DATA, length); + + writer_crypto = register_local_datawriter(encrypted); + CU_ASSERT_FATAL(writer_crypto != 0); + assert(writer_crypto != 0); // for Clang's static analyzer + + CU_ASSERT(check_protection_kind(writer_crypto, encrypted ? DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT : DDS_SECURITY_BASICPROTECTION_KIND_SIGN)); + + session_keys = get_datawriter_session(writer_crypto); + session_keys->master_key_material->transformation_kind = get_transformation_kind(key_size, encrypted); + session_keys->key_size = key_size; + + /* Now call the function. */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + &plain_buffer, + writer_crypto, + &exception); + + if (!result) + { + printf("[ERROR] encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT_FATAL(result); + assert(result); // for Clang's static analyzer + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + reset_exception(&exception); + + result = split_encoded_data(encoded_buffer._buffer, encoded_buffer._length, &header, &encoded_payload, &footer, encrypted); + CU_ASSERT_FATAL(result == true); + assert(result); // for Clang's static analyzer + CU_ASSERT(check_payload_encoded(&encoded_payload, &plain_buffer, encrypted)); + + session_id = ddsrt_fromBE4u(*(uint32_t *)header->session_id); + + if (encrypted) + { + DDS_Security_OctetSeq decoded_buffer; + decoded_buffer._buffer = ddsrt_malloc(length); + decoded_buffer._length = (uint32_t) length; + decoded_buffer._maximum = (uint32_t) length; + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, session_keys->master_key_material, &encoded_payload, &decoded_buffer, footer->common_mac); + if (!result) + { + printf("[ERROR] Decryption failed\n"); + } + CU_ASSERT_FATAL(result); + CU_ASSERT(check_payload_decoded(&decoded_buffer, &plain_buffer)); + DDS_Security_OctetSeq_deinit(&decoded_buffer); + } + else + { + result = crypto_decrypt_data(session_id, &header->session_id[0], header->transform_identifier.transformation_kind, session_keys->master_key_material, &encoded_payload, NULL, footer->common_mac); + if (!result) + { + printf("[ERROR] Signature check failed\n"); + } + CU_ASSERT_FATAL(result); + } + + DDS_Security_OctetSeq_deinit(&encoded_buffer); + DDS_Security_OctetSeq_deinit(&plain_buffer); + + unregister_local_datawriter(writer_crypto); +} + +CU_Test(ddssec_builtin_encode_serialized_payload, encrypt_128, .init = suite_encode_serialized_payload_init, .fini = suite_encode_serialized_payload_fini) +{ + encode_serialized_payload_check(128, true); +} + +CU_Test(ddssec_builtin_encode_serialized_payload, encrypt_256, .init = suite_encode_serialized_payload_init, .fini = suite_encode_serialized_payload_fini) +{ + encode_serialized_payload_check(256, true); +} + +CU_Test(ddssec_builtin_encode_serialized_payload, sign_128, .init = suite_encode_serialized_payload_init, .fini = suite_encode_serialized_payload_fini) +{ + encode_serialized_payload_check(128, false); +} + +CU_Test(ddssec_builtin_encode_serialized_payload, sign_256, .init = suite_encode_serialized_payload_init, .fini = suite_encode_serialized_payload_fini) +{ + encode_serialized_payload_check(256, false); +} + +CU_Test(ddssec_builtin_encode_serialized_payload, invalid_args, .init = suite_encode_serialized_payload_init, .fini = suite_encode_serialized_payload_fini) +{ + DDS_Security_boolean result; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq encoded_buffer = {0, 0, NULL}; + DDS_Security_OctetSeq extra_inline_qos; + DDS_Security_OctetSeq plain_buffer; + DDS_Security_OctetSeq empty_buffer; + size_t length; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform != NULL); + CU_ASSERT_FATAL(crypto->crypto_transform->encode_serialized_payload != NULL); + + writer_crypto = register_local_datawriter(true); + CU_ASSERT_FATAL(writer_crypto != 0); + + reader_crypto = register_remote_datareader(writer_crypto); + CU_ASSERT_FATAL(reader_crypto != 0); + + memset(&extra_inline_qos, 0, sizeof(extra_inline_qos)); + memset(&empty_buffer, 0, sizeof(empty_buffer)); + + length = strlen(SAMPLE_TEST_DATA) + 1; + plain_buffer._length = plain_buffer._maximum = (uint32_t) length; + plain_buffer._buffer = DDS_Security_OctetSeq_allocbuf((uint32_t) length); + memcpy((char *)plain_buffer._buffer, SAMPLE_TEST_DATA, length); + + /* no encoded data specified */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + NULL, + &extra_inline_qos, + &plain_buffer, + writer_crypto, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* no plain data specified */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + NULL, + writer_crypto, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + unregister_local_datawriter(writer_crypto); + + /* empty plain data specified */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + &empty_buffer, + writer_crypto, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* unknown writer crypto handle specified */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + &plain_buffer, + 0, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* incorrect writer crypto handle specified */ + result = crypto->crypto_transform->encode_serialized_payload( + crypto->crypto_transform, + &encoded_buffer, + &extra_inline_qos, + &plain_buffer, + reader_crypto, + &exception); + + if (!result) + { + printf("encode_serialized_payload: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + unregister_remote_datareader(reader_crypto); + unregister_local_datawriter(writer_crypto); + + DDS_Security_OctetSeq_deinit(&plain_buffer); +} + diff --git a/src/security/builtin_plugins/tests/get_authenticated_peer_credential_token/src/get_authenticated_peer_credential_token_utests.c b/src/security/builtin_plugins/tests/get_authenticated_peer_credential_token/src/get_authenticated_peer_credential_token_utests.c new file mode 100644 index 0000000..28f88e2 --- /dev/null +++ b/src/security/builtin_plugins/tests/get_authenticated_peer_credential_token/src/get_authenticated_peer_credential_token_utests.c @@ -0,0 +1,1640 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#include +#include +#include + +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/misc.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/handshake_helper.h" + +#define HANDSHAKE_SIGNATURE_SIZE 6 + +static const char * AUTH_PROTOCOL_CLASS_ID = "DDS:Auth:PKI-DH:1.0"; +static const char * PERM_ACCESS_CLASS_ID = "DDS:Access:Permissions:1.0"; + +static const char * PROPERTY_IDENTITY_CA = "dds.sec.auth.identity_ca"; +static const char * PROPERTY_PRIVATE_KEY = "dds.sec.auth.private_key"; +static const char * PROPERTY_IDENTITY_CERT = "dds.sec.auth.identity_certificate"; + +static const char * PROPERTY_CERT_SUBJECT_NAME = "dds.cert.sn"; +static const char * PROPERTY_CERT_ALGORITHM = "dds.cert.algo"; +static const char * PROPERTY_CA_SUBJECT_NAME = "dds.ca.sn"; +static const char * PROPERTY_CA_ALGORITHM = "dds.ca.aglo"; + +static const char * PROPERTY_PERM_CA_SUBJECT_NAME = "ds.perm_ca.sn"; + +static const char * SUBJECT_NAME_IDENTITY_CERT = "CN=CHAM-574 client,O=Some Company,ST=Some-State,C=NL"; +static const char * SUBJECT_NAME_IDENTITY_CA = "CN=CHAM-574 authority,O=Some Company,ST=Some-State,C=NL"; + +static const char * RSA_2048_ALGORITHM_NAME = "RSA-2048"; + +static const char * AUTH_REQUEST_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+AuthReq"; +static const char * AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME = "future_challenge"; + +static const char * AUTH_HANDSHAKE_REQUEST_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+Req"; +static const char * AUTH_HANDSHAKE_REPLY_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+Reply"; +static const char * AUTH_HANDSHAKE_FINAL_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+Final"; + +static const char * PERMISSIONS_DOCUMENT = "permissions_document"; + +typedef enum { + HANDSHAKE_REQUEST, + HANDSHAKE_REPLY, + HANDSHAKE_FINAL +} HandshakeStep_t; + + +struct octet_seq { + unsigned char *data; + uint32_t length; +}; + +static const char * AUTH_DSIGN_ALGO_RSA_NAME = "RSASSA-PSS-SHA256"; +static const char * AUTH_KAGREE_ALGO_RSA_NAME = "DH+MODP-2048-256"; +static const char * AUTH_KAGREE_ALGO_ECDH_NAME = "ECDH+prime256v1-CEUM"; + + + +static const char *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-----\n"; + + +static const char *identity_ca = +"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-----\n"; + +static const char *REMOTE_IDENTITY_CERTIFICATE = +"-----BEGIN CERTIFICATE-----\n" +"MIIDcDCCAligAwIBAgIBBTANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL\n" +"MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50\n" +"aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu\n" +"Y29tMB4XDTE4MDMxMjAwMDAwMFoXDTI3MDMxMTIzNTk1OVowcDELMAkGA1UEBhMC\n" +"TkwxCzAJBgNVBAgTAk9WMQ8wDQYDVQQKEwZBRExpbmsxETAPBgNVBAsTCElTVCBU\n" +"ZXN0MREwDwYDVQQDEwhCb2IgVGVzdDEdMBsGCSqGSIb3DQEJARYOYm9iQGFkbGlu\n" +"ay5pc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDB5vqhuWnwhxXZ\n" +"qffPmfjzge7w91oX4ISlboIfBXp3sLj2mqLSsYhgBNJAn/Fl1OZeFw0d4gVibBgx\n" +"5Zdcjsi+ClvYK8H534iTJfNriMyhg4kSWxZF1Tixfw3FS7LqjKEY5ZNPfp5a4P+8\n" +"UveorYJusrnlv1DiF6aPhJQh8J62J6bhx62DNLO7dZbN0BUsnWtyDcfi5DOjf2/r\n" +"3lSRfecn3uBr1QYRaS5FrV+MSoGcjI3M75mei1TTUp7YT4ZWRR5rKUMql605xsms\n" +"d6sqJaKofYmw7wCuaVJ86pb/w8srdddKt21xUeQNMKn49H6raezMOE3U5BUMtZ+P\n" +"2OBLk/CPAgMBAAGjEzARMA8GA1UdDwEB/wQFAwMH/4AwDQYJKoZIhvcNAQELBQAD\n" +"ggEBAJV71Ckf1zsks5mJXqdUb8bTVHg4hN32pwjCL5c6W2XHAv+YHwE/fN3C1VIY\n" +"bC8zjUC9dCOyC2AvOQyZQ1eC/WoK6FlXjHVX2upL4lXQ9WL9ztt1mgdRrhvUPuUn\n" +"aBE8VgNU0t4jl93xMIaU8hB0kQsV+kdcN0cWbrF3mT4s9njRvopJ8hS2UE60V2wA\n" +"ceUOazH+QGPh1k0jkynrTlVR9GrpebQwZ2UFeinVO0km17IAyQkz+OmPc4jQLJMl\n" +"CmkbmMwowdLMKC6r/HyE87dN7NvFnRM5iByJklRwN7WDYZrl72HoUOlgTZ7PjW2G\n" +"jTxK8xXtDCXC/3CNpe0YFnOga8g=\n" +"-----END CERTIFICATE-----\n"; + + +static const char *private_key = + +"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-----\n"; + + +static char *remote_private_key = +"-----BEGIN RSA PRIVATE KEY-----\n" +"MIIEowIBAAKCAQEAweb6oblp8IcV2an3z5n484Hu8PdaF+CEpW6CHwV6d7C49pqi\n" +"0rGIYATSQJ/xZdTmXhcNHeIFYmwYMeWXXI7Ivgpb2CvB+d+IkyXza4jMoYOJElsW\n" +"RdU4sX8NxUuy6oyhGOWTT36eWuD/vFL3qK2CbrK55b9Q4hemj4SUIfCetiem4cet\n" +"gzSzu3WWzdAVLJ1rcg3H4uQzo39v695UkX3nJ97ga9UGEWkuRa1fjEqBnIyNzO+Z\n" +"notU01Ke2E+GVkUeaylDKpetOcbJrHerKiWiqH2JsO8ArmlSfOqW/8PLK3XXSrdt\n" +"cVHkDTCp+PR+q2nszDhN1OQVDLWfj9jgS5PwjwIDAQABAoIBAHfgWhED9VgL29le\n" +"uGMzmPLK4LM+6Qcb+kXghTeyhl1a928WeRVzRpG+SVJEz9QaBHYlICnaY2PO2kJ2\n" +"49YIPFkpRFDn9JuLs/7tFonj4Eb2cBbWE3YG9W7e0t+oBiv1117yB9m8uSAMPG7s\n" +"iEpTQvE3M7CzT8kHwCS4XXCCN0z7LqKyZ1heScjdfhV3D2TnFFjdtQ/9KfQa3hIc\n" +"6ftbpi4EKbfasspyqfrJ/cqjHzse9iEXLOZJhs+atBAKe/uJ4Hc3LRPbX4MPniAp\n" +"JJrldXFK9p+HILlbXvu+5n+DSGbZmT1x9a/E9suGyoJiASDH2Ax4yCVTi+v8C1R2\n" +"aKdU1LkCgYEA/3dFuM6zIHwiJ0GKT0gtJL6J3m+i51SNcRIm8deXt6HULMpUNajj\n" +"vZ1bgQm/h+uRBlPV3swkaVxvPTIabOTY4gmCBSzvVCSIAKHVc/+5Nkl9KruwSq4G\n" +"tctmXZ7ymMDi+6QGCJTJkAx6jptXyrzC00HOjXOwyQ+iDipqgr3A8FsCgYEAwk7B\n" +"2/hi569EIHFRT6nz/JMqQVPZ/MJDKoKhffTbnjQ5OAzpiVN6cyThMM1iVJEBFNhx\n" +"OEacy60Qj0TtR1oYrQSRSLm58TTxiuB4Pohbmg3iU+kSM/eTq/ups/Ul1oCs2eAb\n" +"POfweD3c4d4i7sN8bUNQXehiE4MOlK9TYQy39t0CgYAJht0mwy6S644qgJsz0bE9\n" +"SY3Cqc8daV3M9axWIIAb7QEImpMBXUcA7zlWWpK18ub5oW68XEiPVU8grRmnLfGY\n" +"nFoo70ANlz8rJt3a8ZJqn9r3GQC+CDdf2DH9E8xgPfE5CSjgcQwDPzPi1ZA0k02A\n" +"q1eUltfk55xXguVt8r2bOQKBgQC7+kldr1yv20VDRZ1uPnMGRLE6Zg6bkqw78gid\n" +"vEbDNK6uZP+BlTr/LgyVk/yu52Fucz6FPPrvqEw+7mXHA4ifya1r+BHFIn0S57os\n" +"dOp5jTkKCI9NqxQ3683vhRjH/dA7L63qLFDdYqvP74FID+LOKbMURn6rdbyjZ0J4\n" +"vz8yGQKBgHIzcKlQosRxf+KptOPMGRs30L9PnH+sNmTo2SmEzAGkBkt1msGRh/2l\n" +"uT3hOEhUXL9knRyXwQSXgrIwr9QwI5rGS5FAgX26TgBtPBDs2NuyyhhS5yxsiEPT\n" +"BR+EjQFW9dzRkpRJgvsG4DcNAhFn7fQqFNcWXgFWuBXmGNkdtEGR\n" +"-----END RSA PRIVATE KEY-----"; + + + +static struct plugins_hdl *g_plugins = NULL; +static dds_security_authentication *g_auth = NULL; + +static DDS_Security_IdentityHandle g_local_identity_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_IdentityHandle g_remote_identity_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_AuthRequestMessageToken g_remote_auth_request_token = DDS_SECURITY_TOKEN_INIT; +static const DDS_Security_BinaryProperty_t *g_challenge1_predefined_glb = NULL; +static const DDS_Security_BinaryProperty_t *g_challenge2_predefined_glb = NULL; +static DDS_Security_OctetSeq g_serialized_participant_data = DDS_SECURITY_SEQUENCE_INIT; +static DDS_Security_ParticipantBuiltinTopicData *g_local_participant_data = NULL; + +static DDS_Security_ParticipantBuiltinTopicData *g_remote_participant_data1 = NULL; +static DDS_Security_ParticipantBuiltinTopicData *g_remote_participant_data2 = NULL; +static DDS_Security_GUID_t g_candidate_participant_guid; +static DDS_Security_GUID_t g_remote_participant_guid1; +static DDS_Security_GUID_t g_remote_participant_guid2; + +static EVP_PKEY *g_dh_modp_key = NULL; +static EVP_PKEY *g_dh_ecdh_key = NULL; +static struct octet_seq g_dh_modp_pub_key = {NULL, 0}; +static struct octet_seq g_dh_ecdh_pub_key = {NULL, 0}; + + +static void +octet_seq_init( + struct octet_seq *seq, + unsigned char *data, + uint32_t size) +{ + seq->data = ddsrt_malloc(size); + memcpy(seq->data, data, size); + seq->length = size; +} + +static void +octet_seq_deinit( + struct octet_seq *seq) +{ + ddsrt_free(seq->data); +} + +static void +serializer_participant_data( + DDS_Security_ParticipantBuiltinTopicData *pdata, + unsigned char **buffer, + size_t *size); + +static void +dds_security_property_init( + DDS_Security_PropertySeq *seq, + DDS_Security_unsigned_long size) +{ + seq->_length = size; + seq->_maximum = size; + seq->_buffer = ddsrt_malloc(size * sizeof(DDS_Security_Property_t)); + memset(seq->_buffer, 0, size * sizeof(DDS_Security_Property_t)); +} + +static void +dds_security_property_deinit( + DDS_Security_PropertySeq *seq) +{ + uint32_t i; + + for (i = 0; i < seq->_length; i++) { + ddsrt_free(seq->_buffer[i].name); + ddsrt_free(seq->_buffer[i].value); + } + ddsrt_free(seq->_buffer); +} + +static void +reset_exception( + DDS_Security_SecurityException *ex) +{ + ex->minor_code = 0; + ex->code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void +initialize_identity_token( + DDS_Security_IdentityToken *token, + const char *certAlgo, + const char *caAlgo) +{ + memset(token, 0, sizeof(*token)); + + token->class_id = ddsrt_strdup(AUTH_PROTOCOL_CLASS_ID); + token->properties._maximum = 4; + token->properties._length = 4; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(4); + + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_CERT_SUBJECT_NAME); + token->properties._buffer[0].value = ddsrt_strdup(SUBJECT_NAME_IDENTITY_CERT); + token->properties._buffer[0].propagate = true; + + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_CERT_ALGORITHM); + token->properties._buffer[1].value = ddsrt_strdup(certAlgo); + token->properties._buffer[1].propagate = true; + + token->properties._buffer[2].name = ddsrt_strdup(PROPERTY_CA_SUBJECT_NAME); + token->properties._buffer[2].value = ddsrt_strdup(SUBJECT_NAME_IDENTITY_CA); + token->properties._buffer[2].propagate = true; + + token->properties._buffer[3].name = ddsrt_strdup(PROPERTY_CA_ALGORITHM); + token->properties._buffer[3].value = ddsrt_strdup(caAlgo); + token->properties._buffer[3].propagate = true; +} + +static void +initialize_permissions_token( + DDS_Security_PermissionsToken *token, + const char *caAlgo) +{ + token->class_id = ddsrt_strdup(PERM_ACCESS_CLASS_ID); + token->properties._length = 2; + token->properties._maximum = 2; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(4); + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_CERT_SUBJECT_NAME); + token->properties._buffer[0].value = ddsrt_strdup(SUBJECT_NAME_IDENTITY_CA); + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_PERM_CA_SUBJECT_NAME); + token->properties._buffer[1].value = ddsrt_strdup(caAlgo); +} + + + +static void +fill_auth_request_token( + DDS_Security_AuthRequestMessageToken *token) +{ + uint32_t i; + size_t len = 32; + unsigned char *challenge; + + challenge = ddsrt_malloc(len); + + for (i = 0; i < len; i++) { + challenge[i] = (unsigned char)(0xFF - i); + } + + memset(token, 0, sizeof(*token)); + + token->class_id = ddsrt_strdup(AUTH_REQUEST_TOKEN_CLASS_ID); + token->binary_properties._maximum = 1; + token->binary_properties._length = 1; + token->binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + token->binary_properties._buffer->name = ddsrt_strdup(AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + + token->binary_properties._buffer->value._maximum = (DDS_Security_unsigned_long) len; + token->binary_properties._buffer->value._length = (DDS_Security_unsigned_long) len; + token->binary_properties._buffer->value._buffer = challenge; +} + + +static DDS_Security_BinaryProperty_t * +find_binary_property( + DDS_Security_DataHolder *token, + const char *name) +{ + DDS_Security_BinaryProperty_t *result = NULL; + uint32_t i; + + for (i = 0; i < token->binary_properties._length && !result; i++) { + if (token->binary_properties._buffer[i].name && (strcmp(token->binary_properties._buffer[i].name, name) == 0)) { + result = &token->binary_properties._buffer[i]; + } + } + + return result; +} + + +static DDS_Security_Property_t * +find_property( + DDS_Security_DataHolder *token, + const char *name) +{ + DDS_Security_Property_t *result = NULL; + uint32_t i; + + for (i = 0; i < token->properties._length && !result; i++) { + if (token->properties._buffer[i].name && (strcmp(token->properties._buffer[i].name, name) == 0)) { + result = &token->properties._buffer[i]; + } + } + + return result; +} + +static void +deinitialize_identity_token( + DDS_Security_IdentityToken *token) +{ + DDS_Security_DataHolder_deinit(token); +} + + +static int +validate_local_identity(void) +{ + int res = 0; + DDS_Security_ValidationResult_t result; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GUID_t local_participant_guid; + DDS_Security_GuidPrefix_t prefix = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb}; + DDS_Security_EntityId_t entityId = {{0xb0,0xb1,0xb2},0x1}; + unsigned char *sdata; + size_t sz; + + memset(&local_participant_guid, 0, sizeof(local_participant_guid)); + memcpy(&g_candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&g_candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + memset(&participant_qos, 0, sizeof(participant_qos)); + dds_security_property_init(&participant_qos.property.value, 3); + participant_qos.property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + participant_qos.property.value._buffer[0].value = ddsrt_strdup(identity_certificate); + participant_qos.property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + participant_qos.property.value._buffer[1].value = ddsrt_strdup(identity_ca); + participant_qos.property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + participant_qos.property.value._buffer[2].value = ddsrt_strdup(private_key); + + /* Now call the function. */ + result = g_auth->validate_local_identity( + g_auth, + &g_local_identity_handle, + &local_participant_guid, + domain_id, + &participant_qos, + &g_candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + res = -1; + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + g_local_participant_data = DDS_Security_ParticipantBuiltinTopicData_alloc(); + memcpy(&g_local_participant_data->key[0], &local_participant_guid, 12); + /* convert from big-endian format to native format */ + g_local_participant_data->key[0] = ddsrt_fromBE4u(g_local_participant_data->key[0]); + g_local_participant_data->key[1] = ddsrt_fromBE4u(g_local_participant_data->key[1]); + g_local_participant_data->key[2] = ddsrt_fromBE4u(g_local_participant_data->key[2]); + + initialize_identity_token(&g_local_participant_data->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + initialize_permissions_token(&g_local_participant_data->permissions_token, RSA_2048_ALGORITHM_NAME); + + g_local_participant_data->security_info.participant_security_attributes = 0x01; + g_local_participant_data->security_info.plugin_participant_security_attributes = 0x02; + + serializer_participant_data(g_local_participant_data, &sdata, &sz); + + g_serialized_participant_data._length = g_serialized_participant_data._maximum = (DDS_Security_unsigned_long) sz; + g_serialized_participant_data._buffer = sdata; + + return res; +} + +static void +release_local_identity(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (g_local_identity_handle != DDS_SECURITY_HANDLE_NIL) { + success = g_auth->return_identity_handle(g_auth, g_local_identity_handle, &exception); + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } + + DDS_Security_OctetSeq_deinit(&g_serialized_participant_data); + + if (g_local_participant_data) { + DDS_Security_ParticipantBuiltinTopicData_free(g_local_participant_data); + } +} + +static X509 * +load_certificate( + const char *data) +{ + X509 *cert = NULL; + BIO *bio; + + bio = BIO_new_mem_buf((void *) data, -1); + if (!bio) { + return NULL; + } + + cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); + + BIO_free(bio); + + return cert; +} + +static int +get_adjusted_participant_guid( + X509 *cert, + const DDS_Security_GUID_t *candidate, + DDS_Security_GUID_t *adjusted) +{ + int result = 0; + unsigned char high[SHA256_DIGEST_LENGTH], low[SHA256_DIGEST_LENGTH]; + unsigned char *subject; + DDS_Security_octet hb = 0x80; + X509_NAME *name; + unsigned char *tmp = NULL; + int32_t i, size; + + name = X509_get_subject_name(cert); + size = i2d_X509_NAME(name, &tmp); + if (size > 0) { + subject = ddsrt_malloc((size_t) size); + memcpy(subject, tmp, (size_t)size); + OPENSSL_free(tmp); + + SHA256(subject, (size_t)size, high); + SHA256(&candidate->prefix[0], sizeof(DDS_Security_GuidPrefix_t), low); + + adjusted->entityId = candidate->entityId; + for (i = 0; i < 6; i++) { + adjusted->prefix[i] = hb | high[i]>>1; + hb = (unsigned char)( high[i]<<7 ); + } + for (i = 0; i < 6; i++) { + adjusted->prefix[i+6] = low[i]; + } + ddsrt_free(subject); + result = 1; + } + + return result; +} + +static int +create_dh_key_modp_2048( + EVP_PKEY **pkey) +{ + int r = 0; + EVP_PKEY *params = NULL; + EVP_PKEY_CTX *kctx = NULL; + DH *dh = NULL; + + *pkey = NULL; + + if ((params = EVP_PKEY_new()) == NULL) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate EVP_PKEY: %s", msg); + ddsrt_free(msg); + r = -1; + } else if ((dh = DH_get_2048_256()) == NULL) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate DH parameter: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_set1_DH(params, dh) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to set DH parameter to MODP_2048_256: %s", msg); + ddsrt_free(msg); + r = -1; + } else if ((kctx = EVP_PKEY_CTX_new(params, NULL)) == NULL) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate KEY context %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_keygen_init(kctx) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to initialize KEY context: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_keygen(kctx, pkey) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to generate :MODP_2048_256 keys %s", msg); + ddsrt_free(msg); + r = -1; + } + + if (params) EVP_PKEY_free(params); + if (kctx) EVP_PKEY_CTX_free(kctx); + if (dh) DH_free(dh); + + return r; +} + +static int +get_dh_public_key_modp_2048( + EVP_PKEY *pkey, + struct octet_seq *pubkey) +{ + int r = 0; + DH *dhkey; + unsigned char *buffer = NULL; + uint32_t size; + ASN1_INTEGER *asn1int; + + dhkey = EVP_PKEY_get1_DH(pkey); + if (!dhkey) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to get DH key from PKEY: %s", msg); + ddsrt_free(msg); + r = -1; + goto fail_get_dhkey; + } + + asn1int = BN_to_ASN1_INTEGER( dh_get_public_key(dhkey) , NULL); + if (!asn1int) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to convert DH key to ASN1 integer: %s", msg); + ddsrt_free(msg); + r = -1; + goto fail_get_pubkey; + } + + size = (uint32_t)i2d_ASN1_INTEGER(asn1int, &buffer); + octet_seq_init(pubkey, buffer, size); + + ASN1_INTEGER_free(asn1int); + OPENSSL_free(buffer); + +fail_get_pubkey: + DH_free(dhkey); +fail_get_dhkey: + return r; +} + +static int +create_dh_key_ecdh( + EVP_PKEY **pkey) +{ + int r = 0; + EVP_PKEY *params = NULL; + EVP_PKEY_CTX *pctx = NULL; + EVP_PKEY_CTX *kctx = NULL; + + *pkey = NULL; + + if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate DH parameter context: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_paramgen_init(pctx) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to initialize DH generation context: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to set DH generation parameter generation method: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_paramgen(pctx, ¶ms) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to generate DH parameters: %s", msg); + ddsrt_free(msg); + r = -1; + } else if ((kctx = EVP_PKEY_CTX_new(params, NULL)) == NULL) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate KEY context %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_keygen_init(kctx) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to initialize KEY context: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_keygen(kctx, pkey) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to generate :MODP_2048_256 keys %s", msg); + ddsrt_free(msg); + r = -1; + } + + if (kctx) EVP_PKEY_CTX_free(kctx); + if (params) EVP_PKEY_free(params); + if (pctx) EVP_PKEY_CTX_free(pctx); + + return r; +} + +static int +get_dh_public_key_ecdh( + EVP_PKEY *pkey, + struct octet_seq *pubkey) +{ + int r = 0; + EC_KEY *eckey = NULL; + const EC_GROUP *group = NULL; + const EC_POINT *point = NULL; + size_t sz; + + if (!(eckey = EVP_PKEY_get1_EC_KEY(pkey))) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to get EC key from PKEY: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (!(point = EC_KEY_get0_public_key(eckey))) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to get public key from ECKEY: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (!(group = EC_KEY_get0_group(eckey))) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to get group from ECKEY: %s", msg); + ddsrt_free(msg); + r = -1; + } else if ((sz = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, NULL, 0, NULL)) != 0) { + pubkey->data = ddsrt_malloc(sz); + pubkey->length = (uint32_t) EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, pubkey->data, sz, NULL); + if (pubkey->length == 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to serialize public EC key: %s", msg); + ddsrt_free(msg); + octet_seq_deinit(pubkey); + r = -1; + } + } else { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to serialize public EC key: %s", msg); + ddsrt_free(msg); + r = -1; + } + + if (eckey) EC_KEY_free(eckey); + + return r; +} + +static int +validate_remote_identities (const char *remote_id_certificate) +{ + int res = 0; + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityToken remote_identity_token; + static DDS_Security_AuthRequestMessageToken local_auth_request_token = DDS_SECURITY_TOKEN_INIT; + DDS_Security_GUID_t guid1; + DDS_Security_GUID_t guid2; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix1 = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab}; + DDS_Security_GuidPrefix_t prefix2 = {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb}; + DDS_Security_EntityId_t entityId = {{0xb0,0xb1,0xb2},0x1}; + X509 *cert; + + memcpy(&guid1.prefix, &prefix1, sizeof(prefix1)); + memcpy(&guid1.entityId, &entityId, sizeof(entityId)); + memcpy(&guid2.prefix, &prefix2, sizeof(prefix2)); + memcpy(&guid2.entityId, &entityId, sizeof(entityId)); + + if (g_local_identity_handle == DDS_SECURITY_HANDLE_NIL) { + return -1; + } + + cert = load_certificate(remote_id_certificate); + if (!cert) { + return -1; + } + + if (!get_adjusted_participant_guid(cert, &guid1, &g_remote_participant_guid1)) { + X509_free(cert); + return -1; + } + + if (!get_adjusted_participant_guid(cert, &guid2, &g_remote_participant_guid2)) { + X509_free(cert); + return -1; + } + + X509_free(cert); + + initialize_identity_token(&remote_identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + + reset_exception(&exception); + + fill_auth_request_token(&g_remote_auth_request_token); + + result = g_auth->validate_remote_identity( + g_auth, + &g_remote_identity_handle, + &local_auth_request_token, + &g_remote_auth_request_token, + g_local_identity_handle, + &remote_identity_token, + &g_remote_participant_guid2, + &exception); + + if ((result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST) && + (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE)) { + printf("validate_remote_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + reset_exception(&exception); + + deinitialize_identity_token(&remote_identity_token); + DDS_Security_DataHolder_deinit(&local_auth_request_token); + + g_remote_participant_data1 = DDS_Security_ParticipantBuiltinTopicData_alloc(); + memcpy(&g_remote_participant_data1->key[0], &g_remote_participant_guid1, 12); + g_remote_participant_data1->key[0] = ddsrt_fromBE4u(g_remote_participant_data1->key[0]); + g_remote_participant_data1->key[1] = ddsrt_fromBE4u(g_remote_participant_data1->key[1]); + g_remote_participant_data1->key[2] = ddsrt_fromBE4u(g_remote_participant_data1->key[2]); + + initialize_identity_token(&g_remote_participant_data1->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + initialize_permissions_token(&g_remote_participant_data1->permissions_token, RSA_2048_ALGORITHM_NAME); + + g_remote_participant_data1->security_info.participant_security_attributes = 0x01; + g_remote_participant_data1->security_info.plugin_participant_security_attributes = 0x02; + + g_remote_participant_data2 = DDS_Security_ParticipantBuiltinTopicData_alloc(); + memcpy(&g_remote_participant_data2->key[0], &g_remote_participant_guid2, 12); + g_remote_participant_data2->key[0] = ddsrt_fromBE4u(g_remote_participant_data2->key[0]); + g_remote_participant_data2->key[1] = ddsrt_fromBE4u(g_remote_participant_data2->key[1]); + g_remote_participant_data2->key[2] = ddsrt_fromBE4u(g_remote_participant_data2->key[2]); + + initialize_identity_token(&g_remote_participant_data2->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + initialize_permissions_token(&g_remote_participant_data2->permissions_token, RSA_2048_ALGORITHM_NAME); + + g_remote_participant_data2->security_info.participant_security_attributes = 0x01; + g_remote_participant_data2->security_info.plugin_participant_security_attributes = 0x02; + + g_remote_participant_data2->security_info.participant_security_attributes = 0x01; + g_remote_participant_data2->security_info.plugin_participant_security_attributes = 0x02; + + g_challenge1_predefined_glb = find_binary_property(&g_remote_auth_request_token, AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + g_challenge2_predefined_glb = g_challenge1_predefined_glb; + + return res; +} + +static void +release_remote_identities(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (g_remote_identity_handle != DDS_SECURITY_HANDLE_NIL) { + success = g_auth->return_identity_handle(g_auth, g_remote_identity_handle, &exception); + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } + + DDS_Security_DataHolder_deinit(&g_remote_auth_request_token); + + DDS_Security_ParticipantBuiltinTopicData_free(g_remote_participant_data1); + DDS_Security_ParticipantBuiltinTopicData_free(g_remote_participant_data2); +} + +CU_Init(ddssec_builtin_get_authenticated_peer_credential) +{ + int result = 0; + dds_openssl_init (); + + /* Only need the authentication plugin. */ + g_plugins = load_plugins(NULL /* Access Control */, + &g_auth /* Authentication */, + NULL /* Cryptograpy */); + if (g_plugins) { + result = validate_local_identity(); + if (result >= 0) { + result = validate_remote_identities( REMOTE_IDENTITY_CERTIFICATE ); + } + if (result >= 0) { + result = create_dh_key_modp_2048(&g_dh_modp_key); + } + if (result >= 0) { + result = get_dh_public_key_modp_2048(g_dh_modp_key, &g_dh_modp_pub_key); + } + if (result >= 0) { + result = create_dh_key_ecdh(&g_dh_ecdh_key); + } + if (result >= 0) { + result = get_dh_public_key_ecdh(g_dh_ecdh_key, &g_dh_ecdh_pub_key); + } + } else { + result = -1; + } + + + return result; +} + +CU_Clean(ddssec_builtin_get_authenticated_peer_credential) +{ + release_local_identity(); + release_remote_identities(); + unload_plugins(g_plugins); + octet_seq_deinit(&g_dh_modp_pub_key); + octet_seq_deinit(&g_dh_ecdh_pub_key); + if (g_dh_modp_key) { + EVP_PKEY_free(g_dh_modp_key); + } + if (g_dh_ecdh_key) { + EVP_PKEY_free(g_dh_ecdh_key); + } + return 0; +} + +static void +serializer_participant_data( + DDS_Security_ParticipantBuiltinTopicData *pdata, + unsigned char **buffer, + size_t *size) +{ + DDS_Security_Serializer serializer; + serializer = DDS_Security_Serializer_new(1024, 1024); + + DDS_Security_Serialize_ParticipantBuiltinTopicData(serializer, pdata); + DDS_Security_Serializer_buffer(serializer, buffer, size); + DDS_Security_Serializer_free(serializer); +} + + +static void +set_binary_property_value( + DDS_Security_BinaryProperty_t *bp, + const char *name, + const unsigned char *data, + size_t length) +{ + assert(bp); + assert(name); + assert(data); + + bp->name = ddsrt_strdup(name); + bp->value._maximum = bp->value._length = (DDS_Security_unsigned_long) length; + if (length) { + bp->value._buffer = ddsrt_malloc(length); + memcpy(bp->value._buffer, data, length); + } else { + bp->value._buffer = NULL; + } +} + +static void +set_binary_property_string( + DDS_Security_BinaryProperty_t *bp, + const char *name, + const char *data) +{ + uint32_t length; + + assert(bp); + assert(name); + assert(data); + + length = (uint32_t)strlen(data) + 1; + set_binary_property_value(bp, name, (const unsigned char *)data, length); +} + +static void +fill_handshake_message_token( + DDS_Security_HandshakeMessageToken *token, + DDS_Security_ParticipantBuiltinTopicData *pdata, + const char *certificate, + const char *dsign, + const char *kagree, + const struct octet_seq *diffie_hellman1, + const unsigned char *challengeData, + unsigned int challengeDataSize, + const struct octet_seq *diffie_hellman2, + const unsigned char *challengeData2, + unsigned int challengeDataSize2, + const DDS_Security_BinaryProperty_t *hash1_from_request, + const DDS_Security_BinaryProperty_t *hash2_from_reply, + HandshakeStep_t step) +{ + DDS_Security_BinaryProperty_t *tokens; + DDS_Security_BinaryProperty_t *c_id; + DDS_Security_BinaryProperty_t *c_perm; + DDS_Security_BinaryProperty_t *c_pdata; + DDS_Security_BinaryProperty_t *c_dsign_algo; + DDS_Security_BinaryProperty_t *c_kagree_algo; + DDS_Security_BinaryProperty_t *hash_c1; + DDS_Security_BinaryProperty_t *hash_c2; + DDS_Security_BinaryProperty_t *dh1; + DDS_Security_BinaryProperty_t *dh2; + DDS_Security_BinaryProperty_t *challenge1; + DDS_Security_BinaryProperty_t *challenge2; + DDS_Security_BinaryProperty_t *signature; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + unsigned idx; + unsigned char *serialized_local_participant_data; + size_t serialized_local_participant_data_size; + /*unsigned hash[32];*/ + + switch( step ) + { + + case HANDSHAKE_REQUEST: + tokens = DDS_Security_BinaryPropertySeq_allocbuf(8); + c_id = &tokens[0]; + c_perm = &tokens[1]; + c_pdata = &tokens[2]; + c_dsign_algo = &tokens[3]; + c_kagree_algo = &tokens[4]; + hash_c1 = &tokens[5]; + dh1 = &tokens[6]; + challenge1 = &tokens[7]; + + serializer_participant_data(pdata, &serialized_local_participant_data, &serialized_local_participant_data_size); + + /* Store the Identity Certificate associated with the local identify in c.id property */ + if (certificate) { + set_binary_property_string(c_id, "c.id", certificate); + } else { + set_binary_property_string(c_id, "c.idx", "rubbish"); + } + + /* Store the permission document in the c.perm property */ + set_binary_property_string(c_perm, "c.perm", PERMISSIONS_DOCUMENT); + + /* Store the provided g_local_participant_data in the c.pdata property */ + set_binary_property_value(c_pdata, "c.pdata", serialized_local_participant_data, serialized_local_participant_data_size); + ddsrt_free(serialized_local_participant_data); + + /* Set the used signing algorithm descriptor in c.dsign_algo */ + if (dsign) { + set_binary_property_string(c_dsign_algo, "c.dsign_algo", dsign); + } else { + set_binary_property_string(c_dsign_algo, "c.dsign_algox", "rubbish"); + } + + /* Set the used key algorithm descriptor in c.kagree_algo */ + if (kagree) { + set_binary_property_string(c_kagree_algo, "c.kagree_algo", kagree); + } else { + set_binary_property_string(c_kagree_algo, "c.kagree_algox", "rubbish"); + } + + /* Calculate the hash_c1 */ + { + DDS_Security_BinaryPropertySeq bseq; + DDS_Security_Serializer serializer; + unsigned char hash1_sentrequest_arr[32]; + unsigned char *buffer; + size_t size; + + bseq._length = bseq._maximum = 5; + bseq._buffer = tokens; + + serializer = DDS_Security_Serializer_new(1024, 1024); + + DDS_Security_Serialize_BinaryPropertySeq(serializer, &bseq); + DDS_Security_Serializer_buffer(serializer, &buffer, &size); + SHA256(buffer, size, hash1_sentrequest_arr); + ddsrt_free(buffer); + DDS_Security_Serializer_free(serializer); + + set_binary_property_value(hash_c1, "hash_c1", hash1_sentrequest_arr, sizeof(hash1_sentrequest_arr)); + } + + /* Set the DH public key associated with the local participant in dh1 property */ + if (diffie_hellman1) { + set_binary_property_value(dh1, "dh1", diffie_hellman1->data, diffie_hellman1->length); + } else { + set_binary_property_string(dh1, "dh1x", "rubbish"); + } + + /* Set the challenge in challenge1 property */ + if (challengeData) { + set_binary_property_value(challenge1, "challenge1", challengeData, challengeDataSize); + } else { + set_binary_property_value(challenge1, "challenge1x", g_challenge1_predefined_glb->value._buffer, g_challenge1_predefined_glb->value._length); + } + + token->class_id = ddsrt_strdup(AUTH_HANDSHAKE_REQUEST_TOKEN_CLASS_ID); + token->binary_properties._length = token->binary_properties._maximum = 8; + token->binary_properties._buffer = tokens; + break; + + case HANDSHAKE_REPLY: + tokens = DDS_Security_BinaryPropertySeq_allocbuf(12); + idx = 0; + c_id = &tokens[idx++]; + c_perm = &tokens[idx++]; + c_pdata = &tokens[idx++]; + c_dsign_algo = &tokens[idx++]; + c_kagree_algo = &tokens[idx++]; + hash_c2 = &tokens[idx++]; + challenge2 = &tokens[idx++]; + dh2 = &tokens[idx++]; + challenge1 = &tokens[idx++]; + dh1 = &tokens[idx++]; + hash_c1 = &tokens[idx++] ; + signature = &tokens[idx++]; + + serializer_participant_data(pdata, &serialized_local_participant_data, &serialized_local_participant_data_size); + + /* Store the Identity Certificate associated with the local identify in c.id property */ + if (certificate) { + set_binary_property_string(c_id, "c.id", certificate); + } else { + set_binary_property_string(c_id, "c.idx", "rubbish"); + } + + /* Store the permission document in the c.perm property */ + set_binary_property_string(c_perm, "c.perm", PERMISSIONS_DOCUMENT); + + /* Store the provided g_local_participant_data in the c.pdata property */ + set_binary_property_value(c_pdata, "c.pdata", serialized_local_participant_data, serialized_local_participant_data_size); + ddsrt_free(serialized_local_participant_data); + + /* Set the used signing algorithm descriptor in c.dsign_algo */ + if (dsign) { + set_binary_property_string(c_dsign_algo, "c.dsign_algo", dsign); + } else { + set_binary_property_string(c_dsign_algo, "c.dsign_algox", "rubbish"); + } + + /* Set the used key algorithm descriptor in c.kagree_algo */ + if (kagree) { + set_binary_property_string(c_kagree_algo, "c.kagree_algo", kagree); + } else { + set_binary_property_string(c_kagree_algo, "c.kagree_algox", "rubbish"); + } + + CU_ASSERT(hash1_from_request != NULL); + + set_binary_property_value(hash_c1, "hash_c1", hash1_from_request->value._buffer, hash1_from_request->value._length); + + /* Calculate the hash_c2 */ + { + DDS_Security_BinaryPropertySeq bseq; + DDS_Security_Serializer serializer; + unsigned char hash2_sentreply_arr[32]; + unsigned char *buffer; + size_t size; + + bseq._length = bseq._maximum = 5; + bseq._buffer = tokens; + + serializer = DDS_Security_Serializer_new(1024, 1024); + + DDS_Security_Serialize_BinaryPropertySeq(serializer, &bseq); + DDS_Security_Serializer_buffer(serializer, &buffer, &size); + SHA256(buffer, size, hash2_sentreply_arr); + + ddsrt_free(buffer); + DDS_Security_Serializer_free(serializer); + + set_binary_property_value(hash_c2, "hash_c2", hash2_sentreply_arr, sizeof(hash2_sentreply_arr)); + } + + /* Set the challenge in challenge1 property */ + if (challengeData) { + set_binary_property_value(challenge1, "challenge1", challengeData, challengeDataSize); + } else { + set_binary_property_value(challenge1, "challenge1x", challenge2->value._buffer, challenge2->value._length); + } + + /* Set the challenge in challenge2 property */ + if (challengeData2) { + set_binary_property_value(challenge2, "challenge2", challengeData2, challengeDataSize2); + } else { + set_binary_property_value(challenge2, "challenge2x", challenge2->value._buffer, challenge2->value._length); + } + + + /* Set the DH public key associated with the local participant in dh1 property */ + if (diffie_hellman1) { + set_binary_property_value(dh1, "dh1", diffie_hellman1->data, diffie_hellman1->length); + } else { + set_binary_property_string(dh1, "dh1x", "rubbish"); + } + + /* Set the DH public key associated with the local participant in dh2 property */ + if (diffie_hellman2) { + set_binary_property_value(dh2, "dh2", diffie_hellman2->data, diffie_hellman2->length); + } else { + set_binary_property_string(dh2, "dh2x", "rubbish"); + } + + /* Calculate the signature */ + { + BIO *bio; + EVP_PKEY *private_key_x509; + unsigned char *sign; + size_t signlen; + + const DDS_Security_BinaryProperty_t * binary_properties[ HANDSHAKE_SIGNATURE_SIZE ]; + + /* load certificate in buffer */ + bio = BIO_new_mem_buf((const char *) remote_private_key, -1); + assert( bio ); + private_key_x509 = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + assert (private_key_x509 ); + + binary_properties[0] = hash_c2; + binary_properties[1] = challenge2; + binary_properties[2] = dh2; + binary_properties[3] = challenge1; + binary_properties[4] = dh1; + binary_properties[5] = hash_c1; + + if (create_signature_for_test(private_key_x509, binary_properties, HANDSHAKE_SIGNATURE_SIZE , &sign, &signlen, &exception) != DDS_SECURITY_VALIDATION_OK) + { + printf("Exception: %s\n", exception.message); + } + set_binary_property_value(signature, "signature", sign, signlen); + + ddsrt_free(sign); + BIO_free(bio); + EVP_PKEY_free(private_key_x509); + } + + token->class_id = ddsrt_strdup(AUTH_HANDSHAKE_REPLY_TOKEN_CLASS_ID); + token->binary_properties._length = token->binary_properties._maximum = 12; + token->binary_properties._buffer = tokens; + break; + + case HANDSHAKE_FINAL: + tokens = DDS_Security_BinaryPropertySeq_allocbuf(7); + idx = 0; + signature = &tokens[idx++]; + hash_c1 = &tokens[idx++]; + challenge1 = &tokens[idx++]; + dh1 = &tokens[idx++]; + challenge2 = &tokens[idx++]; + dh2 = &tokens[idx++]; + hash_c2 = &tokens[idx++]; + + CU_ASSERT(hash1_from_request != NULL); + CU_ASSERT(hash2_from_reply != NULL); + assert(hash1_from_request && hash2_from_reply); // for Clang's static analyzer + + set_binary_property_value(hash_c1, "hash_c1", hash1_from_request->value._buffer, hash1_from_request->value._length); + set_binary_property_value(hash_c2, "hash_c2", hash2_from_reply->value._buffer, hash2_from_reply->value._length); + + printf("process: %s\n", hash_c1->name); + + /* Set the challenge in challenge1 property */ + if (challengeData) { + set_binary_property_value(challenge1, "challenge1", challengeData, challengeDataSize); + } else { + set_binary_property_value(challenge1, "challenge1x", challenge2->value._buffer, challenge2->value._length); + } + + /* Set the challenge in challenge2 property */ + if (challengeData2) { + set_binary_property_value(challenge2, "challenge2", challengeData2, challengeDataSize2); + } else { + set_binary_property_value(challenge2, "challenge2x", challenge2->value._buffer, challenge2->value._length); + } + + + /* Set the DH public key associated with the local participant in dh1 property */ + if (diffie_hellman1) { + set_binary_property_value(dh1, "dh1", diffie_hellman1->data, diffie_hellman1->length); + } else { + set_binary_property_string(dh1, "dh1x", "rubbish"); + } + + /* Set the DH public key associated with the local participant in dh2 property */ + if (diffie_hellman2) { + set_binary_property_value(dh2, "dh2", diffie_hellman2->data, diffie_hellman2->length); + } else { + set_binary_property_string(dh2, "dh2x", "rubbish"); + } + + /* Calculate the signature */ + { + BIO *bio; + EVP_PKEY *private_key_x509; + unsigned char *sign; + size_t signlen; + const DDS_Security_BinaryProperty_t * binary_properties[ HANDSHAKE_SIGNATURE_SIZE ]; + + /* load certificate in buffer */ + bio = BIO_new_mem_buf((const char *) remote_private_key, -1); + assert( bio ); + private_key_x509 = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + assert (private_key_x509 ); + + binary_properties[0] = hash_c1; + binary_properties[1] = challenge1; + binary_properties[2] = dh1; + binary_properties[3] = challenge2; + binary_properties[4] = dh2; + binary_properties[5] = hash_c2; + + if (create_signature_for_test(private_key_x509, binary_properties, HANDSHAKE_SIGNATURE_SIZE, &sign, &signlen, &exception) != DDS_SECURITY_VALIDATION_OK) + { + printf("Exception: %s\n", exception.message); + } + set_binary_property_value(signature, "signature", sign, signlen); + + ddsrt_free(sign); + BIO_free(bio); + EVP_PKEY_free(private_key_x509); + } + token->class_id = ddsrt_strdup(AUTH_HANDSHAKE_FINAL_TOKEN_CLASS_ID); + token->binary_properties._length = token->binary_properties._maximum = 7; + token->binary_properties._buffer = tokens; + break; + } +} + +static void +fill_handshake_message_token_default( + DDS_Security_HandshakeMessageToken *token, + DDS_Security_ParticipantBuiltinTopicData *pdata, + const unsigned char *challengeData, + unsigned int challengeDataSize) +{ + fill_handshake_message_token( + token, pdata, REMOTE_IDENTITY_CERTIFICATE, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + &g_dh_modp_pub_key, challengeData, challengeDataSize, NULL, NULL, 0, NULL, NULL, HANDSHAKE_REQUEST); +} + +static void +handshake_message_deinit( + DDS_Security_HandshakeMessageToken *token) +{ + DDS_Security_DataHolder_deinit(token); +} + +CU_Test(ddssec_builtin_get_authenticated_peer_credential,token_after_request ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_reply_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_AuthenticatedPeerCredentialToken credential_token = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + const DDS_Security_BinaryProperty_t *hash1_sentrequest; + const DDS_Security_BinaryProperty_t *dh1; + const DDS_Security_BinaryProperty_t *challenge1_glb; + const DDS_Security_Property_t *c_id; + const DDS_Security_Property_t *c_perm; + struct octet_seq dh1_pub_key; + + CU_ASSERT_FATAL (g_auth != NULL); + CU_ASSERT_FATAL (g_local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (g_remote_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (g_auth->begin_handshake_request != NULL); + CU_ASSERT_FATAL (g_auth->process_handshake != NULL); + + /* simulate request */ + result = g_auth->begin_handshake_request( + g_auth, + &handshake_handle, + &handshake_token_out, + g_local_identity_handle, + g_remote_identity_handle, + &g_serialized_participant_data, + &exception); + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + assert(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); // for Clang's static analyzer + + /* mock reply */ + dh1 = find_binary_property(&handshake_token_out, "dh1"); + dh1_pub_key.data = dh1->value._buffer; + dh1_pub_key.length = dh1->value._length; + challenge1_glb = find_binary_property(&handshake_token_out, "challenge1"); + hash1_sentrequest = find_binary_property(&handshake_token_out, "hash_c1"); + fill_handshake_message_token( + &handshake_reply_token_in, + g_remote_participant_data2, + REMOTE_IDENTITY_CERTIFICATE, + AUTH_DSIGN_ALGO_RSA_NAME, + AUTH_KAGREE_ALGO_ECDH_NAME, + &dh1_pub_key, + challenge1_glb->value._buffer, + challenge1_glb->value._length, + &g_dh_ecdh_pub_key, + g_challenge2_predefined_glb->value._buffer, + g_challenge2_predefined_glb->value._length, + hash1_sentrequest, + NULL, + HANDSHAKE_REPLY); + handshake_message_deinit(&handshake_token_out); + + /* simulate process */ + result = g_auth->process_handshake( + g_auth, + &handshake_token_out, + &handshake_reply_token_in, + handshake_handle, + &exception); + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE); + assert(result == DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE); // for Clang's static analyzer + + /* + * Actual test. + */ + success = g_auth->get_authenticated_peer_credential_token( + g_auth, + &credential_token, + handshake_handle, + &exception); + + CU_ASSERT_TRUE (success); + assert(success); // for Clang's static analyzer + + CU_ASSERT_FATAL(credential_token.class_id != NULL); + assert(credential_token.class_id); // for Clang's static analyzer + CU_ASSERT(strcmp(credential_token.class_id, AUTH_PROTOCOL_CLASS_ID) == 0); + CU_ASSERT(credential_token.properties._length == 2); + CU_ASSERT(credential_token.binary_properties._length == 0); + + c_id = find_property(&credential_token, "c.id"); + CU_ASSERT_FATAL(c_id != NULL); + CU_ASSERT_FATAL(c_id->value != NULL); + assert(c_id && c_id->value); // for Clang's static analyzer + //printf("c_id->value: %s\n", c_id->value); + CU_ASSERT(strcmp(c_id->value, REMOTE_IDENTITY_CERTIFICATE) == 0); + + c_perm = find_property(&credential_token, "c.perm"); + CU_ASSERT_FATAL(c_perm != NULL); + CU_ASSERT_FATAL(c_perm->value != NULL); + assert(c_perm && c_perm->value); // for Clang's static analyzer + //printf("c_perm->value: %s\n", c_perm->value); + CU_ASSERT(strcmp(c_perm->value, PERMISSIONS_DOCUMENT) == 0); + + success = g_auth->return_authenticated_peer_credential_token(g_auth, &credential_token, &exception); + CU_ASSERT_TRUE (success); + CU_ASSERT(credential_token.class_id == NULL); + CU_ASSERT(credential_token.properties._buffer == NULL); + CU_ASSERT(credential_token.properties._maximum == 0); + CU_ASSERT(credential_token.properties._length == 0); + CU_ASSERT(credential_token.binary_properties._buffer == NULL); + CU_ASSERT(credential_token.binary_properties._maximum == 0); + CU_ASSERT(credential_token.binary_properties._length == 0); + + success = g_auth->return_handshake_handle(g_auth, handshake_handle, &exception); + CU_ASSERT_TRUE (success); + + reset_exception(&exception); + + handshake_message_deinit(&handshake_reply_token_in); + handshake_message_deinit(&handshake_token_out); +} + +CU_Test(ddssec_builtin_get_authenticated_peer_credential,token_after_reply ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_final_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_final_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_AuthenticatedPeerCredentialToken credential_token = DDS_SECURITY_TOKEN_INIT; + DDS_Security_boolean success; + const DDS_Security_BinaryProperty_t *hash1_sentrequest; + const DDS_Security_BinaryProperty_t *hash2_sentreply; + const DDS_Security_BinaryProperty_t *challenge2_glb; + const DDS_Security_BinaryProperty_t *dh2; + const DDS_Security_Property_t *c_id; + const DDS_Security_Property_t *c_perm; + struct octet_seq dh2_pub_key; + + CU_ASSERT_FATAL (g_auth->process_handshake != NULL); + + CU_ASSERT_FATAL (g_auth != NULL); + CU_ASSERT_FATAL (g_local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (g_remote_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (g_auth->begin_handshake_reply != NULL); + + /* simulate reply */ + fill_handshake_message_token_default( + &handshake_token_in, + g_remote_participant_data1, + g_challenge1_predefined_glb->value._buffer, + g_challenge1_predefined_glb->value._length); + + result = g_auth->begin_handshake_reply( + g_auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + g_remote_identity_handle, + g_local_identity_handle, + &g_serialized_participant_data, + &exception); + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + assert(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); // for Clang's static analyzer + + /* mock final */ + dh2 = find_binary_property(&handshake_token_out, "dh2"); + dh2_pub_key.data = dh2->value._buffer; + dh2_pub_key.length = dh2->value._length; + challenge2_glb = find_binary_property(&handshake_token_out, "challenge2"); + hash1_sentrequest = find_binary_property(&handshake_token_out, "hash_c1"); + hash2_sentreply = find_binary_property(&handshake_token_out, "hash_c2"); + fill_handshake_message_token( + &handshake_final_token_in, + NULL, + REMOTE_IDENTITY_CERTIFICATE, + AUTH_DSIGN_ALGO_RSA_NAME, + AUTH_KAGREE_ALGO_ECDH_NAME, + &g_dh_modp_pub_key, + g_challenge1_predefined_glb->value._buffer, + g_challenge1_predefined_glb->value._length, + &dh2_pub_key, + challenge2_glb->value._buffer, + challenge2_glb->value._length, + hash1_sentrequest, + hash2_sentreply, + HANDSHAKE_FINAL); + + /* simulate process */ + result = g_auth->process_handshake( + g_auth, + &handshake_final_token_out, + &handshake_final_token_in, + handshake_handle, + &exception); + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_OK); + assert(result == DDS_SECURITY_VALIDATION_OK); // for Clang's static analyzer + + /* + * Actual test. + */ + success = g_auth->get_authenticated_peer_credential_token( + g_auth, + &credential_token, + handshake_handle, + &exception); + + CU_ASSERT_TRUE (success); + assert(success); // for Clang's static analyzer + + CU_ASSERT_FATAL(credential_token.class_id != NULL); + CU_ASSERT(strcmp(credential_token.class_id, AUTH_PROTOCOL_CLASS_ID) == 0); + CU_ASSERT(credential_token.properties._length == 2); + CU_ASSERT(credential_token.binary_properties._length == 0); + + c_id = find_property(&credential_token, "c.id"); + CU_ASSERT_FATAL(c_id != NULL); + CU_ASSERT_FATAL(c_id->value != NULL); + assert(c_id && c_id->value); // for Clang's static analyzer + //printf("c_id->value: %s\n", c_id->value); + CU_ASSERT(strcmp(c_id->value, REMOTE_IDENTITY_CERTIFICATE) == 0); + + c_perm = find_property(&credential_token, "c.perm"); + CU_ASSERT_FATAL(c_perm != NULL); + CU_ASSERT_FATAL(c_perm->value != NULL); + assert(c_perm && c_perm->value); // for Clang's static analyzer + //printf("c_perm->value: %s\n", c_perm->value); + CU_ASSERT(strcmp(c_perm->value, PERMISSIONS_DOCUMENT) == 0); + + + success = g_auth->return_authenticated_peer_credential_token(g_auth, &credential_token, &exception); + CU_ASSERT_TRUE (success); + CU_ASSERT(credential_token.class_id == NULL); + CU_ASSERT(credential_token.properties._buffer == NULL); + CU_ASSERT(credential_token.properties._maximum == 0); + CU_ASSERT(credential_token.properties._length == 0); + CU_ASSERT(credential_token.binary_properties._buffer == NULL); + CU_ASSERT(credential_token.binary_properties._maximum == 0); + CU_ASSERT(credential_token.binary_properties._length == 0); + + success = g_auth->return_handshake_handle(g_auth, handshake_handle, &exception); + CU_ASSERT_TRUE (success); + assert(success); // for Clang's static analyzer + + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + handshake_message_deinit(&handshake_final_token_in); + handshake_message_deinit(&handshake_final_token_out); +} + +CU_Test(ddssec_builtin_get_authenticated_peer_credential,token_invalid_arguments ) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_AuthenticatedPeerCredentialToken credential_token = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeHandle invalid_handle = 3; + DDS_Security_boolean success; + + success = g_auth->get_authenticated_peer_credential_token(g_auth, &credential_token, invalid_handle, &exception); + CU_ASSERT_FALSE (success); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + success = g_auth->get_authenticated_peer_credential_token(NULL, &credential_token, invalid_handle, &exception); + CU_ASSERT_FALSE (success); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + success = g_auth->get_authenticated_peer_credential_token(g_auth, NULL, invalid_handle, &exception); + CU_ASSERT_FALSE (success); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + success = g_auth->get_authenticated_peer_credential_token(g_auth, &credential_token, 0, &exception); + CU_ASSERT_FALSE (success); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + success = g_auth->return_authenticated_peer_credential_token(NULL, &credential_token, &exception); + CU_ASSERT_FALSE (success); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + success = g_auth->return_authenticated_peer_credential_token(g_auth, NULL, &exception); + CU_ASSERT_FALSE (success); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); +} diff --git a/src/security/builtin_plugins/tests/get_permissions_credential_token/etc/Test_Governance_ok.p7s b/src/security/builtin_plugins/tests/get_permissions_credential_token/etc/Test_Governance_ok.p7s new file mode 100644 index 0000000..c39903f --- /dev/null +++ b/src/security/builtin_plugins/tests/get_permissions_credential_token/etc/Test_Governance_ok.p7s @@ -0,0 +1,114 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----DB94A190D9780A24156FB0E8F1E76B5F" + +This is an S/MIME signed message + +------DB94A190D9780A24156FB0E8F1E76B5F +Content-Type: text/plain + + + + + + + + + 0 + 230 + + + + + false + + + true + + + ENCRYPT + + + ENCRYPT + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + ENCRYPT + + + ENCRYPT + + + + + + +------DB94A190D9780A24156FB0E8F1E76B5F +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGSAYJKoZIhvcNAQcCoIIGOTCCBjUCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCAnswggJ3AgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggeQwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTgwOTEzMDczOTUwWjAvBgkqhkiG9w0BCQQxIgQgXv8DkvlwebXMwHDbNc0/Pc30 +gyG3xWCnwet49TRMWFsweQYJKoZIhvcNAQkPMWwwajALBglghkgBZQMEASowCwYJ +YIZIAWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG9w0DAgIC +AIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwDQYJKoZI +hvcNAQEBBQAEggEANy8t0EFmv5j1n0+mMn2ut3Chu8PSJceC8gd34IiKq79uC1O3 +PbL9xgiJ2vz7QiTEEeNL2q+CG77cXOcHGUWa4nvbggr/9CqLfHEKGQxDfyXlJZfM +8l550xIXRRBOQ7ilOGLD4QJFfbf9XA4rMuRe8WEYN3FleAaYBJag1tMPg1SS6tgA +BBDM9b1kXHU319zYOk6kZFjlbwHv6XO22SEVRUpXrKudAI8hrGvwksF/+W0S/jS5 +NmYtj/1oMGlCGIaA5rs27H9CkgwrzoMQ3MsR98JlwEUSa4PEe8CClsIziOulQxsp +MicBlMWL0rzpBPVfPTE4gZ/kP7hGBDEQlRzVTA== + +------DB94A190D9780A24156FB0E8F1E76B5F-- + diff --git a/src/security/builtin_plugins/tests/get_permissions_credential_token/etc/Test_Permissions_ok.p7s b/src/security/builtin_plugins/tests/get_permissions_credential_token/etc/Test_Permissions_ok.p7s new file mode 100644 index 0000000..052075b --- /dev/null +++ b/src/security/builtin_plugins/tests/get_permissions_credential_token/etc/Test_Permissions_ok.p7s @@ -0,0 +1,85 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----6B91005B007BBA8EDE10CD1CE487DB27" + +This is an S/MIME signed message + +------6B91005B007BBA8EDE10CD1CE487DB27 +Content-Type: text/plain + + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + + + * + + + + DENY + + + + +------6B91005B007BBA8EDE10CD1CE487DB27 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgl3LfUhn9L0vG/3QRPVYptcYw +/NH5HMN99aMe9JAT+LAwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAHe9vakfXPvbpgMeqlhG +SW6Z3uVA3Yri9bgQDpJ9daIUsM0/TLBSQVs85twTMXvqUSntKbfSGehxDQ9F+yje +mOEPMIwxOqcVyc2jpqoYsUWqpwiiZyk49DHUFrOfWJUx+rKdBftZWkxD05Wkovhk +2d4hGS/65Haoho4Z0AZwcyH+F52FZMiqw7I9FKrPlhxvJfQXmhIjOKtnvWnQ+Ar7 +YYiSrBEHMCy82LF1aKzz0nkL1SYWQHuQX475qoU4LMYY1J8WsD3rSBeq4GYZrl2K +X/JcOquMYqjfJLMYZY4fsc3FgEBkKNqJz1tDZ3ir24VMl+WsbEjVK8oXe/wt4V0U +aNQ= + +------6B91005B007BBA8EDE10CD1CE487DB27-- + diff --git a/src/security/builtin_plugins/tests/get_permissions_credential_token/src/get_permissions_credential_token_utests.c b/src/security/builtin_plugins/tests/get_permissions_credential_token/src/get_permissions_credential_token_utests.c new file mode 100644 index 0000000..0a7c2b8 --- /dev/null +++ b/src/security/builtin_plugins/tests/get_permissions_credential_token/src/get_permissions_credential_token_utests.c @@ -0,0 +1,494 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include + +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/io.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "config_env.h" + +static const char *PERMISSIONS_FILE_NAME = "Test_Permissions_ok.p7s"; +static const char *GOVERNANCE_FILE_NAME = "Test_Governance_ok.p7s"; + +static const char *PROPERTY_IDENTITY_CA = "dds.sec.auth.identity_ca"; +static const char *PROPERTY_PRIVATE_KEY = "dds.sec.auth.private_key"; +static const char *PROPERTY_IDENTITY_CERT = "dds.sec.auth.identity_certificate"; +static const char *PROPERTY_PERMISSIONS_CA = "dds.sec.access.permissions_ca"; +static const char *PROPERTY_PERMISSIONS = "dds.sec.access.permissions"; +static const char *PROPERTY_GOVERNANCE = "dds.sec.access.governance"; + +static const char *RELATIVE_PATH_TO_ETC_DIR = "/get_permissions_credential_token/etc/"; + +static const char *IDENTITY_CERTIFICATE = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEQTCCAymgAwIBAgIINpuaAAnrQZIwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE3MDIy\n" + "MjIyMjIwMFoYDzIyMjIwMjIyMjIyMjAwWjBcMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRUwEwYDVQQDEwxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n" + "ggEKAoIBAQDCpVhivH/wBIyu74rvQncnSZqKyspN6CvD1pmV9wft5PHhVt9jV79v\n" + "gSub5LADoRHAgFdv9duYgBr17Ob6uRrIY4B18CcrCjhQcC4gjx8y2jl9PeYm+qYD\n" + "3o44FYBrBq0QCnrQgKsb/qX9Z+Mw/VUiw65x68W876LEHQQoEgT4kxSuagwBoVRk\n" + "ePD6fYAKmT4XS3x+O0v+rHESTcsKF6yMadgp7h3eH1b8kJTzSx8JV9Zzq++mxjox\n" + "qhbBVP5nDze2hhSIeCkCvSrx7efkgKS4AQXa5/Z44GiAu1TfXXUqdic9rxwD0edn\n" + "ajNElnZe7sjok/0yuqvH+2hSqpNva/zpAgMBAAGjggEAMIH9MAwGA1UdDwQFAwMH\n" + "/4AwgewGA1UdJQSB5DCB4QYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYI\n" + "KwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3AgEVBgorBgEEAYI3AgEWBgorBgEE\n" + "AYI3CgMBBgorBgEEAYI3CgMDBgorBgEEAYI3CgMEBglghkgBhvhCBAEGCysGAQQB\n" + "gjcKAwQBBggrBgEFBQcDBQYIKwYBBQUHAwYGCCsGAQUFBwMHBggrBgEFBQgCAgYK\n" + "KwYBBAGCNxQCAgYIKwYBBQUHAwkGCCsGAQUFBwMNBggrBgEFBQcDDgYHKwYBBQID\n" + "BTANBgkqhkiG9w0BAQsFAAOCAQEAawdHy0Xw7nTK2ltp91Ion6fJ7hqYuj///zr7\n" + "Adt6uonpDh/xl3esuwcFimIJrJrHujnGkL0nLddRCikmnzuBMNDWS6yq0/Ckl/YG\n" + "yjNr44dlX24wo+MVAgkj3/8CyWDZ3a8kBg9QT3bs2SqbjmhTrXN1DRyf9S5vJysE\n" + "I7V1gTN66BeKL64hOrAlRVrEu8Ds6TWL6Q/YH+61ViZkoLTeSaPjH4nknaFr4C35\n" + "iji0JhkyfRHRRVPHFnaj25AkxOrSV64qVKoTMjDl5fji5iMGtjm6iJ7q05ml/qDl\n" + "nLotHXemZNvYhbwUmRzbt4Dls9EMH4VRbP85I94nM5TAvtHVNA==\n" + "-----END CERTIFICATE-----\n"; + +static const char *IDENTITY_CA = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEmTCCA4GgAwIBAgIIZ5gEIUFhO5wwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDIx\n" + "MjE1MDUwMFoYDzIyMjIwMjIyMjIyMjAwWjBfMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRgwFgYDVQQDEw9DSEFNNTAwIHJvb3QgY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" + "DwAwggEKAoIBAQC6Fa3TheL+UrdZCp9GhU/2WbneP2t/avUa3muwDttPxeI2XU9k\n" + "ZjBR95mAXme4SPXHk5+YDN319AqIje3oKhzky/ngvKH2GkoJKYxWnuDBfMEHdViz\n" + "2Q9/xso2ZvH50ukwWa0pfx2/EVV1wRxeQcRd/UVfq3KTJizG0M88mOYvGEAw3LFf\n" + "zef7k1aCuOofQmBvLukUudcYpMzfyHFp7lQqU4CcrrR5RtmfiUfrWfdGLea2iPDB\n" + "pJgN8ESOMwEHtOTEBDclYnH9L4t7CHQz+fXXS5IWFsDK9fCMQjnxDsDVeNrNzTYL\n" + "FaZrMg9S6IUQCEsQWsnq5weS8omOpVLUm9klAgMBAAGjggFVMIIBUTAMBgNVHRME\n" + "BTADAQH/MB0GA1UdDgQWBBQg2FZB/j8uWDVnJhjwXkX278znSTAfBgNVHSMEGDAW\n" + "gBQg2FZB/j8uWDVnJhjwXkX278znSTAPBgNVHQ8BAf8EBQMDB/+AMIHvBgNVHSUB\n" + "Af8EgeQwgeEGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwME\n" + "BggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK\n" + "KwYBBAGCNwoDAwYKKwYBBAGCNwoDBAYJYIZIAYb4QgQBBgsrBgEEAYI3CgMEAQYI\n" + "KwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUIAgIGCisGAQQBgjcU\n" + "AgIGCCsGAQUFBwMJBggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZI\n" + "hvcNAQELBQADggEBAKHmwejWRwGE1wf1k2rG8SNRV/neGsZ6Qfqf6co3TpR/Wi1s\n" + "iZDvSeT/rbqNBS7z34xnG88NIUwu00y78e8Mfon31ZZbK4Uo7fla9/D3ukdJqPQC\n" + "LKdbKJjR2kH+KCukY/1rghjJ8/X+t2egBit0LCOdsFCl07Sfksb9kpGUIZSFcYYm\n" + "geqhjhoNwxazzHiw+QWHC5HG9248JIizBmy1aymNWuMnPudhjHAnPcsIlqMVNq3t\n" + "Rv9ap7S8JeCxHVRPJvJeCwXWvW3dW/v3xH52Yn/fqRblN1w9Fxz5NhopKx0gj/Jd\n" + "sw2N4Fk4gaOWEolFpa0bwNw8nAx7moehZpowzfw=\n" + "-----END CERTIFICATE-----\n"; + +static const char *PRIVATE_KEY = + "data:,-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEogIBAAKCAQEAwqVYYrx/8ASMru+K70J3J0maisrKTegrw9aZlfcH7eTx4Vbf\n" + "Y1e/b4Erm+SwA6ERwIBXb/XbmIAa9ezm+rkayGOAdfAnKwo4UHAuII8fMto5fT3m\n" + "JvqmA96OOBWAawatEAp60ICrG/6l/WfjMP1VIsOucevFvO+ixB0EKBIE+JMUrmoM\n" + "AaFUZHjw+n2ACpk+F0t8fjtL/qxxEk3LChesjGnYKe4d3h9W/JCU80sfCVfWc6vv\n" + "psY6MaoWwVT+Zw83toYUiHgpAr0q8e3n5ICkuAEF2uf2eOBogLtU3111KnYnPa8c\n" + "A9HnZ2ozRJZ2Xu7I6JP9Mrqrx/toUqqTb2v86QIDAQABAoIBAC1q32DKkx+yMBFx\n" + "m32QiLUGG6VfBC2BixS7MkMnzRXZYgcuehl4FBc0kLRjfB6cqsO8LqrVN1QyMBhK\n" + "GutN3c38SbE7RChqzhEW2+yE+Mao3Nk4ZEecHLiyaYT0n25ZtHAVwep823BAzwJ+\n" + "BykbM45VEpNKbG1VjSktjBa9faNyZiZAEJEjVyla+6R8N4kHV52LbZcLjvJv3IQ2\n" + "iPYRrmMyI5C23qTni0vy7yJbAXBo3CqgSlwie9FARBWT7Puu7F4mF1O1c/SnTysw\n" + "Tm3e5FzgfHipQbnRVn0w4rDprPMKmPxMnvf/Wkw0zVgNadp1Tc1I6Yj525DEQ07i\n" + "2gIn/gECgYEA4jNnY1u2Eu7x3pAQF3dRO0x35boVtuq9iwQk7q+uaZaK4RJRr+0Y\n" + "T68S3bPnfer6SHvcxtST89Bvs/j/Ky4SOaX037UYjFh6T7OIzPl+MzO1yb+VOBT6\n" + "D6FVGEJGp8ZAITU1OfJPeTYViUeEC8tHFGoKUCk50FbB6jOf1oKtv/ECgYEA3EnB\n" + "Y7kSbJJaUuj9ciFUL/pAno86Cim3VjegK1wKgEiyDb610bhoMErovPwfVJbtcttG\n" + "eKJNuwizkRcVbj+vpjDvqqaP5eMxLl6/Nd4haPMJYzGo88Z8NJpwFRNF2KEWjOpQ\n" + "2NEvoCeRtVulCJyka2Tpljzw8cOXkxhPOe2UhHkCgYBo3entj0QO7QXm56T+LAvV\n" + "0PK45xdQEO3EuCwjGAFk5C0IgUSrqeCeeIzniZMltj1IQ1wsNbtNynEu3530t8wt\n" + "O7oVyFBUKGSz9IjUdkpClJOPr6kPMfJoMqRPtdIpz+hFPPSrI6IikKdVWHloOlp+\n" + "pVaYqTQrWT1XRY2xli3VEQKBgGySmZN6Cx+h/oywswIGdUT0VdcQhq2to+QFpJba\n" + "VX6m1cM6hMip2Ag9U3qZ1SNPBBdBBfm9HQybHE3dj713/C2wHuAAGhpXIM1W+20k\n" + "X1knuC/AsSH9aQhQOf/ZMOq1crTfZBuI9q0782/sjGmzMsKPySU4QhUWruVb7OiD\n" + "NVkZAoGAEvihW7G+8/iOE40vGHyBqUeopAAWLciTAUIEwM/Oi3BYfNWNTWF/FWNc\n" + "nMvCZPYigY8C1vO+1iT2Frtd3CIU+f01Q3fJNJoRLlEiKLNZUJRF48OKUqjKSmsi\n" + "w6pucFO40z05YW7utApj4L82rZnOS0pd1tUI1yexqvj0i4ThJfk=\n" + "-----END RSA PRIVATE KEY-----\n"; + +static const char *PERMISSIONS_CA = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV\n" + "BAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQKDBZBRExJTksgVGVj\n" + "aG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNvbTAgFw0xODA3MzAx\n" + "MjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMCTkwxEzARBgNVBAgM\n" + "ClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4xFzAV\n" + "BgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" + "CgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blIDehV6XCxrnGXusTCD\n" + "uFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9wicp3BGSpZZax/TcO\n" + "NjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLsDFFC+a0qn2RFh37r\n" + "cWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074BRDXVivx+wVD951L\n" + "FNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiySogRWAmKhysLQudu\n" + "kHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNVHQ4EFgQURWMbWvBK\n" + "ZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJvRV1/tyc1R82k0+gw\n" + "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ysVtvHnk2hpu9yND\n" + "LCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9XVh0rGoR/6nHzo3TI\n" + "eiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9yghhKHHqNDvSsAL0\n" + "KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbtlLX3QnwVOmaRyzyl\n" + "PiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42+OyLqcH1rKT6Xhcs\n" + "hjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb6SDB340BFmtgDHbF\n" + "HQ==\n" + "-----END CERTIFICATE-----\n"; + +static char *permissions = NULL; +static char *g_path_to_etc_dir = NULL; +static struct plugins_hdl *plugins = NULL; +static dds_security_authentication *auth = NULL; +static dds_security_access_control *access_control = NULL; + +static DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_PermissionsHandle local_permissions_handle = DDS_SECURITY_HANDLE_NIL; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static DDS_Security_Property_t *find_property(DDS_Security_DataHolder *token, const char *name) +{ + DDS_Security_Property_t *result = NULL; + uint32_t i; + + for (i = 0; i < token->properties._length && !result; i++) + if (token->properties._buffer[i].name && (strcmp(token->properties._buffer[i].name, name) == 0)) + result = &token->properties._buffer[i]; + return result; +} + +static void dds_security_property_init(DDS_Security_PropertySeq *seq, DDS_Security_unsigned_long size) +{ + seq->_length = size; + seq->_maximum = size; + seq->_buffer = ddsrt_malloc(size * sizeof(DDS_Security_Property_t)); + memset(seq->_buffer, 0, size * sizeof(DDS_Security_Property_t)); +} + +static void dds_security_property_deinit(DDS_Security_PropertySeq *seq) +{ + uint32_t i; + for (i = 0; i < seq->_length; i++) + { + ddsrt_free(seq->_buffer[i].name); + ddsrt_free(seq->_buffer[i].value); + } + ddsrt_free(seq->_buffer); +} + +static char *read_document_from_file(const char *filename) +{ + char *document; + char *normalized; + char *name; + + /* Get proper file name. */ + ddsrt_asprintf(&name, "%s%s", g_path_to_etc_dir, filename); + normalized = DDS_Security_normalize_file(name); + ddsrt_free(name); + document = load_file_contents(normalized); + + ddsrt_free(normalized); + + return document; +} + +static void fill_participant_qos(DDS_Security_Qos *qos, const char *permission_filename, const char *governance_filename) +{ + char *permission_uri; + char *governance_uri; + + ddsrt_asprintf(&permission_uri, "file:%s%s", g_path_to_etc_dir, permission_filename); + ddsrt_asprintf(&governance_uri, "file:%s%s", g_path_to_etc_dir, governance_filename); + + memset(qos, 0, sizeof(*qos)); + dds_security_property_init(&qos->property.value, 6); + qos->property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + qos->property.value._buffer[0].value = ddsrt_strdup(IDENTITY_CERTIFICATE); + qos->property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + qos->property.value._buffer[1].value = ddsrt_strdup(IDENTITY_CA); + qos->property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + qos->property.value._buffer[2].value = ddsrt_strdup(PRIVATE_KEY); + qos->property.value._buffer[3].name = ddsrt_strdup(PROPERTY_PERMISSIONS_CA); + qos->property.value._buffer[3].value = ddsrt_strdup(PERMISSIONS_CA); + qos->property.value._buffer[4].name = ddsrt_strdup(PROPERTY_PERMISSIONS); + qos->property.value._buffer[4].value = ddsrt_strdup(permission_uri); + qos->property.value._buffer[5].name = ddsrt_strdup(PROPERTY_GOVERNANCE); + qos->property.value._buffer[5].value = ddsrt_strdup(governance_uri); + + ddsrt_free(permission_uri); + ddsrt_free(governance_uri); +} + +static int local_permissions_init(DDS_Security_DomainId domain_id) +{ + int res = 0; + DDS_Security_ValidationResult_t result; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t local_participant_guid; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb}; + DDS_Security_EntityId_t entityId = {{0xb0, 0xb1, 0xb2}, 0x1}; + + memset(&local_participant_guid, 0, sizeof(local_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, PERMISSIONS_FILE_NAME, GOVERNANCE_FILE_NAME); + + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &local_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) + { + res = -1; + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + reset_exception(&exception); + + if (res == 0) + { + local_permissions_handle = access_control->validate_local_permissions( + access_control, + auth, + local_identity_handle, + domain_id, + &participant_qos, + &exception); + + if (local_permissions_handle == DDS_SECURITY_HANDLE_NIL) + { + res = -1; + printf("validate_local_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + } + + reset_exception(&exception); + + dds_security_property_deinit(&participant_qos.property.value); + + return res; +} + +static void local_permissions_clean(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (local_permissions_handle != DDS_SECURITY_HANDLE_NIL) + { + success = access_control->return_permissions_handle(access_control, local_permissions_handle, &exception); + if (!success) + { + printf("return_permission_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } + + if (local_identity_handle != DDS_SECURITY_HANDLE_NIL) + { + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + if (!success) + { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } +} + +static void set_path_to_etc_dir(void) +{ + ddsrt_asprintf(&g_path_to_etc_dir, "%s%s", CONFIG_ENV_TESTS_DIR, RELATIVE_PATH_TO_ETC_DIR); +} + +static void suite_get_permissions_credential_token_init(void) +{ + plugins = load_plugins(&access_control, &auth, NULL /* Cryptograpy */); + CU_ASSERT_FATAL (plugins != NULL); + set_path_to_etc_dir(); + local_permissions_init(0); + permissions = read_document_from_file(PERMISSIONS_FILE_NAME); + CU_ASSERT_FATAL (permissions != NULL); +} + +static void suite_get_permissions_credential_token_fini(void) +{ + local_permissions_clean(); + unload_plugins(plugins); + ddsrt_free(g_path_to_etc_dir); + ddsrt_free(permissions); +} + +static bool validate_permissions_token(DDS_Security_PermissionsCredentialToken *token) +{ + DDS_Security_Property_t *property; + + if (!token->class_id || strcmp(token->class_id, "DDS:Access:PermissionsCredential") != 0) + { + CU_FAIL("PermissionsCredentialToken incorrect class_id"); + return false; + } + + property = find_property(token, "dds.perm.cert"); + if (property == NULL) + { + CU_FAIL("PermissionsCredentialToken property 'dds.perm.cert' not found"); + return false; + } + if (property->value == NULL) + { + CU_FAIL("PermissionsCredentialToken property 'dds.perm.cert' does not have a value"); + return false; + } + if (strcmp(property->value, permissions) != 0) + { + CU_FAIL("PermissionsCredentialToken property 'dds.perm.cert' content does not match the permissions file"); + return false; + } + + return true; +} + +CU_Test(ddssec_builtin_get_permissions_credential_token, happy_day, .init = suite_get_permissions_credential_token_init, .fini = suite_get_permissions_credential_token_fini) +{ + DDS_Security_PermissionsCredentialToken token; + DDS_Security_SecurityException exception; + DDS_Security_boolean result; + + /* Pre-requisites. */ + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_permissions_credential_token != NULL); + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&token, 0, sizeof(token)); + + /* Test function call. */ + result = access_control->get_permissions_credential_token( + access_control, + &token, + local_permissions_handle, + &exception); + if (!result) + { + printf("get_permissions_credential_token: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + /* Test token contents. */ + CU_ASSERT(validate_permissions_token(&token)); + + /* Post-requisites. */ + DDS_Security_DataHolder_deinit(&token); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_get_permissions_credential_token, invalid_args, .init = suite_get_permissions_credential_token_init, .fini = suite_get_permissions_credential_token_fini) +{ + DDS_Security_PermissionsCredentialToken token; + DDS_Security_SecurityException exception; + DDS_Security_boolean result; + + /* Pre-requisites. */ + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_permissions_token != NULL); + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&token, 0, sizeof(token)); + + /* Test function calls with different invalid args. */ + result = access_control->get_permissions_credential_token( + NULL, + &token, + local_permissions_handle, + &exception); + if (!result) + { + printf("get_permissions_token: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT(!result); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + result = access_control->get_permissions_credential_token( + access_control, + NULL, + local_permissions_handle, + &exception); + if (!result) + { + printf("get_permissions_credential_token: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT(!result); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + result = access_control->get_permissions_credential_token( + access_control, + &token, + 0, + &exception); + if (!result) + { + printf("get_permissions_credential_token: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT(!result); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + result = access_control->get_permissions_credential_token( + access_control, + &token, + local_permissions_handle, + NULL); + if (!result) + { + printf("get_permissions_credential_token: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT(!result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + reset_exception(&exception); + + result = access_control->get_permissions_credential_token( + access_control, + &token, + local_permissions_handle + 12345 /* invalid handle */, + &exception); + if (!result) + { + printf("get_permissions_credential_token: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT(!result); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); +} + diff --git a/src/security/builtin_plugins/tests/get_permissions_token/etc/Test_Governance_ok.p7s b/src/security/builtin_plugins/tests/get_permissions_token/etc/Test_Governance_ok.p7s new file mode 100644 index 0000000..c39903f --- /dev/null +++ b/src/security/builtin_plugins/tests/get_permissions_token/etc/Test_Governance_ok.p7s @@ -0,0 +1,114 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----DB94A190D9780A24156FB0E8F1E76B5F" + +This is an S/MIME signed message + +------DB94A190D9780A24156FB0E8F1E76B5F +Content-Type: text/plain + + + + + + + + + 0 + 230 + + + + + false + + + true + + + ENCRYPT + + + ENCRYPT + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + ENCRYPT + + + ENCRYPT + + + + + + +------DB94A190D9780A24156FB0E8F1E76B5F +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGSAYJKoZIhvcNAQcCoIIGOTCCBjUCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCAnswggJ3AgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggeQwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTgwOTEzMDczOTUwWjAvBgkqhkiG9w0BCQQxIgQgXv8DkvlwebXMwHDbNc0/Pc30 +gyG3xWCnwet49TRMWFsweQYJKoZIhvcNAQkPMWwwajALBglghkgBZQMEASowCwYJ +YIZIAWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG9w0DAgIC +AIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwDQYJKoZI +hvcNAQEBBQAEggEANy8t0EFmv5j1n0+mMn2ut3Chu8PSJceC8gd34IiKq79uC1O3 +PbL9xgiJ2vz7QiTEEeNL2q+CG77cXOcHGUWa4nvbggr/9CqLfHEKGQxDfyXlJZfM +8l550xIXRRBOQ7ilOGLD4QJFfbf9XA4rMuRe8WEYN3FleAaYBJag1tMPg1SS6tgA +BBDM9b1kXHU319zYOk6kZFjlbwHv6XO22SEVRUpXrKudAI8hrGvwksF/+W0S/jS5 +NmYtj/1oMGlCGIaA5rs27H9CkgwrzoMQ3MsR98JlwEUSa4PEe8CClsIziOulQxsp +MicBlMWL0rzpBPVfPTE4gZ/kP7hGBDEQlRzVTA== + +------DB94A190D9780A24156FB0E8F1E76B5F-- + diff --git a/src/security/builtin_plugins/tests/get_permissions_token/etc/Test_Permissions_ok.p7s b/src/security/builtin_plugins/tests/get_permissions_token/etc/Test_Permissions_ok.p7s new file mode 100644 index 0000000..052075b --- /dev/null +++ b/src/security/builtin_plugins/tests/get_permissions_token/etc/Test_Permissions_ok.p7s @@ -0,0 +1,85 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----6B91005B007BBA8EDE10CD1CE487DB27" + +This is an S/MIME signed message + +------6B91005B007BBA8EDE10CD1CE487DB27 +Content-Type: text/plain + + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + + + * + + + + DENY + + + + +------6B91005B007BBA8EDE10CD1CE487DB27 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgl3LfUhn9L0vG/3QRPVYptcYw +/NH5HMN99aMe9JAT+LAwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAHe9vakfXPvbpgMeqlhG +SW6Z3uVA3Yri9bgQDpJ9daIUsM0/TLBSQVs85twTMXvqUSntKbfSGehxDQ9F+yje +mOEPMIwxOqcVyc2jpqoYsUWqpwiiZyk49DHUFrOfWJUx+rKdBftZWkxD05Wkovhk +2d4hGS/65Haoho4Z0AZwcyH+F52FZMiqw7I9FKrPlhxvJfQXmhIjOKtnvWnQ+Ar7 +YYiSrBEHMCy82LF1aKzz0nkL1SYWQHuQX475qoU4LMYY1J8WsD3rSBeq4GYZrl2K +X/JcOquMYqjfJLMYZY4fsc3FgEBkKNqJz1tDZ3ir24VMl+WsbEjVK8oXe/wt4V0U +aNQ= + +------6B91005B007BBA8EDE10CD1CE487DB27-- + diff --git a/src/security/builtin_plugins/tests/get_permissions_token/src/get_permissions_token_utests.c b/src/security/builtin_plugins/tests/get_permissions_token/src/get_permissions_token_utests.c new file mode 100644 index 0000000..5d39735 --- /dev/null +++ b/src/security/builtin_plugins/tests/get_permissions_token/src/get_permissions_token_utests.c @@ -0,0 +1,436 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/io.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "config_env.h" + +static const char *PROPERTY_IDENTITY_CA = "dds.sec.auth.identity_ca"; +static const char *PROPERTY_PRIVATE_KEY = "dds.sec.auth.private_key"; +static const char *PROPERTY_IDENTITY_CERT = "dds.sec.auth.identity_certificate"; +static const char *PROPERTY_PERMISSIONS_CA = "dds.sec.access.permissions_ca"; +static const char *PROPERTY_PERMISSIONS = "dds.sec.access.permissions"; +static const char *PROPERTY_GOVERNANCE = "dds.sec.access.governance"; + +static const char *RELATIVE_PATH_TO_ETC_DIR = "/get_permissions_token/etc/"; + +static const char *IDENTITY_CERTIFICATE = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEQTCCAymgAwIBAgIINpuaAAnrQZIwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE3MDIy\n" + "MjIyMjIwMFoYDzIyMjIwMjIyMjIyMjAwWjBcMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRUwEwYDVQQDEwxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n" + "ggEKAoIBAQDCpVhivH/wBIyu74rvQncnSZqKyspN6CvD1pmV9wft5PHhVt9jV79v\n" + "gSub5LADoRHAgFdv9duYgBr17Ob6uRrIY4B18CcrCjhQcC4gjx8y2jl9PeYm+qYD\n" + "3o44FYBrBq0QCnrQgKsb/qX9Z+Mw/VUiw65x68W876LEHQQoEgT4kxSuagwBoVRk\n" + "ePD6fYAKmT4XS3x+O0v+rHESTcsKF6yMadgp7h3eH1b8kJTzSx8JV9Zzq++mxjox\n" + "qhbBVP5nDze2hhSIeCkCvSrx7efkgKS4AQXa5/Z44GiAu1TfXXUqdic9rxwD0edn\n" + "ajNElnZe7sjok/0yuqvH+2hSqpNva/zpAgMBAAGjggEAMIH9MAwGA1UdDwQFAwMH\n" + "/4AwgewGA1UdJQSB5DCB4QYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYI\n" + "KwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3AgEVBgorBgEEAYI3AgEWBgorBgEE\n" + "AYI3CgMBBgorBgEEAYI3CgMDBgorBgEEAYI3CgMEBglghkgBhvhCBAEGCysGAQQB\n" + "gjcKAwQBBggrBgEFBQcDBQYIKwYBBQUHAwYGCCsGAQUFBwMHBggrBgEFBQgCAgYK\n" + "KwYBBAGCNxQCAgYIKwYBBQUHAwkGCCsGAQUFBwMNBggrBgEFBQcDDgYHKwYBBQID\n" + "BTANBgkqhkiG9w0BAQsFAAOCAQEAawdHy0Xw7nTK2ltp91Ion6fJ7hqYuj///zr7\n" + "Adt6uonpDh/xl3esuwcFimIJrJrHujnGkL0nLddRCikmnzuBMNDWS6yq0/Ckl/YG\n" + "yjNr44dlX24wo+MVAgkj3/8CyWDZ3a8kBg9QT3bs2SqbjmhTrXN1DRyf9S5vJysE\n" + "I7V1gTN66BeKL64hOrAlRVrEu8Ds6TWL6Q/YH+61ViZkoLTeSaPjH4nknaFr4C35\n" + "iji0JhkyfRHRRVPHFnaj25AkxOrSV64qVKoTMjDl5fji5iMGtjm6iJ7q05ml/qDl\n" + "nLotHXemZNvYhbwUmRzbt4Dls9EMH4VRbP85I94nM5TAvtHVNA==\n" + "-----END CERTIFICATE-----\n"; + +static const char *IDENTITY_CA = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEmTCCA4GgAwIBAgIIZ5gEIUFhO5wwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDIx\n" + "MjE1MDUwMFoYDzIyMjIwMjIyMjIyMjAwWjBfMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRgwFgYDVQQDEw9DSEFNNTAwIHJvb3QgY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" + "DwAwggEKAoIBAQC6Fa3TheL+UrdZCp9GhU/2WbneP2t/avUa3muwDttPxeI2XU9k\n" + "ZjBR95mAXme4SPXHk5+YDN319AqIje3oKhzky/ngvKH2GkoJKYxWnuDBfMEHdViz\n" + "2Q9/xso2ZvH50ukwWa0pfx2/EVV1wRxeQcRd/UVfq3KTJizG0M88mOYvGEAw3LFf\n" + "zef7k1aCuOofQmBvLukUudcYpMzfyHFp7lQqU4CcrrR5RtmfiUfrWfdGLea2iPDB\n" + "pJgN8ESOMwEHtOTEBDclYnH9L4t7CHQz+fXXS5IWFsDK9fCMQjnxDsDVeNrNzTYL\n" + "FaZrMg9S6IUQCEsQWsnq5weS8omOpVLUm9klAgMBAAGjggFVMIIBUTAMBgNVHRME\n" + "BTADAQH/MB0GA1UdDgQWBBQg2FZB/j8uWDVnJhjwXkX278znSTAfBgNVHSMEGDAW\n" + "gBQg2FZB/j8uWDVnJhjwXkX278znSTAPBgNVHQ8BAf8EBQMDB/+AMIHvBgNVHSUB\n" + "Af8EgeQwgeEGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwME\n" + "BggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK\n" + "KwYBBAGCNwoDAwYKKwYBBAGCNwoDBAYJYIZIAYb4QgQBBgsrBgEEAYI3CgMEAQYI\n" + "KwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUIAgIGCisGAQQBgjcU\n" + "AgIGCCsGAQUFBwMJBggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZI\n" + "hvcNAQELBQADggEBAKHmwejWRwGE1wf1k2rG8SNRV/neGsZ6Qfqf6co3TpR/Wi1s\n" + "iZDvSeT/rbqNBS7z34xnG88NIUwu00y78e8Mfon31ZZbK4Uo7fla9/D3ukdJqPQC\n" + "LKdbKJjR2kH+KCukY/1rghjJ8/X+t2egBit0LCOdsFCl07Sfksb9kpGUIZSFcYYm\n" + "geqhjhoNwxazzHiw+QWHC5HG9248JIizBmy1aymNWuMnPudhjHAnPcsIlqMVNq3t\n" + "Rv9ap7S8JeCxHVRPJvJeCwXWvW3dW/v3xH52Yn/fqRblN1w9Fxz5NhopKx0gj/Jd\n" + "sw2N4Fk4gaOWEolFpa0bwNw8nAx7moehZpowzfw=\n" + "-----END CERTIFICATE-----\n"; + +static const char *PRIVATE_KEY = + "data:,-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEogIBAAKCAQEAwqVYYrx/8ASMru+K70J3J0maisrKTegrw9aZlfcH7eTx4Vbf\n" + "Y1e/b4Erm+SwA6ERwIBXb/XbmIAa9ezm+rkayGOAdfAnKwo4UHAuII8fMto5fT3m\n" + "JvqmA96OOBWAawatEAp60ICrG/6l/WfjMP1VIsOucevFvO+ixB0EKBIE+JMUrmoM\n" + "AaFUZHjw+n2ACpk+F0t8fjtL/qxxEk3LChesjGnYKe4d3h9W/JCU80sfCVfWc6vv\n" + "psY6MaoWwVT+Zw83toYUiHgpAr0q8e3n5ICkuAEF2uf2eOBogLtU3111KnYnPa8c\n" + "A9HnZ2ozRJZ2Xu7I6JP9Mrqrx/toUqqTb2v86QIDAQABAoIBAC1q32DKkx+yMBFx\n" + "m32QiLUGG6VfBC2BixS7MkMnzRXZYgcuehl4FBc0kLRjfB6cqsO8LqrVN1QyMBhK\n" + "GutN3c38SbE7RChqzhEW2+yE+Mao3Nk4ZEecHLiyaYT0n25ZtHAVwep823BAzwJ+\n" + "BykbM45VEpNKbG1VjSktjBa9faNyZiZAEJEjVyla+6R8N4kHV52LbZcLjvJv3IQ2\n" + "iPYRrmMyI5C23qTni0vy7yJbAXBo3CqgSlwie9FARBWT7Puu7F4mF1O1c/SnTysw\n" + "Tm3e5FzgfHipQbnRVn0w4rDprPMKmPxMnvf/Wkw0zVgNadp1Tc1I6Yj525DEQ07i\n" + "2gIn/gECgYEA4jNnY1u2Eu7x3pAQF3dRO0x35boVtuq9iwQk7q+uaZaK4RJRr+0Y\n" + "T68S3bPnfer6SHvcxtST89Bvs/j/Ky4SOaX037UYjFh6T7OIzPl+MzO1yb+VOBT6\n" + "D6FVGEJGp8ZAITU1OfJPeTYViUeEC8tHFGoKUCk50FbB6jOf1oKtv/ECgYEA3EnB\n" + "Y7kSbJJaUuj9ciFUL/pAno86Cim3VjegK1wKgEiyDb610bhoMErovPwfVJbtcttG\n" + "eKJNuwizkRcVbj+vpjDvqqaP5eMxLl6/Nd4haPMJYzGo88Z8NJpwFRNF2KEWjOpQ\n" + "2NEvoCeRtVulCJyka2Tpljzw8cOXkxhPOe2UhHkCgYBo3entj0QO7QXm56T+LAvV\n" + "0PK45xdQEO3EuCwjGAFk5C0IgUSrqeCeeIzniZMltj1IQ1wsNbtNynEu3530t8wt\n" + "O7oVyFBUKGSz9IjUdkpClJOPr6kPMfJoMqRPtdIpz+hFPPSrI6IikKdVWHloOlp+\n" + "pVaYqTQrWT1XRY2xli3VEQKBgGySmZN6Cx+h/oywswIGdUT0VdcQhq2to+QFpJba\n" + "VX6m1cM6hMip2Ag9U3qZ1SNPBBdBBfm9HQybHE3dj713/C2wHuAAGhpXIM1W+20k\n" + "X1knuC/AsSH9aQhQOf/ZMOq1crTfZBuI9q0782/sjGmzMsKPySU4QhUWruVb7OiD\n" + "NVkZAoGAEvihW7G+8/iOE40vGHyBqUeopAAWLciTAUIEwM/Oi3BYfNWNTWF/FWNc\n" + "nMvCZPYigY8C1vO+1iT2Frtd3CIU+f01Q3fJNJoRLlEiKLNZUJRF48OKUqjKSmsi\n" + "w6pucFO40z05YW7utApj4L82rZnOS0pd1tUI1yexqvj0i4ThJfk=\n" + "-----END RSA PRIVATE KEY-----\n"; + +static const char *PERMISSIONS_CA = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV\n" + "BAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQKDBZBRExJTksgVGVj\n" + "aG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNvbTAgFw0xODA3MzAx\n" + "MjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMCTkwxEzARBgNVBAgM\n" + "ClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4xFzAV\n" + "BgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" + "CgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blIDehV6XCxrnGXusTCD\n" + "uFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9wicp3BGSpZZax/TcO\n" + "NjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLsDFFC+a0qn2RFh37r\n" + "cWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074BRDXVivx+wVD951L\n" + "FNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiySogRWAmKhysLQudu\n" + "kHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNVHQ4EFgQURWMbWvBK\n" + "ZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJvRV1/tyc1R82k0+gw\n" + "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ysVtvHnk2hpu9yND\n" + "LCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9XVh0rGoR/6nHzo3TI\n" + "eiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9yghhKHHqNDvSsAL0\n" + "KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbtlLX3QnwVOmaRyzyl\n" + "PiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42+OyLqcH1rKT6Xhcs\n" + "hjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb6SDB340BFmtgDHbF\n" + "HQ==\n" + "-----END CERTIFICATE-----\n"; + +static char *g_path_to_etc_dir = NULL; +static struct plugins_hdl *plugins = NULL; +static dds_security_authentication *auth = NULL; +static dds_security_access_control *access_control = NULL; + +static DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_PermissionsHandle local_permissions_handle = DDS_SECURITY_HANDLE_NIL; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static DDS_Security_Property_t *find_property(DDS_Security_DataHolder *token, const char *name) +{ + DDS_Security_Property_t *result = NULL; + uint32_t i; + for (i = 0; i < token->properties._length && !result; i++) + if (token->properties._buffer[i].name && (strcmp(token->properties._buffer[i].name, name) == 0)) + result = &token->properties._buffer[i]; + return result; +} + +static void dds_security_property_init(DDS_Security_PropertySeq *seq, DDS_Security_unsigned_long size) +{ + seq->_length = size; + seq->_maximum = size; + seq->_buffer = ddsrt_malloc(size * sizeof(DDS_Security_Property_t)); + memset(seq->_buffer, 0, size * sizeof(DDS_Security_Property_t)); +} + +static void dds_security_property_deinit(DDS_Security_PropertySeq *seq) +{ + uint32_t i; + for (i = 0; i < seq->_length; i++) + { + ddsrt_free(seq->_buffer[i].name); + ddsrt_free(seq->_buffer[i].value); + } + ddsrt_free(seq->_buffer); +} + +static void fill_participant_qos(DDS_Security_Qos *qos, const char *permission_filename, const char *governance_filename) +{ + char *permission_uri; + char *governance_uri; + + ddsrt_asprintf(&permission_uri, "file:%s%s", g_path_to_etc_dir, permission_filename); + ddsrt_asprintf(&governance_uri, "file:%s%s", g_path_to_etc_dir, governance_filename); + + memset(qos, 0, sizeof(*qos)); + dds_security_property_init(&qos->property.value, 6); + qos->property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + qos->property.value._buffer[0].value = ddsrt_strdup(IDENTITY_CERTIFICATE); + qos->property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + qos->property.value._buffer[1].value = ddsrt_strdup(IDENTITY_CA); + qos->property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + qos->property.value._buffer[2].value = ddsrt_strdup(PRIVATE_KEY); + qos->property.value._buffer[3].name = ddsrt_strdup(PROPERTY_PERMISSIONS_CA); + qos->property.value._buffer[3].value = ddsrt_strdup(PERMISSIONS_CA); + qos->property.value._buffer[4].name = ddsrt_strdup(PROPERTY_PERMISSIONS); + qos->property.value._buffer[4].value = ddsrt_strdup(permission_uri); + qos->property.value._buffer[5].name = ddsrt_strdup(PROPERTY_GOVERNANCE); + qos->property.value._buffer[5].value = ddsrt_strdup(governance_uri); + + ddsrt_free(permission_uri); + ddsrt_free(governance_uri); +} + +static void local_permissions_init(DDS_Security_DomainId domain_id) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t local_participant_guid; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb}; + DDS_Security_EntityId_t entityId = {{0xb0, 0xb1, 0xb2}, 0x1}; + + memset(&local_participant_guid, 0, sizeof(local_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, "Test_Permissions_ok.p7s", "Test_Governance_ok.p7s"); + + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &local_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + CU_ASSERT_EQUAL_FATAL (result, DDS_SECURITY_VALIDATION_OK); + reset_exception(&exception); + local_permissions_handle = access_control->validate_local_permissions( + access_control, + auth, + local_identity_handle, + domain_id, + &participant_qos, + &exception); + + CU_ASSERT_FATAL (local_permissions_handle != DDS_SECURITY_HANDLE_NIL); + reset_exception(&exception); + dds_security_property_deinit(&participant_qos.property.value); +} + +static void local_permissions_clean(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (local_permissions_handle != DDS_SECURITY_HANDLE_NIL) + { + success = access_control->return_permissions_handle(access_control, local_permissions_handle, &exception); + if (!success) + { + printf("return_permission_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } + + if (local_identity_handle != DDS_SECURITY_HANDLE_NIL) + { + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + if (!success) + { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } +} + +static void set_path_to_etc_dir(void) +{ + ddsrt_asprintf(&g_path_to_etc_dir, "%s%s", CONFIG_ENV_TESTS_DIR, RELATIVE_PATH_TO_ETC_DIR); +} + +static void suite_get_permissions_token_init(void) +{ + plugins = load_plugins(&access_control, &auth, NULL /* Cryptograpy */); + CU_ASSERT_FATAL (plugins != NULL); + set_path_to_etc_dir(); + local_permissions_init(0); +} + +static void suite_get_permissions_token_fini(void) +{ + local_permissions_clean(); + unload_plugins(plugins); + ddsrt_free(g_path_to_etc_dir); +} + +static bool validate_permissions_token( + DDS_Security_PermissionsToken *token) +{ + if (!token->class_id || strcmp(token->class_id, "DDS:Access:Permissions:1.0") != 0) + { + CU_FAIL("PermissionsToken incorrect class_id"); + return false; + } + + /* Optional. */ + if (find_property(token, "dds.perm_ca.sn") == NULL) + printf("Optional PermissionsToken property 'dds.perm_ca.sn' not found\n"); + if (find_property(token, "dds.perm_ca.algo") == NULL) + printf("Optional PermissionsToken property 'dds.perm_ca.algo' not found\n"); + return true; +} + +CU_Test(ddssec_builtin_get_permissions_token, happy_day, .init = suite_get_permissions_token_init, .fini = suite_get_permissions_token_fini) +{ + DDS_Security_SecurityException exception; + DDS_Security_PermissionsToken token; + DDS_Security_boolean result; + + /* Pre-requisites. */ + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_permissions_token != NULL); + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&token, 0, sizeof(token)); + + /* Test function call. */ + result = access_control->get_permissions_token( + access_control, + &token, + local_permissions_handle, + &exception); + if (!result) + { + printf("get_permissions_token: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + /* Test token contents. */ + CU_ASSERT(validate_permissions_token(&token)); + + /* Post-requisites. */ + DDS_Security_DataHolder_deinit(&token); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_get_permissions_token, invalid_args, .init = suite_get_permissions_token_init, .fini = suite_get_permissions_token_fini) +{ + DDS_Security_SecurityException exception; + DDS_Security_PermissionsToken token; + DDS_Security_boolean result; + + /* Pre-requisites. */ + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_permissions_token != NULL); + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&token, 0, sizeof(token)); + + /* Test function calls with different invalid args. */ + result = access_control->get_permissions_token( + NULL, + &token, + local_permissions_handle, + &exception); + if (!result) + { + printf("get_permissions_token: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT(!result); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + result = access_control->get_permissions_token( + access_control, + NULL, + local_permissions_handle, + &exception); + if (!result) + { + printf("get_permissions_token: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT(!result); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + result = access_control->get_permissions_token( + access_control, + &token, + 0, + &exception); + if (!result) + { + printf("get_permissions_token: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT(!result); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + result = access_control->get_permissions_token( + access_control, + &token, + local_permissions_handle, + NULL); + if (!result) + { + printf("get_permissions_token: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT(!result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + reset_exception(&exception); + + result = access_control->get_permissions_token( + access_control, + &token, + local_permissions_handle + 12345 /* invalid handle */, + &exception); + if (!result) + { + printf("get_permissions_token: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT(!result); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); +} diff --git a/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_full.p7s b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_full.p7s new file mode 100644 index 0000000..4ea8fe8 --- /dev/null +++ b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_full.p7s @@ -0,0 +1,267 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----05DBD6F6E587875751A79EAC78048D60" + +This is an S/MIME signed message + +------05DBD6F6E587875751A79EAC78048D60 +Content-Type: text/plain + + + + + + + + 20 + + 0 + 23 + + + 100 + 120 + + 200 + + + + false + + + TRUE + + + SIGN_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + + + + OwnShip?ata + + + FALSE + + + false + + + false + + + true + + + SIGN + + + ENCRYPT + + + + + Kinematics + + + true + + + true + + + true + + + false + + + NONE + + + NONE + + + + + *other + + + true + + + true + + + true + + + true + + + NONE + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT + + + + + + + + 100 + 120 + + 20 + + 0 + 23 + + 200 + 30 + + + + 1 + + + 0 + + + SIGN + + + ENCRYPT + + + NONE + + + + + OwnShipData + + + true + + + true + + + false + + + false + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT + + + + + + + + +------05DBD6F6E587875751A79EAC78048D60 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQg0GyBZYdNlmQT2Nv1CHrUEB6+ +C0U0yXvpmj5+mlGojPAwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAJXrVHO7KdgYM20uGGNL +P4VRPmYVWoWIkl5/OEzZ8uirs+oGJR7tYLiFl1wzXUzPBB/03qsANmlshDpFgbmV +thTV7AGRg3SXUDa/cG4N9PupE5VRZaVdbcbdH1DfoIZCLLp4HK3HgqUXkH9vnC92 +tdtgzxZOCrQ4A6WbGiBkWr5LtMWg2lnwPp55vrfRoh6u0qVEumD+VQi+Lroo9M1E +659LB2dwEcNb1g1HyoodpKlUSsbGsY/JA7bbNrw/KIGVYcoXfmpgWmtzUjfpkPDj +zVPImqr6jdxP4quGmGWRmrLHPrEYJscJqCwjNTi6naXnAvaE4nxQ4HBgveEodTuP +8tM= + +------05DBD6F6E587875751A79EAC78048D60-- + diff --git a/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_clear.p7s b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_clear.p7s new file mode 100644 index 0000000..3ef33a2 --- /dev/null +++ b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_clear.p7s @@ -0,0 +1,114 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----D5AADCFDEEF9EC8B0B116AC356AF41CA" + +This is an S/MIME signed message + +------D5AADCFDEEF9EC8B0B116AC356AF41CA +Content-Type: text/plain + + + + + + + + + 0 + 230 + + + + + false + + + TRUE + + + NONE + + + NONE + + + NONE + + + + + * + + + FALSE + + + false + + + false + + + false + + + NONE + + + NONE + + + + + + +------D5AADCFDEEF9EC8B0B116AC356AF41CA +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQg1l4l1hEFvxsjc65MThWHhvCb +YoBySw0UQA61LL+lSsEwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAF88Gg525eeqmgAtBky5 +lMnQehnA0c37pSL5uTklEcb0xwkQcdWQVerkAwKQb8CJGz4ttwvVqIde2Jn8boJP +Tb8xYvk38HXFHOpzSEv0qAj0u6dVB+go3OnrdhcM1R7jrHfReBRgnict8pLOPb+Y +khdlqzOMVxoTpJSiXUWdt5ucKbNvuWROG6TsNs4S5+lJ3EEvDn3++g32VRX9V3h4 +5Hni4AMGmZrjBbmL/S02iR33ltwXYqfipUQjR5S5V/HS0LHX/mjYwuiWCtHNiSIi +s+8mqW8vNebYA9LeK7bvWXCygqnVr3qJT+ryeXUXtBl7dCTV+QVAlUzbW1wgHSuq +wtc= + +------D5AADCFDEEF9EC8B0B116AC356AF41CA-- + diff --git a/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_clear.xml b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_clear.xml new file mode 100644 index 0000000..e829911 --- /dev/null +++ b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_clear.xml @@ -0,0 +1,62 @@ + + + + + + + + 0 + 230 + + + + + false + + + TRUE + + + NONE + + + NONE + + + NONE + + + + + * + + + FALSE + + + false + + + false + + + false + + + NONE + + + NONE + + + + + diff --git a/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_different.p7s b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_different.p7s new file mode 100644 index 0000000..38b2c26 --- /dev/null +++ b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_different.p7s @@ -0,0 +1,114 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----37F7530AAA327BE7C00C18ECA28FFF95" + +This is an S/MIME signed message + +------37F7530AAA327BE7C00C18ECA28FFF95 +Content-Type: text/plain + + + + + + + + + 0 + 230 + + + + + false + + + TRUE + + + ENCRYPT + + + NONE + + + NONE + + + + + * + + + false + + + true + + + false + + + false + + + NONE + + + NONE + + + + + + +------37F7530AAA327BE7C00C18ECA28FFF95 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgqqTuijPzgi5UyYnaRmfKMSwt +M8Mbr6egpAxWLt7vkkAwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBACmMVANcUvNpeIpdG6is +IbAJWbvoIh68B4nMLMU8gij1ZcNavWg6dDU709AJcrCU2ZbVsHKPyBvRuSctkbKe +XHCRv5bAkcqkLsEVPc4Yu8w2hIC8nSTW1E2l1I+tChcXepcSsmrRFjZI8myDWmre +Slzcq0nSwKayhMSkv0CJeSzhQGCHBhRnVCb7ZDJXL94VKh1OBxlqTWGLRNQcIk0p +WXI0B2j5n8nM+neQd1gnKKuvqjSh2/IwUPariRfqpfVm1e8Mc0zNAubHOfuZ/hXj +tDAPBcJq8gz3sKSbwvN4Rk1J7YV0AnA8pPq3nfoZWvqcUzbdExn2zvzawRgteUyf +luw= + +------37F7530AAA327BE7C00C18ECA28FFF95-- + diff --git a/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_different.xml b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_different.xml new file mode 100644 index 0000000..6f12d18 --- /dev/null +++ b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_different.xml @@ -0,0 +1,62 @@ + + + + + + + + 0 + 230 + + + + + false + + + TRUE + + + ENCRYPT + + + NONE + + + NONE + + + + + * + + + false + + + true + + + false + + + false + + + NONE + + + NONE + + + + + diff --git a/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_encrypted.p7s b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_encrypted.p7s new file mode 100644 index 0000000..cfc92ac --- /dev/null +++ b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_encrypted.p7s @@ -0,0 +1,114 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----E6FE6351D381785F2D971BF5DB266909" + +This is an S/MIME signed message + +------E6FE6351D381785F2D971BF5DB266909 +Content-Type: text/plain + + + + + + + + + 0 + 230 + + + + + false + + + TRUE + + + ENCRYPT + + + ENCRYPT + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + NONE + + + NONE + + + + + + +------E6FE6351D381785F2D971BF5DB266909 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQg7ee1YxacZ9KtXJCLUCzhZB8p +Sv4SXMFrKtVchg886ZkwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAB3tqkFmfwnk2HXgn9H1 +Ap6Hk7I3TIYBMMQkDTZHbPj3EMOls02+QI++ztvwaBzG7bS6f7qfxhHnNgXF/52t +Qf20nOXjxAUL82UxVxNmJjqE+FHksSTqEjtKFMy8V+wz9doVSUgdfKKD8SUOOr1I +nakp0o/Vk/E5bbYOoWaDXJKAo7iiEssbsw33/8eZgPpVOyPS0pqk7w6d/fmo2OMm +niCl24qiXjdQbkuUT+zuhjKIfBjxqIPRKnOxK+HheR77m/EhkNsYYbsOgLaSXQVW +O3Kv0GmJGKg0N2KXW5VH+6FhS5KA6TL/6Xz6LzLZFsSyAmhWsBK0l1Ted+z4Tgw3 +fP8= + +------E6FE6351D381785F2D971BF5DB266909-- + diff --git a/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_encrypted.xml b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_encrypted.xml new file mode 100644 index 0000000..01b2d20 --- /dev/null +++ b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_encrypted.xml @@ -0,0 +1,62 @@ + + + + + + + + 0 + 230 + + + + + false + + + TRUE + + + ENCRYPT + + + ENCRYPT + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + NONE + + + NONE + + + + + diff --git a/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_encrypted_and_authenticated.p7s b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_encrypted_and_authenticated.p7s new file mode 100644 index 0000000..c604b13 --- /dev/null +++ b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_encrypted_and_authenticated.p7s @@ -0,0 +1,114 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----4375434DF6819FB7435B04810D502609" + +This is an S/MIME signed message + +------4375434DF6819FB7435B04810D502609 +Content-Type: text/plain + + + + + + + + + 0 + 230 + + + + + false + + + TRUE + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + NONE + + + NONE + + + + + + +------4375434DF6819FB7435B04810D502609 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQglibSNHDswKA0PDJrsz8tZiXT +1UrMUhYJJbXsLdvTGVowgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBACLqhHS8kapMUhLBjAfI +17FuvzGjgJ2CSy7/yJDz1+OsUdbCofV8jA1rxxPIGv9Koq/BaKHtJdtzpLaag/CD +SITepCjU+rRoGnZ5vOeSgaHJlDWcRBtAoFME3NrgdYT7ldUABuiPngR5HuwNAUTA +aY2rPaSds2eWluqH6WJqO+qvRvSZEsypy+OSpRAu954rDfkFGyZ00aQnTpzJTVJT +MLF8rXziOY9CAHXFN0w6jEBy7Y4pBjnp/bQQFmE41NH9KuATEGPLChInQOYEEeNK +2rr96Z/rgfhcBE1qyZdt4RNgGNFNCRzeGIX5Kti/jTeas1430sQ+DYJypObVhrhY +S/M= + +------4375434DF6819FB7435B04810D502609-- + diff --git a/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_encrypted_and_authenticated.xml b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_encrypted_and_authenticated.xml new file mode 100644 index 0000000..d011e9c --- /dev/null +++ b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_encrypted_and_authenticated.xml @@ -0,0 +1,62 @@ + + + + + + + + 0 + 230 + + + + + false + + + TRUE + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + NONE + + + NONE + + + + + diff --git a/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_signed.p7s b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_signed.p7s new file mode 100644 index 0000000..55cf899 --- /dev/null +++ b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_signed.p7s @@ -0,0 +1,114 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----CAAC97AAFA02CB29461AE6EEFCBDADE0" + +This is an S/MIME signed message + +------CAAC97AAFA02CB29461AE6EEFCBDADE0 +Content-Type: text/plain + + + + + + + + + 0 + 230 + + + + + false + + + TRUE + + + SIGN + + + SIGN + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + NONE + + + NONE + + + + + + +------CAAC97AAFA02CB29461AE6EEFCBDADE0 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgUQGGQlfgFH2GTdp8QcQHAf7c +ytQO0EMxvnsXNDiWmfcwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBABl+6OuVlW5UltPGg+9c +6DlnX12Ah1feD0c/cmOkWjKW9A/soc+5npXvLcbxlkO/+MEkHlH00QKQmX7uY+3Z +NybUU/2KbzEeqo8WwkqJPFBBPrjbHTAuIIPDHFcSq9oY6zUWMcHDFVjaXcNOfyiA +clECqfcXesxfwGNXv5x58y0rJdxGiyptryLvJnZozwjNJ08ggY6d2mnitxbtSowY +InQ02I95vWHYquonVAihvKX9NhaCSDEMyJb/ckL8tJuzQ3qUsEfc5DJVUSOEyCo8 +C7cZbfCpM9R+ZwyhRQOaleHs4kLvli7Q8OkpH8ecUBeg9gQmriju1G2/irvTg4t+ +Tlw= + +------CAAC97AAFA02CB29461AE6EEFCBDADE0-- + diff --git a/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_signed.xml b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_signed.xml new file mode 100644 index 0000000..63ee9e4 --- /dev/null +++ b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_signed.xml @@ -0,0 +1,62 @@ + + + + + + + + 0 + 230 + + + + + false + + + TRUE + + + SIGN + + + SIGN + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + NONE + + + NONE + + + + + diff --git a/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_signed_and_authenticated.p7s b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_signed_and_authenticated.p7s new file mode 100644 index 0000000..6273245 --- /dev/null +++ b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_signed_and_authenticated.p7s @@ -0,0 +1,114 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----7D08A7D2B4B01785900B9A7208F12A69" + +This is an S/MIME signed message + +------7D08A7D2B4B01785900B9A7208F12A69 +Content-Type: text/plain + + + + + + + + + 0 + 230 + + + + + false + + + TRUE + + + SIGN_WITH_ORIGIN_AUTHENTICATION + + + SIGN_WITH_ORIGIN_AUTHENTICATION + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + NONE + + + NONE + + + + + + +------7D08A7D2B4B01785900B9A7208F12A69 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgu4lTESCOlPw4ua2e8RFY0V80 +KDwe7OyvA7k5OJvb70MwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAE6icR4lmUwDahVEA4BA +QIl2Pp+WGo1wDLHRdR1YnKt9narfgi6YHlt37sppOuKYPZSrjkcE07nlj9IN3PNR +2RxeUogt5fLHPll2E+GIfXRkPq5MtCscko+7MyrPkaMOPCv0pQ8e+nEvDkLeKqvS +jinelekFzICvUd8vg9UozxyUQciPLvjmEVwe+czFiM0oFqN9O9d1y5n985HXc/T5 +RfhSXpXUk2KBPvU+tN9UtdInMylPs8PK8wbONTem7uG9nP/tKL7VCjLiTQm5zAuo +ecEvLybuALPVwylTppB2a8jMwb3Qt3ERY/do9s9RyFszvMOqBXsDOpSGtjBHT2uU +Bhs= + +------7D08A7D2B4B01785900B9A7208F12A69-- + diff --git a/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_signed_and_authenticated.xml b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_signed_and_authenticated.xml new file mode 100644 index 0000000..3930f88 --- /dev/null +++ b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Governance_liveliness_discovery_signed_and_authenticated.xml @@ -0,0 +1,62 @@ + + + + + + + + 0 + 230 + + + + + false + + + TRUE + + + SIGN_WITH_ORIGIN_AUTHENTICATION + + + SIGN_WITH_ORIGIN_AUTHENTICATION + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + NONE + + + NONE + + + + + diff --git a/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Permissions_ok.p7s b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Permissions_ok.p7s new file mode 100644 index 0000000..052075b --- /dev/null +++ b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/etc/Test_Permissions_ok.p7s @@ -0,0 +1,85 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----6B91005B007BBA8EDE10CD1CE487DB27" + +This is an S/MIME signed message + +------6B91005B007BBA8EDE10CD1CE487DB27 +Content-Type: text/plain + + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + + + * + + + + DENY + + + + +------6B91005B007BBA8EDE10CD1CE487DB27 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgl3LfUhn9L0vG/3QRPVYptcYw +/NH5HMN99aMe9JAT+LAwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAHe9vakfXPvbpgMeqlhG +SW6Z3uVA3Yri9bgQDpJ9daIUsM0/TLBSQVs85twTMXvqUSntKbfSGehxDQ9F+yje +mOEPMIwxOqcVyc2jpqoYsUWqpwiiZyk49DHUFrOfWJUx+rKdBftZWkxD05Wkovhk +2d4hGS/65Haoho4Z0AZwcyH+F52FZMiqw7I9FKrPlhxvJfQXmhIjOKtnvWnQ+Ar7 +YYiSrBEHMCy82LF1aKzz0nkL1SYWQHuQX475qoU4LMYY1J8WsD3rSBeq4GYZrl2K +X/JcOquMYqjfJLMYZY4fsc3FgEBkKNqJz1tDZ3ir24VMl+WsbEjVK8oXe/wt4V0U +aNQ= + +------6B91005B007BBA8EDE10CD1CE487DB27-- + diff --git a/src/security/builtin_plugins/tests/get_xxx_sec_attributes/src/get_xxx_sec_attributes_utests.c b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/src/get_xxx_sec_attributes_utests.c new file mode 100644 index 0000000..2b0c47e --- /dev/null +++ b/src/security/builtin_plugins/tests/get_xxx_sec_attributes/src/get_xxx_sec_attributes_utests.c @@ -0,0 +1,1646 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/io.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "config_env.h" + +#if OPENSLL_VERSION_NUMBER >= 0x10002000L +#define AUTH_INCLUDE_EC +#endif + +static const char *RELATIVE_PATH_TO_ETC_DIR = "/get_xxx_sec_attributes/etc/"; + +static const char *PROPERTY_IDENTITY_CA = "dds.sec.auth.identity_ca"; +static const char *PROPERTY_PRIVATE_KEY = "dds.sec.auth.private_key"; +static const char *PROPERTY_IDENTITY_CERT = "dds.sec.auth.identity_certificate"; +static const char *PROPERTY_PERMISSIONS_CA = "dds.sec.access.permissions_ca"; +static const char *PROPERTY_PERMISSIONS = "dds.sec.access.permissions"; +static const char *PROPERTY_GOVERNANCE = "dds.sec.access.governance"; + +static const char *IDENTITY_CERTIFICATE = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEQTCCAymgAwIBAgIINpuaAAnrQZIwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE3MDIy\n" + "MjIyMjIwMFoYDzIyMjIwMjIyMjIyMjAwWjBcMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRUwEwYDVQQDEwxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n" + "ggEKAoIBAQDCpVhivH/wBIyu74rvQncnSZqKyspN6CvD1pmV9wft5PHhVt9jV79v\n" + "gSub5LADoRHAgFdv9duYgBr17Ob6uRrIY4B18CcrCjhQcC4gjx8y2jl9PeYm+qYD\n" + "3o44FYBrBq0QCnrQgKsb/qX9Z+Mw/VUiw65x68W876LEHQQoEgT4kxSuagwBoVRk\n" + "ePD6fYAKmT4XS3x+O0v+rHESTcsKF6yMadgp7h3eH1b8kJTzSx8JV9Zzq++mxjox\n" + "qhbBVP5nDze2hhSIeCkCvSrx7efkgKS4AQXa5/Z44GiAu1TfXXUqdic9rxwD0edn\n" + "ajNElnZe7sjok/0yuqvH+2hSqpNva/zpAgMBAAGjggEAMIH9MAwGA1UdDwQFAwMH\n" + "/4AwgewGA1UdJQSB5DCB4QYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYI\n" + "KwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3AgEVBgorBgEEAYI3AgEWBgorBgEE\n" + "AYI3CgMBBgorBgEEAYI3CgMDBgorBgEEAYI3CgMEBglghkgBhvhCBAEGCysGAQQB\n" + "gjcKAwQBBggrBgEFBQcDBQYIKwYBBQUHAwYGCCsGAQUFBwMHBggrBgEFBQgCAgYK\n" + "KwYBBAGCNxQCAgYIKwYBBQUHAwkGCCsGAQUFBwMNBggrBgEFBQcDDgYHKwYBBQID\n" + "BTANBgkqhkiG9w0BAQsFAAOCAQEAawdHy0Xw7nTK2ltp91Ion6fJ7hqYuj///zr7\n" + "Adt6uonpDh/xl3esuwcFimIJrJrHujnGkL0nLddRCikmnzuBMNDWS6yq0/Ckl/YG\n" + "yjNr44dlX24wo+MVAgkj3/8CyWDZ3a8kBg9QT3bs2SqbjmhTrXN1DRyf9S5vJysE\n" + "I7V1gTN66BeKL64hOrAlRVrEu8Ds6TWL6Q/YH+61ViZkoLTeSaPjH4nknaFr4C35\n" + "iji0JhkyfRHRRVPHFnaj25AkxOrSV64qVKoTMjDl5fji5iMGtjm6iJ7q05ml/qDl\n" + "nLotHXemZNvYhbwUmRzbt4Dls9EMH4VRbP85I94nM5TAvtHVNA==\n" + "-----END CERTIFICATE-----\n"; + +static const char *IDENTITY_CA = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEmTCCA4GgAwIBAgIIZ5gEIUFhO5wwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDIx\n" + "MjE1MDUwMFoYDzIyMjIwMjIyMjIyMjAwWjBfMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRgwFgYDVQQDEw9DSEFNNTAwIHJvb3QgY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" + "DwAwggEKAoIBAQC6Fa3TheL+UrdZCp9GhU/2WbneP2t/avUa3muwDttPxeI2XU9k\n" + "ZjBR95mAXme4SPXHk5+YDN319AqIje3oKhzky/ngvKH2GkoJKYxWnuDBfMEHdViz\n" + "2Q9/xso2ZvH50ukwWa0pfx2/EVV1wRxeQcRd/UVfq3KTJizG0M88mOYvGEAw3LFf\n" + "zef7k1aCuOofQmBvLukUudcYpMzfyHFp7lQqU4CcrrR5RtmfiUfrWfdGLea2iPDB\n" + "pJgN8ESOMwEHtOTEBDclYnH9L4t7CHQz+fXXS5IWFsDK9fCMQjnxDsDVeNrNzTYL\n" + "FaZrMg9S6IUQCEsQWsnq5weS8omOpVLUm9klAgMBAAGjggFVMIIBUTAMBgNVHRME\n" + "BTADAQH/MB0GA1UdDgQWBBQg2FZB/j8uWDVnJhjwXkX278znSTAfBgNVHSMEGDAW\n" + "gBQg2FZB/j8uWDVnJhjwXkX278znSTAPBgNVHQ8BAf8EBQMDB/+AMIHvBgNVHSUB\n" + "Af8EgeQwgeEGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwME\n" + "BggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK\n" + "KwYBBAGCNwoDAwYKKwYBBAGCNwoDBAYJYIZIAYb4QgQBBgsrBgEEAYI3CgMEAQYI\n" + "KwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUIAgIGCisGAQQBgjcU\n" + "AgIGCCsGAQUFBwMJBggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZI\n" + "hvcNAQELBQADggEBAKHmwejWRwGE1wf1k2rG8SNRV/neGsZ6Qfqf6co3TpR/Wi1s\n" + "iZDvSeT/rbqNBS7z34xnG88NIUwu00y78e8Mfon31ZZbK4Uo7fla9/D3ukdJqPQC\n" + "LKdbKJjR2kH+KCukY/1rghjJ8/X+t2egBit0LCOdsFCl07Sfksb9kpGUIZSFcYYm\n" + "geqhjhoNwxazzHiw+QWHC5HG9248JIizBmy1aymNWuMnPudhjHAnPcsIlqMVNq3t\n" + "Rv9ap7S8JeCxHVRPJvJeCwXWvW3dW/v3xH52Yn/fqRblN1w9Fxz5NhopKx0gj/Jd\n" + "sw2N4Fk4gaOWEolFpa0bwNw8nAx7moehZpowzfw=\n" + "-----END CERTIFICATE-----\n"; + +static const char *PRIVATE_KEY = + "data:,-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEogIBAAKCAQEAwqVYYrx/8ASMru+K70J3J0maisrKTegrw9aZlfcH7eTx4Vbf\n" + "Y1e/b4Erm+SwA6ERwIBXb/XbmIAa9ezm+rkayGOAdfAnKwo4UHAuII8fMto5fT3m\n" + "JvqmA96OOBWAawatEAp60ICrG/6l/WfjMP1VIsOucevFvO+ixB0EKBIE+JMUrmoM\n" + "AaFUZHjw+n2ACpk+F0t8fjtL/qxxEk3LChesjGnYKe4d3h9W/JCU80sfCVfWc6vv\n" + "psY6MaoWwVT+Zw83toYUiHgpAr0q8e3n5ICkuAEF2uf2eOBogLtU3111KnYnPa8c\n" + "A9HnZ2ozRJZ2Xu7I6JP9Mrqrx/toUqqTb2v86QIDAQABAoIBAC1q32DKkx+yMBFx\n" + "m32QiLUGG6VfBC2BixS7MkMnzRXZYgcuehl4FBc0kLRjfB6cqsO8LqrVN1QyMBhK\n" + "GutN3c38SbE7RChqzhEW2+yE+Mao3Nk4ZEecHLiyaYT0n25ZtHAVwep823BAzwJ+\n" + "BykbM45VEpNKbG1VjSktjBa9faNyZiZAEJEjVyla+6R8N4kHV52LbZcLjvJv3IQ2\n" + "iPYRrmMyI5C23qTni0vy7yJbAXBo3CqgSlwie9FARBWT7Puu7F4mF1O1c/SnTysw\n" + "Tm3e5FzgfHipQbnRVn0w4rDprPMKmPxMnvf/Wkw0zVgNadp1Tc1I6Yj525DEQ07i\n" + "2gIn/gECgYEA4jNnY1u2Eu7x3pAQF3dRO0x35boVtuq9iwQk7q+uaZaK4RJRr+0Y\n" + "T68S3bPnfer6SHvcxtST89Bvs/j/Ky4SOaX037UYjFh6T7OIzPl+MzO1yb+VOBT6\n" + "D6FVGEJGp8ZAITU1OfJPeTYViUeEC8tHFGoKUCk50FbB6jOf1oKtv/ECgYEA3EnB\n" + "Y7kSbJJaUuj9ciFUL/pAno86Cim3VjegK1wKgEiyDb610bhoMErovPwfVJbtcttG\n" + "eKJNuwizkRcVbj+vpjDvqqaP5eMxLl6/Nd4haPMJYzGo88Z8NJpwFRNF2KEWjOpQ\n" + "2NEvoCeRtVulCJyka2Tpljzw8cOXkxhPOe2UhHkCgYBo3entj0QO7QXm56T+LAvV\n" + "0PK45xdQEO3EuCwjGAFk5C0IgUSrqeCeeIzniZMltj1IQ1wsNbtNynEu3530t8wt\n" + "O7oVyFBUKGSz9IjUdkpClJOPr6kPMfJoMqRPtdIpz+hFPPSrI6IikKdVWHloOlp+\n" + "pVaYqTQrWT1XRY2xli3VEQKBgGySmZN6Cx+h/oywswIGdUT0VdcQhq2to+QFpJba\n" + "VX6m1cM6hMip2Ag9U3qZ1SNPBBdBBfm9HQybHE3dj713/C2wHuAAGhpXIM1W+20k\n" + "X1knuC/AsSH9aQhQOf/ZMOq1crTfZBuI9q0782/sjGmzMsKPySU4QhUWruVb7OiD\n" + "NVkZAoGAEvihW7G+8/iOE40vGHyBqUeopAAWLciTAUIEwM/Oi3BYfNWNTWF/FWNc\n" + "nMvCZPYigY8C1vO+1iT2Frtd3CIU+f01Q3fJNJoRLlEiKLNZUJRF48OKUqjKSmsi\n" + "w6pucFO40z05YW7utApj4L82rZnOS0pd1tUI1yexqvj0i4ThJfk=\n" + "-----END RSA PRIVATE KEY-----\n"; + +static const char *PERMISSIONS_CA = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV\n" + "BAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQKDBZBRExJTksgVGVj\n" + "aG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNvbTAgFw0xODA3MzAx\n" + "MjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMCTkwxEzARBgNVBAgM\n" + "ClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4xFzAV\n" + "BgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" + "CgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blIDehV6XCxrnGXusTCD\n" + "uFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9wicp3BGSpZZax/TcO\n" + "NjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLsDFFC+a0qn2RFh37r\n" + "cWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074BRDXVivx+wVD951L\n" + "FNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiySogRWAmKhysLQudu\n" + "kHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNVHQ4EFgQURWMbWvBK\n" + "ZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJvRV1/tyc1R82k0+gw\n" + "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ysVtvHnk2hpu9yND\n" + "LCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9XVh0rGoR/6nHzo3TI\n" + "eiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9yghhKHHqNDvSsAL0\n" + "KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbtlLX3QnwVOmaRyzyl\n" + "PiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42+OyLqcH1rKT6Xhcs\n" + "hjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb6SDB340BFmtgDHbF\n" + "HQ==\n" + "-----END CERTIFICATE-----\n"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_access_control *access_control = NULL; +static dds_security_authentication *auth = NULL; +static DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_PermissionsHandle local_permissions_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_GUID_t local_participant_guid; +static char *g_path_to_etc_dir = NULL; + +typedef enum SEC_TOPIC_NAME +{ + SEC_TOPIC_DCPSPARTICIPANTSECURE, + SEC_TOPIC_DCPSPUBLICATIONSSECURE, + SEC_TOPIC_DCPSSUBSCRIPTIONSSECURE, + SEC_TOPIC_DCPSPARTICIPANTMESSAGESECURE, + SEC_TOPIC_DCPSPARTICIPANTSTATELESSMESSAGE, + SEC_TOPIC_DCPSPARTICIPANTVOLATILEMESSAGESECURE, + SEC_TOPIC_DCPS_KINEMATICS, + SEC_TOPIC_DCPS_OWNSHIPDATA, + SEC_TOPIC_DCPS_SHAPE +} SEC_TOPIC_TYPE; + +const char *TOPIC_NAMES[] = {"DCPSParticipantsSecure", + "DCPSPublicationsSecure", + "DCPSSubscriptionsSecure", + "DCPSParticipantMessageSecure", + "DCPSParticipantStatelessMessage", + "DCPSParticipantVolatileMessageSecure", + "Kinematics", + "OwnShipData", + "Shape" + +}; + +static DDS_Security_EndpointSecurityAttributes ATTRIBUTE_CHECKLIST[9]; + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void dds_security_property_init(DDS_Security_PropertySeq *seq, DDS_Security_unsigned_long size) +{ + seq->_length = size; + seq->_maximum = size; + seq->_buffer = ddsrt_malloc(size * sizeof(DDS_Security_Property_t)); + memset(seq->_buffer, 0, size * sizeof(DDS_Security_Property_t)); +} + +static void dds_security_property_deinit(DDS_Security_PropertySeq *seq) +{ + uint32_t i; + for (i = 0; i < seq->_length; i++) + { + ddsrt_free(seq->_buffer[i].name); + ddsrt_free(seq->_buffer[i].value); + } + ddsrt_free(seq->_buffer); +} + +static void fill_participant_qos(DDS_Security_Qos *qos, const char *permission_filename, + const char *governance_filename) +{ + char *permission_uri; + char *governance_uri; + + ddsrt_asprintf(&permission_uri, "file:%s%s", g_path_to_etc_dir, permission_filename); + ddsrt_asprintf(&governance_uri, "file:%s%s", g_path_to_etc_dir, governance_filename); + + memset(qos, 0, sizeof(*qos)); + dds_security_property_init(&qos->property.value, 6); + qos->property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + qos->property.value._buffer[0].value = ddsrt_strdup(IDENTITY_CERTIFICATE); + qos->property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + qos->property.value._buffer[1].value = ddsrt_strdup(IDENTITY_CA); + qos->property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + qos->property.value._buffer[2].value = ddsrt_strdup(PRIVATE_KEY); + qos->property.value._buffer[3].name = ddsrt_strdup(PROPERTY_PERMISSIONS_CA); + qos->property.value._buffer[3].value = ddsrt_strdup(PERMISSIONS_CA); + qos->property.value._buffer[4].name = ddsrt_strdup(PROPERTY_PERMISSIONS); + qos->property.value._buffer[4].value = ddsrt_strdup(permission_uri); + qos->property.value._buffer[5].name = ddsrt_strdup(PROPERTY_GOVERNANCE); + qos->property.value._buffer[5].value = ddsrt_strdup(governance_uri); + + ddsrt_free(permission_uri); + ddsrt_free(governance_uri); +} + +static bool create_local_identity(DDS_Security_DomainId domain_id, const char *governance_file) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb}; + DDS_Security_EntityId_t entityId = {{0xb0, 0xb1, 0xb2}, 0x1}; + + memset(&local_participant_guid, 0, sizeof(local_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, "Test_Permissions_ok.p7s", governance_file); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &local_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) + { + printf("[ERROR] validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + return false; + } + + local_permissions_handle = access_control->validate_local_permissions( + access_control, + auth, + local_identity_handle, + domain_id, + &participant_qos, + &exception); + + if (local_permissions_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("[ERROR] validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + return false; + } + + dds_security_property_deinit(&participant_qos.property.value); + + return true; +} + +static void clear_local_identity(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (local_identity_handle != DDS_SECURITY_HANDLE_NIL) + { + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + if (!success) + { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } + + if (local_permissions_handle != DDS_SECURITY_HANDLE_NIL) + { + success = access_control->return_permissions_handle(access_control, local_permissions_handle, &exception); + if (!success) + { + printf("return_permissions_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } + + local_identity_handle = DDS_SECURITY_HANDLE_NIL; + local_permissions_handle = DDS_SECURITY_HANDLE_NIL; +} + +static void set_path_to_etc_dir(void) +{ + ddsrt_asprintf(&g_path_to_etc_dir, "%s%s", CONFIG_ENV_TESTS_DIR, RELATIVE_PATH_TO_ETC_DIR); +} + +static DDS_Security_PluginEndpointSecurityAttributesMask get_plugin_endpoint_security_attributes_mask(DDS_Security_boolean is_payload_encrypted, DDS_Security_boolean is_submessage_encrypted, DDS_Security_boolean is_submessage_origin_authenticated) +{ + DDS_Security_PluginEndpointSecurityAttributesMask mask = DDS_SECURITY_ENDPOINT_ATTRIBUTES_FLAG_IS_VALID; + if (is_submessage_encrypted) + mask |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + if (is_payload_encrypted) + mask |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + if (is_submessage_origin_authenticated) + mask |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + return mask; +} + +static void suite_get_xxx_sec_attributes_init(void) +{ + set_path_to_etc_dir(); + + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTSECURE].is_read_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPUBLICATIONSSECURE].is_read_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSSUBSCRIPTIONSSECURE].is_read_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTMESSAGESECURE].is_read_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTSTATELESSMESSAGE].is_read_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTVOLATILEMESSAGESECURE].is_read_protected = false; + + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTSECURE].is_write_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPUBLICATIONSSECURE].is_write_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSSUBSCRIPTIONSSECURE].is_write_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTMESSAGESECURE].is_write_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTSTATELESSMESSAGE].is_write_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTVOLATILEMESSAGESECURE].is_write_protected = false; + + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTSECURE].is_payload_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPUBLICATIONSSECURE].is_payload_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSSUBSCRIPTIONSSECURE].is_payload_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTMESSAGESECURE].is_payload_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTSTATELESSMESSAGE].is_payload_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTVOLATILEMESSAGESECURE].is_payload_protected = false; + + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTSECURE].is_key_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPUBLICATIONSSECURE].is_key_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSSUBSCRIPTIONSSECURE].is_key_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTMESSAGESECURE].is_key_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTSTATELESSMESSAGE].is_key_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTVOLATILEMESSAGESECURE].is_key_protected = false; + + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTSECURE].is_submessage_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPUBLICATIONSSECURE].is_submessage_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSSUBSCRIPTIONSSECURE].is_submessage_protected = + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTMESSAGESECURE].is_submessage_protected = true; + + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTSTATELESSMESSAGE].is_submessage_protected = false; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPSPARTICIPANTVOLATILEMESSAGESECURE].is_submessage_protected = true; + + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_KINEMATICS].is_read_protected = true; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_KINEMATICS].is_write_protected = false; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_KINEMATICS].is_discovery_protected = true; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_KINEMATICS].is_liveliness_protected = true; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_KINEMATICS].is_submessage_protected = false; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_KINEMATICS].is_payload_protected = false; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_KINEMATICS].is_key_protected = false; + + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_KINEMATICS].plugin_endpoint_attributes = + get_plugin_endpoint_security_attributes_mask(false, false, false); + + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_OWNSHIPDATA].is_read_protected = false; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_OWNSHIPDATA].is_write_protected = true; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_OWNSHIPDATA].is_discovery_protected = false; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_OWNSHIPDATA].is_liveliness_protected = false; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_OWNSHIPDATA].is_submessage_protected = true; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_OWNSHIPDATA].is_payload_protected = true; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_OWNSHIPDATA].is_key_protected = true; + + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_OWNSHIPDATA].plugin_endpoint_attributes = + get_plugin_endpoint_security_attributes_mask(true, false, false); + + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_SHAPE].is_read_protected = false; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_SHAPE].is_write_protected = false; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_SHAPE].is_discovery_protected = true; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_SHAPE].is_liveliness_protected = true; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_SHAPE].is_submessage_protected = true; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_SHAPE].is_payload_protected = true; + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_SHAPE].is_key_protected = true; + + ATTRIBUTE_CHECKLIST[SEC_TOPIC_DCPS_SHAPE].plugin_endpoint_attributes = + get_plugin_endpoint_security_attributes_mask(true, true, true); +} + +static void suite_get_xxx_sec_attributes_fini(void) +{ + ddsrt_free(g_path_to_etc_dir); +} + +static bool plugins_init(void) +{ + /* Checking AccessControl, but needing Authentication to setup local identity. */ + plugins = load_plugins(&access_control, &auth, NULL /* Cryptograpy */); + return plugins ? true : false; +} + +static void plugins_fini(void) +{ + unload_plugins(plugins); +} + +static bool +verify_endpoint_attributes(SEC_TOPIC_TYPE topic_type, DDS_Security_EndpointSecurityAttributes *attributes) +{ + bool result = true; + if (attributes->is_read_protected != ATTRIBUTE_CHECKLIST[topic_type].is_read_protected || + attributes->is_write_protected != ATTRIBUTE_CHECKLIST[topic_type].is_write_protected || + attributes->is_submessage_protected != ATTRIBUTE_CHECKLIST[topic_type].is_submessage_protected || + attributes->is_payload_protected != ATTRIBUTE_CHECKLIST[topic_type].is_payload_protected || + attributes->is_key_protected != ATTRIBUTE_CHECKLIST[topic_type].is_key_protected) + { + + result = false; + } + if (topic_type == SEC_TOPIC_DCPS_KINEMATICS || topic_type == SEC_TOPIC_DCPS_SHAPE) + { + if (attributes->is_discovery_protected != ATTRIBUTE_CHECKLIST[topic_type].is_discovery_protected || + attributes->is_liveliness_protected != ATTRIBUTE_CHECKLIST[topic_type].is_liveliness_protected || + attributes->plugin_endpoint_attributes != ATTRIBUTE_CHECKLIST[topic_type].plugin_endpoint_attributes) + { + result = false; + } + } + + if (!result) + { + printf("Invalid attribute for Topic: %s\n", TOPIC_NAMES[topic_type]); + printf("is_read_protected: EXPECTED: %d ACTUAL: %d\n" + "is_write_protected: EXPECTED: %d ACTUAL: %d\n" + "is_discovery_protected: EXPECTED: %d ACTUAL: %d\n" + "is_liveliness_protected: EXPECTED: %d ACTUAL: %d\n" + "is_submessage_protected: EXPECTED: %d ACTUAL: %d\n" + "is_payload_protected: EXPECTED: %d ACTUAL: %d\n" + "is_key_protected: EXPECTED: %d ACTUAL: %d\n", + ATTRIBUTE_CHECKLIST[topic_type].is_read_protected, attributes->is_read_protected, + ATTRIBUTE_CHECKLIST[topic_type].is_write_protected, attributes->is_write_protected, + ATTRIBUTE_CHECKLIST[topic_type].is_discovery_protected, attributes->is_discovery_protected, + ATTRIBUTE_CHECKLIST[topic_type].is_liveliness_protected, attributes->is_liveliness_protected, + ATTRIBUTE_CHECKLIST[topic_type].is_submessage_protected, attributes->is_submessage_protected, + ATTRIBUTE_CHECKLIST[topic_type].is_payload_protected, attributes->is_payload_protected, + ATTRIBUTE_CHECKLIST[topic_type].is_key_protected, attributes->is_key_protected); + } + + return result; +} + +static bool verify_topic_attributes(SEC_TOPIC_TYPE topic_type, DDS_Security_TopicSecurityAttributes *attributes) +{ + bool result = true; + if (attributes->is_read_protected != ATTRIBUTE_CHECKLIST[topic_type].is_read_protected || + attributes->is_write_protected != ATTRIBUTE_CHECKLIST[topic_type].is_write_protected || + attributes->is_discovery_protected != ATTRIBUTE_CHECKLIST[topic_type].is_discovery_protected || + attributes->is_liveliness_protected != ATTRIBUTE_CHECKLIST[topic_type].is_liveliness_protected) + { + result = false; + } + + if (!result) + { + printf("Invalid attribute for Topic: %s\n", TOPIC_NAMES[topic_type]); + printf("is_read_protected: EXPECTED: %d ACTUAL: %d\n" + "is_write_protected: EXPECTED: %d ACTUAL: %d\n" + "is_discovery_protected: EXPECTED: %d ACTUAL: %d\n" + "is_liveliness_protected: EXPECTED: %d ACTUAL: %d\n", + ATTRIBUTE_CHECKLIST[topic_type].is_read_protected, attributes->is_read_protected, + ATTRIBUTE_CHECKLIST[topic_type].is_write_protected, attributes->is_write_protected, + ATTRIBUTE_CHECKLIST[topic_type].is_discovery_protected, attributes->is_discovery_protected, + ATTRIBUTE_CHECKLIST[topic_type].is_liveliness_protected, attributes->is_liveliness_protected); + } + + return result; +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, participant_happy_day, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_ParticipantSecurityAttributes attributes; + bool result; + + result = plugins_init(); + CU_ASSERT_FATAL(result); + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_participant_sec_attributes != NULL); + + result = create_local_identity(0, "Test_Governance_full.p7s"); + CU_ASSERT_FATAL(result); + + memset(&attributes, 0, sizeof(attributes)); + + result = access_control->get_participant_sec_attributes( + access_control, + local_permissions_handle, + &attributes, + &exception); + CU_ASSERT(result); + + /* + * Expect these values based on these options, which is the 1st domain rule + * in the Test_Governance_full.p7s (selected because of domain id 0): + * + * false + * true + * SIGN_WITH_ORIGIN_AUTHENTICATION + * ENCRYPT + * ENCRYPT_WITH_ORIGIN_AUTHENTICATION + */ + CU_ASSERT(attributes.allow_unauthenticated_participants == false); + CU_ASSERT(attributes.is_access_protected == true); + CU_ASSERT(attributes.is_discovery_protected == true); + CU_ASSERT(attributes.is_liveliness_protected == true); + CU_ASSERT(attributes.is_rtps_protected == true); + CU_ASSERT((attributes.plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED) == DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED); + CU_ASSERT((attributes.plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_ENCRYPTED) == 0); + CU_ASSERT((attributes.plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_ENCRYPTED) == DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_ENCRYPTED); + CU_ASSERT((attributes.plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED) == DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED); + CU_ASSERT((attributes.plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_AUTHENTICATED) == DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_AUTHENTICATED); + CU_ASSERT((attributes.plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_AUTHENTICATED) == 0); + CU_ASSERT((attributes.plugin_participant_attributes & DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID) != 0); + + result = access_control->return_participant_sec_attributes( + access_control, + &attributes, + &exception); + CU_ASSERT(result); + + clear_local_identity(); + plugins_fini(); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, datawriter_happy_day, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PartitionQosPolicy *partition = NULL; + DDS_Security_DataTagQosPolicy data_tag; + DDS_Security_EndpointSecurityAttributes attributes; + bool result; + unsigned i; + + result = plugins_init(); + CU_ASSERT_FATAL(result); + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_datawriter_sec_attributes != NULL); + + result = create_local_identity(0, "Test_Governance_full.p7s"); + CU_ASSERT_FATAL(result); + + memset(&attributes, 0, sizeof(attributes)); + + /*Test for each builtin topics: + "DCPSParticipantsSecure", "DCPSPublicationsSecure", "DCPSSubscriptionsSecure" + "DCPSParticipantMessageSecure", "DCPSParticipantStatelessMessage", "DCPSParticipantVolatileMessageSecure" + and a sample DCPS topic*/ + + /* Now call the function. */ + for (i = SEC_TOPIC_DCPSPARTICIPANTSECURE; i <= SEC_TOPIC_DCPS_SHAPE; ++i) + { + + result = access_control->get_datawriter_sec_attributes( + access_control, + local_permissions_handle, + TOPIC_NAMES[i], + partition, + &data_tag, + &attributes, + &exception); + + CU_ASSERT_FATAL(result); + + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_OK_CODE); + CU_ASSERT_FATAL(verify_endpoint_attributes(i, &attributes)); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + } + + plugins_fini(); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, datawriter_non_existing_topic, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PartitionQosPolicy *partition = NULL; + DDS_Security_DataTagQosPolicy data_tag; + DDS_Security_EndpointSecurityAttributes attributes; + bool result; + + result = plugins_init(); + CU_ASSERT_FATAL(result); + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_datawriter_sec_attributes != NULL); + + /* use a different domain(30) to get non matching topic result */ + result = create_local_identity(30, "Test_Governance_full.p7s"); + CU_ASSERT_FATAL(result); + + memset(&attributes, 0, sizeof(attributes)); + + /* Now call the function. */ + result = access_control->get_datawriter_sec_attributes( + access_control, + local_permissions_handle, + TOPIC_NAMES[SEC_TOPIC_DCPS_SHAPE], + partition, + &data_tag, + &attributes, + &exception); + + CU_ASSERT_FATAL(!result); + + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_CAN_NOT_FIND_TOPIC_IN_DOMAIN_CODE); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + plugins_fini(); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, datareader_happy_day, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PartitionQosPolicy *partition = NULL; + DDS_Security_DataTagQosPolicy data_tag; + DDS_Security_EndpointSecurityAttributes attributes; + bool result; + unsigned i; + + result = plugins_init(); + CU_ASSERT_FATAL(result); + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_datareader_sec_attributes != NULL); + + result = create_local_identity(0, "Test_Governance_full.p7s"); + CU_ASSERT_FATAL(result); + + memset(&attributes, 0, sizeof(attributes)); + + /*Test for each builtin topics: + "DCPSParticipantSecure", "DCPSPublicationsSecure", "DCPSSubscriptionsSecure" + "DCPSParticipantMessageSecure", "DCPSParticipantStatelessMessage", "DCPSParticipantVolatileMessageSecure" + and a sample DCPS topic*/ + + /* Now call the function. */ + for (i = SEC_TOPIC_DCPSPARTICIPANTSECURE; i <= SEC_TOPIC_DCPS_SHAPE; ++i) + { + + result = access_control->get_datareader_sec_attributes( + access_control, + local_permissions_handle, + TOPIC_NAMES[i], + partition, + &data_tag, + &attributes, + &exception); + + CU_ASSERT_FATAL(result); + + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_OK_CODE); + CU_ASSERT_FATAL(verify_endpoint_attributes(i, &attributes) == true); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + } + + plugins_fini(); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, datareader_non_existing_topic, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PartitionQosPolicy *partition = NULL; + DDS_Security_DataTagQosPolicy data_tag; + DDS_Security_EndpointSecurityAttributes attributes; + bool result; + + result = plugins_init(); + CU_ASSERT_FATAL(result); + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_datawriter_sec_attributes != NULL); + + /* use a different domain (30) to get non matching topic result */ + result = create_local_identity(30, "Test_Governance_full.p7s"); + CU_ASSERT_FATAL(result); + + memset(&attributes, 0, sizeof(attributes)); + + result = access_control->get_datareader_sec_attributes( + access_control, + local_permissions_handle, + TOPIC_NAMES[SEC_TOPIC_DCPS_SHAPE], + partition, + &data_tag, + &attributes, + &exception); + + CU_ASSERT_FATAL(!result); + + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_CAN_NOT_FIND_TOPIC_IN_DOMAIN_CODE); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + plugins_fini(); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, participant_invalid_param, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_ParticipantSecurityAttributes attributes; + bool result; + + memset(&attributes, 0, sizeof(attributes)); + + result = plugins_init(); + CU_ASSERT_FATAL(result); + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_participant_sec_attributes != NULL); + + result = access_control->get_participant_sec_attributes( + NULL, + local_permissions_handle, + &attributes, + &exception); + CU_ASSERT(!result); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + result = access_control->get_participant_sec_attributes( + access_control, + 0, + &attributes, + &exception); + CU_ASSERT(!result); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + result = access_control->get_participant_sec_attributes( + access_control, + local_permissions_handle, + NULL, + &exception); + CU_ASSERT(!result); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + result = access_control->get_participant_sec_attributes( + access_control, + local_permissions_handle + 12345, + &attributes, + &exception); + CU_ASSERT(!result); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + plugins_fini(); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, datareader_invalid_param, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PartitionQosPolicy *partition = NULL; + DDS_Security_DataTagQosPolicy data_tag; + DDS_Security_EndpointSecurityAttributes attributes; + bool result; + + result = plugins_init(); + CU_ASSERT_FATAL(result); + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_datareader_sec_attributes != NULL); + + memset(&attributes, 0, sizeof(attributes)); + + /* Now call the function. */ + + result = access_control->get_datareader_sec_attributes( + access_control, + local_permissions_handle, + NULL, + partition, + &data_tag, + &attributes, + &exception); + + CU_ASSERT_FATAL(!result); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + result = access_control->get_datareader_sec_attributes( + access_control, + local_permissions_handle, + "", + partition, + &data_tag, + &attributes, + &exception); + + CU_ASSERT_FATAL(!result); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + result = access_control->get_datareader_sec_attributes( + access_control, + local_permissions_handle, + "Shape", + partition, + &data_tag, + NULL, + &exception); + + CU_ASSERT_FATAL(!result); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + result = access_control->get_datareader_sec_attributes( + access_control, + local_permissions_handle + 12345, + "Shape", + partition, + &data_tag, + &attributes, + &exception); + + CU_ASSERT_FATAL(!result); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + plugins_fini(); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, datawriter_invalid_param, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PartitionQosPolicy *partition = NULL; + DDS_Security_DataTagQosPolicy data_tag; + DDS_Security_EndpointSecurityAttributes attributes; + bool result; + + result = plugins_init(); + CU_ASSERT_FATAL(result); + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_datawriter_sec_attributes != NULL); + + memset(&attributes, 0, sizeof(attributes)); + + /* Now call the function. */ + + result = access_control->get_datawriter_sec_attributes( + access_control, + local_permissions_handle, + NULL, + partition, + &data_tag, + &attributes, + &exception); + + CU_ASSERT_FATAL(!result); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + result = access_control->get_datawriter_sec_attributes( + access_control, + local_permissions_handle, + "", + partition, + &data_tag, + &attributes, + &exception); + + CU_ASSERT_FATAL(!result); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + result = access_control->get_datawriter_sec_attributes( + access_control, + local_permissions_handle, + "Shape", + partition, + &data_tag, + NULL, + &exception); + + CU_ASSERT_FATAL(!result); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + result = access_control->get_datawriter_sec_attributes( + access_control, + local_permissions_handle + 12345, + "Shape", + partition, + &data_tag, + &attributes, + &exception); + + CU_ASSERT_FATAL(!result); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + plugins_fini(); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, topic_happy_day, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_TopicSecurityAttributes attributes; + bool result; + unsigned i; + + result = plugins_init(); + CU_ASSERT_FATAL(result); + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_topic_sec_attributes != NULL); + + result = create_local_identity(0, "Test_Governance_full.p7s"); + CU_ASSERT_FATAL(result); + + memset(&attributes, 0, sizeof(attributes)); + + /*Test for each builtin topics: + "DCPSParticipantsSecure", "DCPSPublicationsSecure", "DCPSSubscriptionsSecure" + "DCPSParticipantMessageSecure", "DCPSParticipantStatelessMessage", "DCPSParticipantVolatileMessageSecure" + and a sample DCPS topic*/ + + /* Now call the function. */ + for (i = SEC_TOPIC_DCPS_KINEMATICS; i <= SEC_TOPIC_DCPS_SHAPE; ++i) + { + + result = access_control->get_topic_sec_attributes( + access_control, + local_permissions_handle, + TOPIC_NAMES[i], + &attributes, + &exception); + + CU_ASSERT_FATAL(result); + + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_OK_CODE); + CU_ASSERT_FATAL(verify_topic_attributes(i, &attributes)); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + } + + plugins_fini(); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, topic_non_existing_topic, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_TopicSecurityAttributes attributes; + bool result; + + result = plugins_init(); + CU_ASSERT_FATAL(result); + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_topic_sec_attributes != NULL); + + result = create_local_identity(30, "Test_Governance_full.p7s"); + CU_ASSERT_FATAL(result); + + memset(&attributes, 0, sizeof(attributes)); + + /*Test for each builtin topics: + "DCPSParticipantsSecure", "DCPSPublicationsSecure", "DCPSSubscriptionsSecure" + "DCPSParticipantMessageSecure", "DCPSParticipantStatelessMessage", "DCPSParticipantVolatileMessageSecure" + and a sample DCPS topic*/ + + /* Now call the function. */ + result = access_control->get_topic_sec_attributes( + access_control, + local_permissions_handle, + TOPIC_NAMES[SEC_TOPIC_DCPS_SHAPE], + &attributes, + &exception); + + CU_ASSERT_FATAL(!result); + + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_CAN_NOT_FIND_TOPIC_IN_DOMAIN_CODE); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + plugins_fini(); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, topic_invalid_param, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_TopicSecurityAttributes attributes; + bool result; + + result = plugins_init(); + CU_ASSERT_FATAL(result); + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_topic_sec_attributes != NULL); + + result = create_local_identity(0, "Test_Governance_full.p7s"); + CU_ASSERT_FATAL(result); + + memset(&attributes, 0, sizeof(attributes)); + + /* Now call the function. */ + + result = access_control->get_topic_sec_attributes( + access_control, + local_permissions_handle, + NULL, + &attributes, + &exception); + + CU_ASSERT_FATAL(!result); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + result = access_control->get_topic_sec_attributes( + access_control, + local_permissions_handle, + "", + &attributes, + &exception); + + CU_ASSERT_FATAL(!result); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + result = access_control->get_topic_sec_attributes( + access_control, + local_permissions_handle, + "Shape", + NULL, + &exception); + + CU_ASSERT_FATAL(!result); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + result = access_control->get_topic_sec_attributes( + access_control, + local_permissions_handle + 12345, + "Shape", + &attributes, + &exception); + + CU_ASSERT_FATAL(!result); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_PARAMETER_CODE); + + //reset control values + memset(&attributes, 0, sizeof(attributes)); + reset_exception(&exception); + + plugins_fini(); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, participant_2nd_rule, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_ParticipantSecurityAttributes attributes; + bool result; + + result = plugins_init(); + CU_ASSERT_FATAL(result); + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(access_control->get_participant_sec_attributes != NULL); + + result = create_local_identity(30, "Test_Governance_full.p7s"); + CU_ASSERT_FATAL(result); + + memset(&attributes, 0, sizeof(attributes)); + + result = access_control->get_participant_sec_attributes( + access_control, + local_permissions_handle, + &attributes, + &exception); + CU_ASSERT(result); + + /* + * Expect these values based on these options, which is the 2nd domain rule + * in the Test_Governance_full.p7s (selected because of domain id 30): + * + * 1 + * 0 + * SIGN + * ENCRYPT + * NONE + */ + CU_ASSERT(attributes.allow_unauthenticated_participants == true); + CU_ASSERT(attributes.is_access_protected == false); + CU_ASSERT(attributes.is_discovery_protected == true); + CU_ASSERT(attributes.is_liveliness_protected == true); + CU_ASSERT(attributes.is_rtps_protected == false); + CU_ASSERT((attributes.plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED) == + 0); + CU_ASSERT((attributes.plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_ENCRYPTED) == + 0); + CU_ASSERT((attributes.plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_ENCRYPTED) == + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_ENCRYPTED); + CU_ASSERT((attributes.plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_AUTHENTICATED) == + 0); + CU_ASSERT((attributes.plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_AUTHENTICATED) == + 0); + CU_ASSERT((attributes.plugin_participant_attributes & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_AUTHENTICATED) == + 0); + + result = access_control->return_participant_sec_attributes( + access_control, + &attributes, + &exception); + CU_ASSERT(result); + + clear_local_identity(); + plugins_fini(); +} + +static void test_liveliness_discovery_participant_attr( + DDS_Security_PermissionsHandle hdl, + bool liveliness_protected, + DDS_Security_unsigned_long liveliness_mask, + bool discovery_protected, + DDS_Security_unsigned_long discovery_mask) +{ + DDS_Security_unsigned_long mask = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID | + liveliness_mask | + discovery_mask; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_ParticipantSecurityAttributes attr; + bool result; + + CU_ASSERT_FATAL(access_control->get_participant_sec_attributes != NULL); + + memset(&attr, 0, sizeof(attr)); + + result = access_control->get_participant_sec_attributes( + access_control, + hdl, + &attr, + &exception); + CU_ASSERT(result); + + CU_ASSERT(attr.allow_unauthenticated_participants == false); + CU_ASSERT(attr.is_access_protected == true); + CU_ASSERT(attr.is_discovery_protected == discovery_protected); + CU_ASSERT(attr.is_liveliness_protected == liveliness_protected); + CU_ASSERT(attr.is_rtps_protected == false); + CU_ASSERT(attr.plugin_participant_attributes == mask); + + result = access_control->return_participant_sec_attributes( + access_control, + &attr, + &exception); + CU_ASSERT(result); +} + +static void test_liveliness_discovery_writer_attr( + const char *topic_name, + DDS_Security_PermissionsHandle hdl, + bool liveliness_protected, + bool discovery_protected, + bool submsg_protected, + DDS_Security_unsigned_long submsg_mask) +{ + DDS_Security_unsigned_long mask = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID | submsg_mask; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_EndpointSecurityAttributes attr; + DDS_Security_DataTagQosPolicy data_tag; + DDS_Security_PartitionQosPolicy *partition = NULL; + bool result; + + CU_ASSERT_FATAL(access_control->get_datawriter_sec_attributes != NULL); + + memset(&attr, 0, sizeof(attr)); + + result = access_control->get_datawriter_sec_attributes( + access_control, + hdl, + topic_name, + partition, + &data_tag, + &attr, + &exception); + CU_ASSERT_FATAL(result); + + CU_ASSERT(attr.is_read_protected == false); + CU_ASSERT(attr.is_write_protected == false); + CU_ASSERT(attr.is_submessage_protected == submsg_protected); + CU_ASSERT(attr.is_payload_protected == false); + CU_ASSERT(attr.is_key_protected == false); + CU_ASSERT(attr.is_discovery_protected == discovery_protected); + CU_ASSERT(attr.is_liveliness_protected == liveliness_protected); + CU_ASSERT(attr.plugin_endpoint_attributes == mask); + + result = access_control->return_datawriter_sec_attributes( + access_control, + &attr, + &exception); + CU_ASSERT(result); +} + +static void test_liveliness_discovery_reader_attr( + const char *topic_name, + DDS_Security_PermissionsHandle hdl, + bool liveliness_protected, + bool discovery_protected, + bool submsg_protected, + DDS_Security_unsigned_long submsg_mask) +{ + DDS_Security_unsigned_long mask = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID | submsg_mask; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_EndpointSecurityAttributes attr; + DDS_Security_DataTagQosPolicy data_tag; + DDS_Security_PartitionQosPolicy *partition = NULL; + bool result; + + CU_ASSERT_FATAL(access_control->get_datareader_sec_attributes != NULL); + + memset(&attr, 0, sizeof(attr)); + + result = access_control->get_datareader_sec_attributes( + access_control, + hdl, + topic_name, + partition, + &data_tag, + &attr, + &exception); + CU_ASSERT_FATAL(result); + + CU_ASSERT(attr.is_read_protected == false); + CU_ASSERT(attr.is_write_protected == false); + CU_ASSERT(attr.is_submessage_protected == submsg_protected); + CU_ASSERT(attr.is_payload_protected == false); + CU_ASSERT(attr.is_key_protected == false); + CU_ASSERT(attr.is_discovery_protected == discovery_protected); + CU_ASSERT(attr.is_liveliness_protected == liveliness_protected); + CU_ASSERT(attr.plugin_endpoint_attributes == mask); + + result = access_control->return_datareader_sec_attributes( + access_control, + &attr, + &exception); + CU_ASSERT(result); +} + +static void test_liveliness_discovery_attr( + const char *governance, + bool liveliness_protected, + DDS_Security_unsigned_long liveliness_mask, + bool discovery_protected, + DDS_Security_unsigned_long discovery_mask) +{ + DDS_Security_unsigned_long submsg_liveliness_mask = 0; + DDS_Security_unsigned_long submsg_discovery_mask = 0; + bool result; + + result = plugins_init(); + CU_ASSERT_FATAL(result); + CU_ASSERT_FATAL(access_control != NULL); + + result = create_local_identity(0, governance); + CU_ASSERT_FATAL(result); + + /* For some endpoints, the submsg encryption mask depends on either the + * discovery or liveliness mask. */ + if (liveliness_mask & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_ENCRYPTED) + { + submsg_liveliness_mask |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + } + if (liveliness_mask & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_AUTHENTICATED) + { + submsg_liveliness_mask |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + if (discovery_mask & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_ENCRYPTED) + { + submsg_discovery_mask |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + } + if (discovery_mask & DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_AUTHENTICATED) + { + submsg_discovery_mask |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ORIGIN_AUTHENTICATED; + } + + /* Participant attributes */ + + test_liveliness_discovery_participant_attr( + local_permissions_handle, + liveliness_protected, + liveliness_mask, + discovery_protected, + discovery_mask); + + /* Writer attributes */ + + /* User topic. */ + test_liveliness_discovery_writer_attr( + "Kinematics", + local_permissions_handle, + liveliness_protected, + discovery_protected, + false /* submsg_protected */, + 0 /* submsg_mask */); + + /* Builtin topic. */ + test_liveliness_discovery_writer_attr( + "DCPSPublication", + local_permissions_handle, + false /* liveliness_protected */, + false /* discovery_protected */, + false /* submsg_protected */, + 0 /* submsg_mask */); + + /* Security (normal) builtin topic. */ + test_liveliness_discovery_writer_attr( + "DCPSPublicationsSecure", + local_permissions_handle, + false /* liveliness_protected */, + false /* discovery_protected */, + discovery_protected /* submsg_protected */, + submsg_discovery_mask /* submsg_mask */); + + /* Security (liveliness affected) builtin topic. */ + test_liveliness_discovery_writer_attr( + "DCPSParticipantMessageSecure", + local_permissions_handle, + false /* liveliness_protected */, + false /* discovery_protected */, + liveliness_protected /* submsg_protected */, + submsg_liveliness_mask /* submsg_mask */); + + /* Reader attributes */ + + /* User topic. */ + test_liveliness_discovery_reader_attr( + "Kinematics", + local_permissions_handle, + liveliness_protected, + discovery_protected, + false /* submsg_protected */, + false /* submsg_mask */); + + /* Builtin topic. */ + test_liveliness_discovery_reader_attr( + "DCPSPublication", + local_permissions_handle, + false /* liveliness_protected */, + false /* discovery_protected */, + false /* submsg_protected */, + 0 /* submsg_mask */); + + /* Security (normal) builtin topic. */ + test_liveliness_discovery_reader_attr( + "DCPSPublicationsSecure", + local_permissions_handle, + false /* liveliness_protected */, + false /* discovery_protected */, + discovery_protected /* submsg_protected */, + submsg_discovery_mask /* submsg_mask */); + + /* Security (liveliness affected) builtin topic. */ + test_liveliness_discovery_reader_attr( + "DCPSParticipantMessageSecure", + local_permissions_handle, + false /* liveliness_protected */, + false /* discovery_protected */, + liveliness_protected /* submsg_protected */, + submsg_liveliness_mask /* submsg_mask */); + + clear_local_identity(); + plugins_fini(); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, liveliness_discovery_clear, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + /* + * Expect these values based on these options, which is the 1st domain rule + * in the Test_Governance_liveliness_discovery_clear.p7s (selected because of domain id 0): + * + * false + * true + * NONE + * NONE + * NONE + * + * + * * + * false + * false + * false + * false + * NONE + * NONE + * + * + */ + test_liveliness_discovery_attr( + "Test_Governance_liveliness_discovery_clear.p7s", + /* liveliness_protected */ + false, + /* liveliness_mask */ + 0, + /* discovery_protected */ + false, + /* discovery_mask */ + 0); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, liveliness_discovery_encrypted, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + /* + * Expect these values based on these options, which is the 1st domain rule + * in the Test_Governance_liveliness_discovery_clear.p7s (selected because of domain id 0): + * + * false + * true + * ENCRYPT + * ENCRYPT + * NONE + * + * + * * + * true + * true + * false + * false + * NONE + * NONE + * + * + */ + test_liveliness_discovery_attr( + "Test_Governance_liveliness_discovery_encrypted.p7s", + /* liveliness_protected */ + true, + /* liveliness_mask */ + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_ENCRYPTED, + /* discovery_protected */ + true, + /* discovery_mask */ + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_ENCRYPTED); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, liveliness_discovery_signed, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + /* + * Expect these values based on these options, which is the 1st domain rule + * in the Test_Governance_liveliness_discovery_clear.p7s (selected because of domain id 0): + * + * false + * true + * SIGN + * SIGN + * NONE + * + * + * * + * true + * true + * false + * false + * NONE + * NONE + * + * + */ + test_liveliness_discovery_attr( + "Test_Governance_liveliness_discovery_signed.p7s", + /* liveliness_protected */ + true, + /* liveliness_mask */ + 0, + /* discovery_protected */ + true, + /* discovery_mask */ + 0); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, liveliness_discovery_encrypted_and_authenticated, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + /* + * Expect these values based on these options, which is the 1st domain rule + * in the Test_Governance_liveliness_discovery_clear.p7s (selected because of domain id 0): + * + * false + * true + * ENCRYPT_WITH_ORIGIN_AUTHENTICATION + * ENCRYPT_WITH_ORIGIN_AUTHENTICATION + * NONE + * + * + * * + * true + * true + * false + * false + * NONE + * NONE + * + * + */ + test_liveliness_discovery_attr( + "Test_Governance_liveliness_discovery_encrypted_and_authenticated.p7s", + /* liveliness_protected */ + true, + /* liveliness_mask */ + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_ENCRYPTED | + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_AUTHENTICATED, + /* discovery_protected */ + true, + /* discovery_mask */ + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_ENCRYPTED | + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_AUTHENTICATED); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, liveliness_discovery_signed_and_authenticated, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + /* + * Expect these values based on these options, which is the 1st domain rule + * in the Test_Governance_liveliness_discovery_clear.p7s (selected because of domain id 0): + * + * false + * true + * SIGN_WITH_ORIGIN_AUTHENTICATION + * SIGN_WITH_ORIGIN_AUTHENTICATION + * NONE + * + * + * * + * true + * true + * false + * false + * NONE + * NONE + * + * + */ + test_liveliness_discovery_attr( + "Test_Governance_liveliness_discovery_signed_and_authenticated.p7s", + /* liveliness_protected */ + true, + /* liveliness_mask */ + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_LIVELINESS_AUTHENTICATED, + /* discovery_protected */ + true, + /* discovery_mask */ + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_AUTHENTICATED); +} + +CU_Test(ddssec_builtin_get_xxx_sec_attributes, liveliness_discovery_different, .init = suite_get_xxx_sec_attributes_init, .fini = suite_get_xxx_sec_attributes_fini) +{ + /* + * Expect these values based on these options, which is the 1st domain rule + * in the Test_Governance_liveliness_discovery_clear.p7s (selected because of domain id 0): + * + * false + * true + * ENCRYPT + * NONE + * NONE + * + * + * * + * false + * true + * false + * false + * NONE + * NONE + * + * + */ + test_liveliness_discovery_attr( + "Test_Governance_liveliness_discovery_different.p7s", + /* liveliness_protected */ + false, + /* liveliness_mask */ + 0, + /* discovery_protected */ + true, + /* discovery_mask */ + DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_DISCOVERY_ENCRYPTED); +} diff --git a/src/security/builtin_plugins/tests/listeners_access_control/etc/Test_Governance_ok.p7s b/src/security/builtin_plugins/tests/listeners_access_control/etc/Test_Governance_ok.p7s new file mode 100644 index 0000000..c39903f --- /dev/null +++ b/src/security/builtin_plugins/tests/listeners_access_control/etc/Test_Governance_ok.p7s @@ -0,0 +1,114 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----DB94A190D9780A24156FB0E8F1E76B5F" + +This is an S/MIME signed message + +------DB94A190D9780A24156FB0E8F1E76B5F +Content-Type: text/plain + + + + + + + + + 0 + 230 + + + + + false + + + true + + + ENCRYPT + + + ENCRYPT + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + ENCRYPT + + + ENCRYPT + + + + + + +------DB94A190D9780A24156FB0E8F1E76B5F +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGSAYJKoZIhvcNAQcCoIIGOTCCBjUCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCAnswggJ3AgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggeQwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTgwOTEzMDczOTUwWjAvBgkqhkiG9w0BCQQxIgQgXv8DkvlwebXMwHDbNc0/Pc30 +gyG3xWCnwet49TRMWFsweQYJKoZIhvcNAQkPMWwwajALBglghkgBZQMEASowCwYJ +YIZIAWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG9w0DAgIC +AIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwDQYJKoZI +hvcNAQEBBQAEggEANy8t0EFmv5j1n0+mMn2ut3Chu8PSJceC8gd34IiKq79uC1O3 +PbL9xgiJ2vz7QiTEEeNL2q+CG77cXOcHGUWa4nvbggr/9CqLfHEKGQxDfyXlJZfM +8l550xIXRRBOQ7ilOGLD4QJFfbf9XA4rMuRe8WEYN3FleAaYBJag1tMPg1SS6tgA +BBDM9b1kXHU319zYOk6kZFjlbwHv6XO22SEVRUpXrKudAI8hrGvwksF/+W0S/jS5 +NmYtj/1oMGlCGIaA5rs27H9CkgwrzoMQ3MsR98JlwEUSa4PEe8CClsIziOulQxsp +MicBlMWL0rzpBPVfPTE4gZ/kP7hGBDEQlRzVTA== + +------DB94A190D9780A24156FB0E8F1E76B5F-- + diff --git a/src/security/builtin_plugins/tests/listeners_access_control/etc/Test_Permissions_ca.pem b/src/security/builtin_plugins/tests/listeners_access_control/etc/Test_Permissions_ca.pem new file mode 100644 index 0000000..2372ae0 --- /dev/null +++ b/src/security/builtin_plugins/tests/listeners_access_control/etc/Test_Permissions_ca.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV +BAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQKDBZBRExJTksgVGVj +aG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNvbTAgFw0xODA3MzAx +MjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMCTkwxEzARBgNVBAgM +ClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4xFzAV +BgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blIDehV6XCxrnGXusTCD +uFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9wicp3BGSpZZax/TcO +NjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLsDFFC+a0qn2RFh37r +cWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074BRDXVivx+wVD951L +FNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiySogRWAmKhysLQudu +kHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNVHQ4EFgQURWMbWvBK +ZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJvRV1/tyc1R82k0+gw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ysVtvHnk2hpu9yND +LCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9XVh0rGoR/6nHzo3TI +eiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9yghhKHHqNDvSsAL0 +KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbtlLX3QnwVOmaRyzyl +PiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42+OyLqcH1rKT6Xhcs +hjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb6SDB340BFmtgDHbF +HQ== +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/listeners_access_control/etc/Test_Permissions_ca_key.pem b/src/security/builtin_plugins/tests/listeners_access_control/etc/Test_Permissions_ca_key.pem new file mode 100644 index 0000000..22fac8b --- /dev/null +++ b/src/security/builtin_plugins/tests/listeners_access_control/etc/Test_Permissions_ca_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blIDehV6XCxr +nGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9wicp3BGSp +ZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLsDFFC+a0q +n2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074BRDXVivx ++wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiySogRWAmK +hysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABAoIBABWqhMSCr+7Mr3O3 +bIymOr+CT4xWI8S47hmKGFCLTrNsfy7cQZ9PdHkm7Ez+rCx+KwQaTrwz7EM/e8aH +q2zimMn4YXxeS7MFdM+Xvp/Y0BhXMd1j8Nk0x14+WHmQ88YfA4szdrHDekR+6oB6 +5Lc2fAfNbCGdpRksCQWDndrvIOda1swKW1RsGWHPGtSM1qOg09A4CeASqbsxZfdL +9MgI7aJKYnvJrUhqsNZU3fuOrLDNl7/JvdI08nYLnNkEvbDYbdfH0Q/4laKsSJcp +0jM6tPrxbHMDmBEwullVPrVqJX+n6Hvz3E8C9QiZq8NWbJUc5FntLx8ynbiJg6Lb +1w49WxECgYEA8yVky++3v0ZMKZeSeGj3MuKuEJ2q3UdmsKXA+Pyq0rL/hh7r2oUY +dQDs23BIuaHeIZxAGaMeMjoYQBi+G50XfwHZSMqivxX/yYkXxOJfPQvVLDbqCIWS +94qU4/xo50IkCNxpvRwfpKG2ce5YG7jrQkfb5I6TfKUWAaXpmaQnbYsCgYEAxaVn +Hzw3OdY7q6kURSY6a8KqtcuN0lNKeUb68vZemmZ0FNKmyh+xGVFXXlvmJpQgr5Zm +2W2a1C1oPq2DEdvSKt/aTHVIazG9TtFK1WAXpLxmlXlyqWRv+IvdVkph+p/3dIT0 +Ilaglgbndth4xk0c1zqy3g4VlAgWgKKi5owZ/j8CgYEAndsFGbHEJZZKFCannSzo +cEzinT7/kzGr5bt3ES9Y5/n2Euk4TmJignPbUowPaxU/1apPo1VXYVx+Kf7mTZ8r +hfV5T9ze1BhAPGOY3uXo1wU7nLz6LBYsWDHMgEd7A8jZBDe1HmWH1aZ3gHgxE652 +bk2g4T3/WskDBIbmpi0AvAkCgYBKAfFnRMj5IzscwCcS7YmaqD377MiiJQYR+34k +VBSAhDSbR3Wk4dESxd6NOqQndff3R74jVGNRZ99M+PPHUCSWYVQApToEyY81YDFB +TMYNrW5MMjm5LB6xVs3+bcPacOPcAZzY7s8a3mL1oYE339AY16X6eBOkZpLmf/+3 +jGZ/SQKBgQDkyxymL4xJGV8HCDontJZiBStD954GH1AgqEAOdQxU5vW4ySQ7yRoT +ajb8tH052yWW11Mxd0TRW9qbVI0/4/4lR86sODYLFbgrHAMBl7mxJ8Qwi4zdI9Am +FXGkj5SX2bYrf2f0YvCHNUbELTd4mF6kAH0Eg6kHRXLsSbhtWC7D3Q== +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/listeners_access_control/src/listeners_access_control_utests.c b/src/security/builtin_plugins/tests/listeners_access_control/src/listeners_access_control_utests.c new file mode 100644 index 0000000..5cc898a --- /dev/null +++ b/src/security/builtin_plugins/tests/listeners_access_control/src/listeners_access_control_utests.c @@ -0,0 +1,668 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/io.h" +#include "dds/ddsrt/misc.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "config_env.h" + +static const char *ACCESS_PERMISSIONS_TOKEN_ID = "DDS:Access:Permissions:1.0"; +static const char *AUTH_PROTOCOL_CLASS_ID = "DDS:Auth:PKI-DH:1.0"; + +static const char *PROPERTY_IDENTITY_CA = "dds.sec.auth.identity_ca"; +static const char *PROPERTY_PRIVATE_KEY = "dds.sec.auth.private_key"; +static const char *PROPERTY_IDENTITY_CERT = "dds.sec.auth.identity_certificate"; +static const char *PROPERTY_PERMISSIONS_CA = "dds.sec.access.permissions_ca"; +static const char *PROPERTY_PERMISSIONS = "dds.sec.access.permissions"; +static const char *PROPERTY_GOVERNANCE = "dds.sec.access.governance"; + +static const char *PROPERTY_PERMISSIONS_CA_SN = "dds.perm_ca.sn"; +static const char *PROPERTY_PERMISSIONS_CA_ALGO = "dds.perm_ca.algo"; +static const char *PROPERTY_C_ID = "c.id"; +static const char *PROPERTY_C_PERM = "c.perm"; + +static const char *SUBJECT_NAME_PERMISSIONS_CA = "C=NL, ST=Some-State, O=ADLINK Technolocy Inc., CN=adlinktech.com"; +static const char *RSA_2048_ALGORITHM_NAME = "RSA-2048"; + +static const char *RELATIVE_PATH_TO_ETC_DIR = "/listeners_access_control/etc/"; +static const char *PERMISSIONS_CA_CERT_FILE = "Test_Permissions_ca.pem"; +static const char *PERMISSIONS_CA_KEY_FILE = "Test_Permissions_ca_key.pem"; +static const char *PERMISSIONS_FILE = "Test_Permissions_listener.p7s"; +static dds_security_access_control_listener ac_listener; + +static const char *identity_certificate = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEQTCCAymgAwIBAgIINpuaAAnrQZIwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE3MDIy\n" + "MjIyMjIwMFoYDzIyMjIwMjIyMjIyMjAwWjBcMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRUwEwYDVQQDEwxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n" + "ggEKAoIBAQDCpVhivH/wBIyu74rvQncnSZqKyspN6CvD1pmV9wft5PHhVt9jV79v\n" + "gSub5LADoRHAgFdv9duYgBr17Ob6uRrIY4B18CcrCjhQcC4gjx8y2jl9PeYm+qYD\n" + "3o44FYBrBq0QCnrQgKsb/qX9Z+Mw/VUiw65x68W876LEHQQoEgT4kxSuagwBoVRk\n" + "ePD6fYAKmT4XS3x+O0v+rHESTcsKF6yMadgp7h3eH1b8kJTzSx8JV9Zzq++mxjox\n" + "qhbBVP5nDze2hhSIeCkCvSrx7efkgKS4AQXa5/Z44GiAu1TfXXUqdic9rxwD0edn\n" + "ajNElnZe7sjok/0yuqvH+2hSqpNva/zpAgMBAAGjggEAMIH9MAwGA1UdDwQFAwMH\n" + "/4AwgewGA1UdJQSB5DCB4QYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYI\n" + "KwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3AgEVBgorBgEEAYI3AgEWBgorBgEE\n" + "AYI3CgMBBgorBgEEAYI3CgMDBgorBgEEAYI3CgMEBglghkgBhvhCBAEGCysGAQQB\n" + "gjcKAwQBBggrBgEFBQcDBQYIKwYBBQUHAwYGCCsGAQUFBwMHBggrBgEFBQgCAgYK\n" + "KwYBBAGCNxQCAgYIKwYBBQUHAwkGCCsGAQUFBwMNBggrBgEFBQcDDgYHKwYBBQID\n" + "BTANBgkqhkiG9w0BAQsFAAOCAQEAawdHy0Xw7nTK2ltp91Ion6fJ7hqYuj///zr7\n" + "Adt6uonpDh/xl3esuwcFimIJrJrHujnGkL0nLddRCikmnzuBMNDWS6yq0/Ckl/YG\n" + "yjNr44dlX24wo+MVAgkj3/8CyWDZ3a8kBg9QT3bs2SqbjmhTrXN1DRyf9S5vJysE\n" + "I7V1gTN66BeKL64hOrAlRVrEu8Ds6TWL6Q/YH+61ViZkoLTeSaPjH4nknaFr4C35\n" + "iji0JhkyfRHRRVPHFnaj25AkxOrSV64qVKoTMjDl5fji5iMGtjm6iJ7q05ml/qDl\n" + "nLotHXemZNvYhbwUmRzbt4Dls9EMH4VRbP85I94nM5TAvtHVNA==\n" + "-----END CERTIFICATE-----\n"; + +static const char *identity_ca = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEmTCCA4GgAwIBAgIIZ5gEIUFhO5wwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDIx\n" + "MjE1MDUwMFoYDzIyMjIwMjIyMjIyMjAwWjBfMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRgwFgYDVQQDEw9DSEFNNTAwIHJvb3QgY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" + "DwAwggEKAoIBAQC6Fa3TheL+UrdZCp9GhU/2WbneP2t/avUa3muwDttPxeI2XU9k\n" + "ZjBR95mAXme4SPXHk5+YDN319AqIje3oKhzky/ngvKH2GkoJKYxWnuDBfMEHdViz\n" + "2Q9/xso2ZvH50ukwWa0pfx2/EVV1wRxeQcRd/UVfq3KTJizG0M88mOYvGEAw3LFf\n" + "zef7k1aCuOofQmBvLukUudcYpMzfyHFp7lQqU4CcrrR5RtmfiUfrWfdGLea2iPDB\n" + "pJgN8ESOMwEHtOTEBDclYnH9L4t7CHQz+fXXS5IWFsDK9fCMQjnxDsDVeNrNzTYL\n" + "FaZrMg9S6IUQCEsQWsnq5weS8omOpVLUm9klAgMBAAGjggFVMIIBUTAMBgNVHRME\n" + "BTADAQH/MB0GA1UdDgQWBBQg2FZB/j8uWDVnJhjwXkX278znSTAfBgNVHSMEGDAW\n" + "gBQg2FZB/j8uWDVnJhjwXkX278znSTAPBgNVHQ8BAf8EBQMDB/+AMIHvBgNVHSUB\n" + "Af8EgeQwgeEGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwME\n" + "BggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK\n" + "KwYBBAGCNwoDAwYKKwYBBAGCNwoDBAYJYIZIAYb4QgQBBgsrBgEEAYI3CgMEAQYI\n" + "KwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUIAgIGCisGAQQBgjcU\n" + "AgIGCCsGAQUFBwMJBggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZI\n" + "hvcNAQELBQADggEBAKHmwejWRwGE1wf1k2rG8SNRV/neGsZ6Qfqf6co3TpR/Wi1s\n" + "iZDvSeT/rbqNBS7z34xnG88NIUwu00y78e8Mfon31ZZbK4Uo7fla9/D3ukdJqPQC\n" + "LKdbKJjR2kH+KCukY/1rghjJ8/X+t2egBit0LCOdsFCl07Sfksb9kpGUIZSFcYYm\n" + "geqhjhoNwxazzHiw+QWHC5HG9248JIizBmy1aymNWuMnPudhjHAnPcsIlqMVNq3t\n" + "Rv9ap7S8JeCxHVRPJvJeCwXWvW3dW/v3xH52Yn/fqRblN1w9Fxz5NhopKx0gj/Jd\n" + "sw2N4Fk4gaOWEolFpa0bwNw8nAx7moehZpowzfw=\n" + "-----END CERTIFICATE-----\n"; + +static const char *private_key = + "data:,-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEogIBAAKCAQEAwqVYYrx/8ASMru+K70J3J0maisrKTegrw9aZlfcH7eTx4Vbf\n" + "Y1e/b4Erm+SwA6ERwIBXb/XbmIAa9ezm+rkayGOAdfAnKwo4UHAuII8fMto5fT3m\n" + "JvqmA96OOBWAawatEAp60ICrG/6l/WfjMP1VIsOucevFvO+ixB0EKBIE+JMUrmoM\n" + "AaFUZHjw+n2ACpk+F0t8fjtL/qxxEk3LChesjGnYKe4d3h9W/JCU80sfCVfWc6vv\n" + "psY6MaoWwVT+Zw83toYUiHgpAr0q8e3n5ICkuAEF2uf2eOBogLtU3111KnYnPa8c\n" + "A9HnZ2ozRJZ2Xu7I6JP9Mrqrx/toUqqTb2v86QIDAQABAoIBAC1q32DKkx+yMBFx\n" + "m32QiLUGG6VfBC2BixS7MkMnzRXZYgcuehl4FBc0kLRjfB6cqsO8LqrVN1QyMBhK\n" + "GutN3c38SbE7RChqzhEW2+yE+Mao3Nk4ZEecHLiyaYT0n25ZtHAVwep823BAzwJ+\n" + "BykbM45VEpNKbG1VjSktjBa9faNyZiZAEJEjVyla+6R8N4kHV52LbZcLjvJv3IQ2\n" + "iPYRrmMyI5C23qTni0vy7yJbAXBo3CqgSlwie9FARBWT7Puu7F4mF1O1c/SnTysw\n" + "Tm3e5FzgfHipQbnRVn0w4rDprPMKmPxMnvf/Wkw0zVgNadp1Tc1I6Yj525DEQ07i\n" + "2gIn/gECgYEA4jNnY1u2Eu7x3pAQF3dRO0x35boVtuq9iwQk7q+uaZaK4RJRr+0Y\n" + "T68S3bPnfer6SHvcxtST89Bvs/j/Ky4SOaX037UYjFh6T7OIzPl+MzO1yb+VOBT6\n" + "D6FVGEJGp8ZAITU1OfJPeTYViUeEC8tHFGoKUCk50FbB6jOf1oKtv/ECgYEA3EnB\n" + "Y7kSbJJaUuj9ciFUL/pAno86Cim3VjegK1wKgEiyDb610bhoMErovPwfVJbtcttG\n" + "eKJNuwizkRcVbj+vpjDvqqaP5eMxLl6/Nd4haPMJYzGo88Z8NJpwFRNF2KEWjOpQ\n" + "2NEvoCeRtVulCJyka2Tpljzw8cOXkxhPOe2UhHkCgYBo3entj0QO7QXm56T+LAvV\n" + "0PK45xdQEO3EuCwjGAFk5C0IgUSrqeCeeIzniZMltj1IQ1wsNbtNynEu3530t8wt\n" + "O7oVyFBUKGSz9IjUdkpClJOPr6kPMfJoMqRPtdIpz+hFPPSrI6IikKdVWHloOlp+\n" + "pVaYqTQrWT1XRY2xli3VEQKBgGySmZN6Cx+h/oywswIGdUT0VdcQhq2to+QFpJba\n" + "VX6m1cM6hMip2Ag9U3qZ1SNPBBdBBfm9HQybHE3dj713/C2wHuAAGhpXIM1W+20k\n" + "X1knuC/AsSH9aQhQOf/ZMOq1crTfZBuI9q0782/sjGmzMsKPySU4QhUWruVb7OiD\n" + "NVkZAoGAEvihW7G+8/iOE40vGHyBqUeopAAWLciTAUIEwM/Oi3BYfNWNTWF/FWNc\n" + "nMvCZPYigY8C1vO+1iT2Frtd3CIU+f01Q3fJNJoRLlEiKLNZUJRF48OKUqjKSmsi\n" + "w6pucFO40z05YW7utApj4L82rZnOS0pd1tUI1yexqvj0i4ThJfk=\n" + "-----END RSA PRIVATE KEY-----\n"; + +static const char *permissions_ca = /*Test_Permissions_ca.pem */ + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV\n" + "BAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQKDBZBRExJTksgVGVj\n" + "aG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNvbTAgFw0xODA3MzAx\n" + "MjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMCTkwxEzARBgNVBAgM\n" + "ClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4xFzAV\n" + "BgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" + "CgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blIDehV6XCxrnGXusTCD\n" + "uFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9wicp3BGSpZZax/TcO\n" + "NjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLsDFFC+a0qn2RFh37r\n" + "cWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074BRDXVivx+wVD951L\n" + "FNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiySogRWAmKhysLQudu\n" + "kHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNVHQ4EFgQURWMbWvBK\n" + "ZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJvRV1/tyc1R82k0+gw\n" + "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ysVtvHnk2hpu9yND\n" + "LCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9XVh0rGoR/6nHzo3TI\n" + "eiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9yghhKHHqNDvSsAL0\n" + "KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbtlLX3QnwVOmaRyzyl\n" + "PiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42+OyLqcH1rKT6Xhcs\n" + "hjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb6SDB340BFmtgDHbF\n" + "HQ==\n" + "-----END CERTIFICATE-----\n"; + +#define PERMISSIONS_DOCUMENT " \ + \ + \ + \ + /C=NL/ST=Some-State/O=Internet Widgits Pty Ltd/CN=CHAM500 cert \ + \ + 2015-09-15T01:00:00 \ + PERMISSION_EXPIRY_DATE \ + \ + \ + \ + \ + 0 \ + 230 \ + \ + \ + \ + \ + * \ + \ + \ + \ + \ + \ + * \ + \ + \ + \ + \ + DENY \ + \ + \ + " + +static struct plugins_hdl *plugins = NULL; +static dds_security_authentication *auth = NULL; +static dds_security_access_control *access_control = NULL; +static DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_IdentityHandle remote_identity_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_PermissionsHandle local_permissions_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_PermissionsHandle remote_permissions_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_GUID_t local_participant_guid; +static char *g_path_to_etc_dir = NULL; +static char *g_path_build_dir = NULL; +static DDS_Security_PermissionsHandle permission_handle_for_callback1 = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_PermissionsHandle permission_handle_for_callback2 = DDS_SECURITY_HANDLE_NIL; +static dds_time_t local_expiry_date; +static dds_time_t remote_expiry_date; + +static void dds_security_property_init(DDS_Security_PropertySeq *seq, DDS_Security_unsigned_long size) +{ + seq->_length = size; + seq->_maximum = size; + seq->_buffer = ddsrt_malloc(size * sizeof(DDS_Security_Property_t)); + memset(seq->_buffer, 0, size * sizeof(DDS_Security_Property_t)); +} + +static void dds_security_property_deinit(DDS_Security_PropertySeq *seq) +{ + uint32_t i; + + for (i = 0; i < seq->_length; i++) + { + ddsrt_free(seq->_buffer[i].name); + ddsrt_free(seq->_buffer[i].value); + } + ddsrt_free(seq->_buffer); +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void get_future_xsdate(char *str, size_t len, int32_t delta) +{ + time_t rawtime; + struct tm *future = ddsrt_malloc(sizeof(struct tm)); + + /* Get future time. */ + rawtime = time(NULL) + delta; + OPENSSL_gmtime(&rawtime, future); + + /* Put the future time in a xsDate format. */ + strftime(str, len, "%Y-%m-%dT%H:%M:%S", future); + + ddsrt_free(future); +} + +static int smime_sign(const char *certificate_file, const char *key_file, const char *data, const char *out_file) +{ + BIO *in = NULL, *out = NULL, *tbio = NULL, *keybio = NULL; + X509 *scert = NULL; + EVP_PKEY *skey = NULL; + PKCS7 *p7 = NULL; + int ret = 1; + int flags = PKCS7_DETACHED | PKCS7_STREAM | PKCS7_TEXT; + + /* Read in signer certificate and private key */ + tbio = BIO_new_file(certificate_file, "r"); + if (!tbio) + goto err; + scert = PEM_read_bio_X509(tbio, NULL, 0, NULL); + + keybio = BIO_new_file(key_file, "r"); + if (!keybio) + goto err; + + skey = PEM_read_bio_PrivateKey(keybio, NULL, 0, NULL); + if (!scert || !skey) + goto err; + + /* Open content being signed */ + in = BIO_new_mem_buf(data, (int)strlen(data)); + if (!in) + goto err; + /* Sign content */ + p7 = PKCS7_sign(scert, skey, NULL, in, flags); + if (!p7) + goto err; + out = BIO_new_file(out_file, "w"); + if (!out) + goto err; + + //if (!(flags & PKCS7_STREAM)) + // BIO_reset(in); + + /* Write out S/MIME message */ + if (!SMIME_write_PKCS7(out, p7, in, flags)) + goto err; + ret = 0; +err: + if (ret) + { + fprintf(stderr, "Error Signing Data\n"); + ERR_print_errors_fp(stderr); + } + if (p7) + PKCS7_free(p7); + if (scert) + X509_free(scert); + if (skey) + EVP_PKEY_free(skey); + if (in) + BIO_free(in); + if (keybio) + BIO_free(keybio); + if (out) + BIO_free(out); + if (tbio) + BIO_free(tbio); + + return ret; +} + +static void fill_participant_qos(DDS_Security_Qos *qos, int32_t permission_expiry, const char *governance_filename) +{ + char *permission_uri; + char *governance_uri; + char *permissions_ca_cert_file; + char *permissions_ca_key_file; + char *permissions_file; + char *permissions_xml_with_expiry; + char permission_expiry_date_str[30]; + + /*get time in future */ + get_future_xsdate(permission_expiry_date_str, 30, permission_expiry); + local_expiry_date = DDS_Security_parse_xml_date(permission_expiry_date_str); + + permissions_xml_with_expiry = ddsrt_str_replace(PERMISSIONS_DOCUMENT, "PERMISSION_EXPIRY_DATE", permission_expiry_date_str, 1); + + ddsrt_asprintf(&permissions_ca_cert_file, "%s%s", g_path_to_etc_dir, PERMISSIONS_CA_CERT_FILE); + ddsrt_asprintf(&permissions_ca_key_file, "%s%s", g_path_to_etc_dir, PERMISSIONS_CA_KEY_FILE); + ddsrt_asprintf(&permissions_file, "%s%s", g_path_build_dir, PERMISSIONS_FILE); + + smime_sign(permissions_ca_cert_file, permissions_ca_key_file, permissions_xml_with_expiry, permissions_file); + + //check sign result + ddsrt_asprintf(&permission_uri, "file:%s", permissions_file); + ddsrt_asprintf(&governance_uri, "file:%s%s", g_path_to_etc_dir, governance_filename); + + memset(qos, 0, sizeof(*qos)); + dds_security_property_init(&qos->property.value, 6); + qos->property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + qos->property.value._buffer[0].value = ddsrt_strdup(identity_certificate); + qos->property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + qos->property.value._buffer[1].value = ddsrt_strdup(identity_ca); + qos->property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + qos->property.value._buffer[2].value = ddsrt_strdup(private_key); + qos->property.value._buffer[3].name = ddsrt_strdup(PROPERTY_PERMISSIONS_CA); + qos->property.value._buffer[3].value = ddsrt_strdup(permissions_ca); + qos->property.value._buffer[4].name = ddsrt_strdup(PROPERTY_PERMISSIONS); + qos->property.value._buffer[4].value = ddsrt_strdup(permission_uri); + qos->property.value._buffer[5].name = ddsrt_strdup(PROPERTY_GOVERNANCE); + qos->property.value._buffer[5].value = ddsrt_strdup(governance_uri); + + ddsrt_free(permission_uri); + ddsrt_free(governance_uri); + ddsrt_free(permissions_xml_with_expiry); + ddsrt_free(permissions_ca_key_file); + ddsrt_free(permissions_ca_cert_file); + ddsrt_free(permissions_file); +} + +static void fill_permissions_token(DDS_Security_PermissionsToken *token) +{ + memset(token, 0, sizeof(DDS_Security_PermissionsToken)); + + token->class_id = ddsrt_strdup(ACCESS_PERMISSIONS_TOKEN_ID); + token->properties._length = token->properties._maximum = 2; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(2); + + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_PERMISSIONS_CA_SN); + token->properties._buffer[0].value = ddsrt_strdup(SUBJECT_NAME_PERMISSIONS_CA); + + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_PERMISSIONS_CA_ALGO); + token->properties._buffer[1].value = ddsrt_strdup(RSA_2048_ALGORITHM_NAME); +} + +static int fill_peer_credential_token(DDS_Security_AuthenticatedPeerCredentialToken *token, int32_t permission_expiry) +{ + int result = 1; + char *permission_data; + + char *permissions_ca_cert_file; + char *permissions_ca_key_file; + char *permissions_file; + char *permissions_xml_with_expiry; + char permission_expiry_date_str[30]; + + /*get time in future */ + get_future_xsdate(permission_expiry_date_str, 30, permission_expiry); + remote_expiry_date = DDS_Security_parse_xml_date(permission_expiry_date_str); + permissions_xml_with_expiry = ddsrt_str_replace(PERMISSIONS_DOCUMENT, "PERMISSION_EXPIRY_DATE", permission_expiry_date_str, 1); + + ddsrt_asprintf(&permissions_ca_cert_file, "%s%s", g_path_to_etc_dir, PERMISSIONS_CA_CERT_FILE); + ddsrt_asprintf(&permissions_ca_key_file, "%s%s", g_path_to_etc_dir, PERMISSIONS_CA_KEY_FILE); + ddsrt_asprintf(&permissions_file, "%s%s", g_path_build_dir, PERMISSIONS_FILE); + + smime_sign(permissions_ca_cert_file, permissions_ca_key_file, permissions_xml_with_expiry, permissions_file); + + memset(token, 0, sizeof(DDS_Security_AuthenticatedPeerCredentialToken)); + + permission_data = load_file_contents(permissions_file); + + if (permission_data) + { + token->class_id = ddsrt_strdup(AUTH_PROTOCOL_CLASS_ID); + token->properties._length = token->properties._maximum = 2; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(2); + + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_C_ID); + token->properties._buffer[0].value = ddsrt_strdup(&identity_certificate[6]); + + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_C_PERM); + token->properties._buffer[1].value = permission_data; + } + else + { + ddsrt_free(permission_data); + result = 0; + } + + ddsrt_free(permissions_xml_with_expiry); + ddsrt_free(permissions_ca_key_file); + ddsrt_free(permissions_ca_cert_file); + ddsrt_free(permissions_file); + return result; +} + +static DDS_Security_long +validate_local_identity_and_permissions(int32_t permission_expiry) +{ + DDS_Security_long res = DDS_SECURITY_ERR_OK_CODE; + DDS_Security_ValidationResult_t result; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb}; + DDS_Security_EntityId_t entityId = {{0xb0, 0xb1, 0xb2}, 0x1}; + + memset(&local_participant_guid, 0, sizeof(local_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, permission_expiry, "Test_Governance_ok.p7s"); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &local_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) + { + res = DDS_SECURITY_ERR_UNDEFINED_CODE; + printf("validate_local_identity_failed: (%d) %s\n", (int)exception.code, exception.message ? exception.message : "Error message missing"); + } + + reset_exception(&exception); + + if (res == 0) + { + local_permissions_handle = access_control->validate_local_permissions( + access_control, + auth, + local_identity_handle, + 0, + &participant_qos, + &exception); + + if (local_permissions_handle == DDS_SECURITY_HANDLE_NIL) + { + printf("validate_local_permissions_failed: (%d) %s\n", (int)exception.code, exception.message ? exception.message : "Error message missing"); + if (exception.code == DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_CODE) + /* This can happen on very slow platforms or when doing a valgrind run. */ + res = DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_CODE; + else + res = DDS_SECURITY_ERR_UNDEFINED_CODE; + } + } + + dds_security_property_deinit(&participant_qos.property.value); + ddsrt_free(exception.message); + + return res; +} + +static void clear_local_identity_and_permissions(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (local_permissions_handle != DDS_SECURITY_HANDLE_NIL) + { + success = access_control->return_permissions_handle(access_control, local_permissions_handle, &exception); + if (!success) + printf("return_permission_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + reset_exception(&exception); + } + + if (local_identity_handle != DDS_SECURITY_HANDLE_NIL) + { + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + if (!success) + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + reset_exception(&exception); + } +} + +static void set_path_to_etc_dir(void) +{ + ddsrt_asprintf(&g_path_to_etc_dir, "%s%s", CONFIG_ENV_TESTS_DIR, RELATIVE_PATH_TO_ETC_DIR); +} +static void set_path_build_dir(void) +{ + ddsrt_asprintf(&g_path_build_dir, "%s/", CONFIG_ENV_BUILD_DIR); +} + +CU_Init(ddssec_builtin_listeners_access_control) +{ + int res = 0; + + plugins = load_plugins(&access_control, &auth, NULL /* Cryptograpy */); + if (!plugins) { + res = -1; + } else { + set_path_to_etc_dir(); + set_path_build_dir(); + dds_openssl_init (); + } + + return res; +} + +CU_Clean(ddssec_builtin_listeners_access_control) +{ + unload_plugins(plugins); + ddsrt_free(g_path_to_etc_dir); + return 0; +} + +static DDS_Security_boolean on_revoke_permissions_cb(const dds_security_access_control *plugin, const DDS_Security_PermissionsHandle handle) +{ + DDSRT_UNUSED_ARG(plugin); + if (permission_handle_for_callback1 == DDS_SECURITY_HANDLE_NIL) + permission_handle_for_callback1 = handle; + else if (permission_handle_for_callback2 == DDS_SECURITY_HANDLE_NIL) + permission_handle_for_callback2 = handle; + printf("Listener called for handle: %lld Local:%lld Remote:%lld\n", (long long)handle, (long long)local_permissions_handle, (long long)remote_permissions_handle); + return true; +} + +CU_Test(ddssec_builtin_listeners_access_control, local_2secs) +{ + DDS_Security_PermissionsHandle result; + DDS_Security_PermissionsToken permissions_token; + DDS_Security_AuthenticatedPeerCredentialToken credential_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_long valid; + int r; + dds_duration_t time_left = DDS_MSECS(10000); + bool local_expired = false; + bool remote_expired = false; + + local_expiry_date = 0; + remote_expiry_date = 0; + + ac_listener.on_revoke_permissions = &on_revoke_permissions_cb; + + valid = validate_local_identity_and_permissions(2); + if (valid == DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_CODE) + { + /* This can happen on very slow platforms or when doing a valgrind run. + * Just take our losses and quit, simulating a success. */ + return; + } + CU_ASSERT_FATAL(valid == DDS_SECURITY_ERR_OK_CODE); + + /* Check if we actually have validate_remote_permissions function. */ + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL(access_control->validate_remote_permissions != NULL); + CU_ASSERT_FATAL(access_control->return_permissions_handle != NULL); + + fill_permissions_token(&permissions_token); + r = fill_peer_credential_token(&credential_token, 1); + CU_ASSERT_FATAL(r); + + remote_identity_handle++; + + access_control->set_listener(access_control, &ac_listener, &exception); + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + if (result == 0) + { + printf("validate_remote_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + /* Expiry can happen on very slow platforms or when doing a valgrind run. + * Just take our losses and quit, simulating a success. */ + CU_ASSERT(exception.code == DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_CODE); + goto end; + } + + remote_permissions_handle = result; + + reset_exception(&exception); + + while (time_left > 0 && (!local_expired || !remote_expired)) + { + /* Normally, it is expected that the remote expiry is triggered before the + * local one. However, that can change on slow platforms. */ + if (remote_expiry_date < local_expiry_date) + { + if (permission_handle_for_callback1 == remote_permissions_handle) + { + remote_expired = true; + } + if (permission_handle_for_callback2 == local_permissions_handle) + { + local_expired = true; + } + } + else + { + if (permission_handle_for_callback2 == remote_permissions_handle) + { + remote_expired = true; + } + if (permission_handle_for_callback1 == local_permissions_handle) + { + local_expired = true; + } + } + + dds_sleepfor(DDS_MSECS(100)); + time_left -= DDS_MSECS(100); + } + + CU_ASSERT(local_expired); + CU_ASSERT(remote_expired); + + access_control->return_permissions_handle(access_control, result, &exception); + +end: + reset_exception(&exception); + + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&permissions_token); + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&credential_token); + + clear_local_identity_and_permissions(); +} diff --git a/src/security/builtin_plugins/tests/listeners_authentication/etc/Example_Governance.p7s b/src/security/builtin_plugins/tests/listeners_authentication/etc/Example_Governance.p7s new file mode 100644 index 0000000..8c6aae5 --- /dev/null +++ b/src/security/builtin_plugins/tests/listeners_authentication/etc/Example_Governance.p7s @@ -0,0 +1,120 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----8F2D5CA80FE8B4509AF031712E008F0E" + +This is an S/MIME signed message + +------8F2D5CA80FE8B4509AF031712E008F0E +Content-Type: text/plain + + + + + + + + + 0 + 230 + + + + + true + + + true + + + ENCRYPT + + + ENCRYPT + + + ENCRYPT + + + + + * + + + true + + + true + + + true + + + true + + + ENCRYPT + + + ENCRYPT + + + + + + +------8F2D5CA80FE8B4509AF031712E008F0E +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIHiwYJKoZIhvcNAQcCoIIHfDCCB3gCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggRnMIIEYzCCA0ugAwIBAgIJAM3yAtULcaEIMA0GCSqGSIb3DQEB +CwUAMIHHMQswCQYDVQQGEwJOTDELMAkGA1UECAwCT1YxFjAUBgNVBAcMDUxvY2Fs +aXR5IE5hbWUxITAfBgNVBAsMGE9yZ2FuaXphdGlvbmFsIFVuaXQgTmFtZTEgMB4G +A1UECgwXRXhhbXBsZSBDQSBPcmdhbml6YXRpb24xHzAdBgNVBAMMFkV4YW1wbGUg +UGVybWlzc2lvbnMgQ0ExLTArBgkqhkiG9w0BCQEWHmF1dGhvcml0eUBwZXJtaXNz +aW9uc2NhbHRkLm9yZzAeFw0xOTAyMTIxMzUyMzJaFw0yOTAyMDkxMzUyMzJaMIHH +MQswCQYDVQQGEwJOTDELMAkGA1UECAwCT1YxFjAUBgNVBAcMDUxvY2FsaXR5IE5h +bWUxITAfBgNVBAsMGE9yZ2FuaXphdGlvbmFsIFVuaXQgTmFtZTEgMB4GA1UECgwX +RXhhbXBsZSBDQSBPcmdhbml6YXRpb24xHzAdBgNVBAMMFkV4YW1wbGUgUGVybWlz +c2lvbnMgQ0ExLTArBgkqhkiG9w0BCQEWHmF1dGhvcml0eUBwZXJtaXNzaW9uc2Nh +bHRkLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKD6nYCszMha +h3xGfJy8f3lowPHIj6zcldVYs5Krg7zXxZn+20lAMHUfgQcWZAauKbCnokYfTvXV +v0j9HCpQ3mRynNTyjLjc7HxAe6kfaJ75PoIoOMMQMEGvPOqRUq0tomVVJvcgzZZk +pwE30E6xvZrlQcrkQY/aOQ0sbje+RN8RKQ9vf6O45Np/0m2K5ohZPlBqg4F539v2 +iXGZczCr9AqAszc/7rOPX1aqZmmRDou0T+Zhx3ZZSAwZYQtr7uvvlUeGmDhNh+8p +LC+1FQPtkKmcVXO8oZWm5N8piOvH3M+v3qhyPtLv30cpl0bDiFl+PN7nZ6InOOtd +ZJVMa2rYCk8CAwEAAaNQME4wHQYDVR0OBBYEFA/CtiP8Z5Fk4aWDIb2j3FPwh9pg +MB8GA1UdIwQYMBaAFA/CtiP8Z5Fk4aWDIb2j3FPwh9pgMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQELBQADggEBACBupRddIR9zYBFLGFTzeiW+H1tRRKz+B3SWnCJH +89ijEdMYlKKLYT0R18lCV0vHnl29bU1CPlkLn+GQkvdfIjKguWEQKTP+GLzoa9TV +zOKAJ8NttCyW3YqriUOUGKqra1Fdt8nvrAyZUF+v/k8pTInmCvwu3l5HrVhkKHER +IbCIohKi/2mk1JZS9reWvZhqLoUIw5IDFlqtBDYOfMaqm8XF01YjEDBM6OuyQzYN +gDFVUZx0At4zzRjGTvqpLTkDYL1A3v4QYXZcwZiKeEVbFuNkauXgD+8pEZMB8yL4 +h1feIH+aucsAKBz1Ne5fTiTCannlKvLl8xWz5IdzP7gF0LIxggLoMIIC5AIBATCB +1TCBxzELMAkGA1UEBhMCTkwxCzAJBgNVBAgMAk9WMRYwFAYDVQQHDA1Mb2NhbGl0 +eSBOYW1lMSEwHwYDVQQLDBhPcmdhbml6YXRpb25hbCBVbml0IE5hbWUxIDAeBgNV +BAoMF0V4YW1wbGUgQ0EgT3JnYW5pemF0aW9uMR8wHQYDVQQDDBZFeGFtcGxlIFBl +cm1pc3Npb25zIENBMS0wKwYJKoZIhvcNAQkBFh5hdXRob3JpdHlAcGVybWlzc2lv +bnNjYWx0ZC5vcmcCCQDN8gLVC3GhCDANBglghkgBZQMEAgEFAKCB5DAYBgkqhkiG +9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xOTEyMDcxNjAxMjZa +MC8GCSqGSIb3DQEJBDEiBCCAw/IHksMBWVnBQEtBoPLvJ1B+9IvOrQ4OkihJ6q0v +ijB5BgkqhkiG9w0BCQ8xbDBqMAsGCWCGSAFlAwQBKjALBglghkgBZQMEARYwCwYJ +YIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqGSIb3DQMCAgIAgDANBggqhkiG9w0D +AgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIBKDANBgkqhkiG9w0BAQEFAASCAQAd +j3vO63v4bBbNhE0wZ8gWPHFfJsZO4JUu+ZzJ08hO1fku07Q13medyyp1+6jeZWoV +rCqQbG37xL1dx023wsRu+mYPSgEtIx2zBGW8ADk2qEIGAVPUPGUiVXl6+7esAmnP +AFDrt3Qp6nEZIr7iQ6i+4WW3kWM3o9C1ghSz4tVBjP9El5/yrux2mo5DTSeB8QMR +npMNgwgatwAxTwUrBpQj0FE5NUDm21OT1VwlUAGTHz6m5npw92p6qvQxFYufRzWj +XoADdJW0qgfbL00Gvoimi2K21cSUqiYcKU06eQeCkrLXyjif2JlFdKXvODwlydOy +dtwcKpPKVKgBI01+5Imf + +------8F2D5CA80FE8B4509AF031712E008F0E-- + diff --git a/src/security/builtin_plugins/tests/listeners_authentication/etc/Example_Permissions_Alice.p7s b/src/security/builtin_plugins/tests/listeners_authentication/etc/Example_Permissions_Alice.p7s new file mode 100644 index 0000000..1e19a63 --- /dev/null +++ b/src/security/builtin_plugins/tests/listeners_authentication/etc/Example_Permissions_Alice.p7s @@ -0,0 +1,98 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----51AB97062CF028E6EBDDAA31699954BC" + +This is an S/MIME signed message + +------51AB97062CF028E6EBDDAA31699954BC +Content-Type: text/plain + + + + + + /C=NL/ST=OV/L=Locality Name/OU=Organizational Unit Name/O=Example Organization/CN=Alice Example/emailAddress=alice@exampleltd.com + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + * + + + + + * + + + * + + + + + DENY + + + + +------51AB97062CF028E6EBDDAA31699954BC +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIHiwYJKoZIhvcNAQcCoIIHfDCCB3gCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggRnMIIEYzCCA0ugAwIBAgIJAM3yAtULcaEIMA0GCSqGSIb3DQEB +CwUAMIHHMQswCQYDVQQGEwJOTDELMAkGA1UECAwCT1YxFjAUBgNVBAcMDUxvY2Fs +aXR5IE5hbWUxITAfBgNVBAsMGE9yZ2FuaXphdGlvbmFsIFVuaXQgTmFtZTEgMB4G +A1UECgwXRXhhbXBsZSBDQSBPcmdhbml6YXRpb24xHzAdBgNVBAMMFkV4YW1wbGUg +UGVybWlzc2lvbnMgQ0ExLTArBgkqhkiG9w0BCQEWHmF1dGhvcml0eUBwZXJtaXNz +aW9uc2NhbHRkLm9yZzAeFw0xOTAyMTIxMzUyMzJaFw0yOTAyMDkxMzUyMzJaMIHH +MQswCQYDVQQGEwJOTDELMAkGA1UECAwCT1YxFjAUBgNVBAcMDUxvY2FsaXR5IE5h +bWUxITAfBgNVBAsMGE9yZ2FuaXphdGlvbmFsIFVuaXQgTmFtZTEgMB4GA1UECgwX +RXhhbXBsZSBDQSBPcmdhbml6YXRpb24xHzAdBgNVBAMMFkV4YW1wbGUgUGVybWlz +c2lvbnMgQ0ExLTArBgkqhkiG9w0BCQEWHmF1dGhvcml0eUBwZXJtaXNzaW9uc2Nh +bHRkLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKD6nYCszMha +h3xGfJy8f3lowPHIj6zcldVYs5Krg7zXxZn+20lAMHUfgQcWZAauKbCnokYfTvXV +v0j9HCpQ3mRynNTyjLjc7HxAe6kfaJ75PoIoOMMQMEGvPOqRUq0tomVVJvcgzZZk +pwE30E6xvZrlQcrkQY/aOQ0sbje+RN8RKQ9vf6O45Np/0m2K5ohZPlBqg4F539v2 +iXGZczCr9AqAszc/7rOPX1aqZmmRDou0T+Zhx3ZZSAwZYQtr7uvvlUeGmDhNh+8p +LC+1FQPtkKmcVXO8oZWm5N8piOvH3M+v3qhyPtLv30cpl0bDiFl+PN7nZ6InOOtd +ZJVMa2rYCk8CAwEAAaNQME4wHQYDVR0OBBYEFA/CtiP8Z5Fk4aWDIb2j3FPwh9pg +MB8GA1UdIwQYMBaAFA/CtiP8Z5Fk4aWDIb2j3FPwh9pgMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQELBQADggEBACBupRddIR9zYBFLGFTzeiW+H1tRRKz+B3SWnCJH +89ijEdMYlKKLYT0R18lCV0vHnl29bU1CPlkLn+GQkvdfIjKguWEQKTP+GLzoa9TV +zOKAJ8NttCyW3YqriUOUGKqra1Fdt8nvrAyZUF+v/k8pTInmCvwu3l5HrVhkKHER +IbCIohKi/2mk1JZS9reWvZhqLoUIw5IDFlqtBDYOfMaqm8XF01YjEDBM6OuyQzYN +gDFVUZx0At4zzRjGTvqpLTkDYL1A3v4QYXZcwZiKeEVbFuNkauXgD+8pEZMB8yL4 +h1feIH+aucsAKBz1Ne5fTiTCannlKvLl8xWz5IdzP7gF0LIxggLoMIIC5AIBATCB +1TCBxzELMAkGA1UEBhMCTkwxCzAJBgNVBAgMAk9WMRYwFAYDVQQHDA1Mb2NhbGl0 +eSBOYW1lMSEwHwYDVQQLDBhPcmdhbml6YXRpb25hbCBVbml0IE5hbWUxIDAeBgNV +BAoMF0V4YW1wbGUgQ0EgT3JnYW5pemF0aW9uMR8wHQYDVQQDDBZFeGFtcGxlIFBl +cm1pc3Npb25zIENBMS0wKwYJKoZIhvcNAQkBFh5hdXRob3JpdHlAcGVybWlzc2lv +bnNjYWx0ZC5vcmcCCQDN8gLVC3GhCDANBglghkgBZQMEAgEFAKCB5DAYBgkqhkiG +9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xOTEyMDcxNjAxMjZa +MC8GCSqGSIb3DQEJBDEiBCAX5wSM0Og83gWKRmru9iCOm8h85e9oZ7rBebmSbLVN +1TB5BgkqhkiG9w0BCQ8xbDBqMAsGCWCGSAFlAwQBKjALBglghkgBZQMEARYwCwYJ +YIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqGSIb3DQMCAgIAgDANBggqhkiG9w0D +AgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIBKDANBgkqhkiG9w0BAQEFAASCAQAT +QZbljrtQs/FcBUJBYoenquAQ5++twy5LE6A06dASaHFDxSxPsAe0KBl9EWJzE59X +4k73u+4bJZiuLHUPztuXIUt3gEKM72DDT+ET/13dWdM2vtITW6HZ27nvkngE35cc +kdUqkLyeM5dzsSDpr3Ba8epulThlwl7bw9dUd2FUOBCc266da+q1lcChjwfC5GBu +GB7oWODhSAk6L9dici8w5q9ybygBkFJHXTZVtsXQWuNmDtXWB2ury++WQlvtNK0s +aF+dtQlyEx2vvi5tV195vncAt514uHJ9optdEbaIyMo51G53QD0Cq62QhuFusug0 +nz2pgcEZ35JCd4gESMkL + +------51AB97062CF028E6EBDDAA31699954BC-- + diff --git a/src/security/builtin_plugins/tests/listeners_authentication/etc/Example_Permissions_Bob.p7s b/src/security/builtin_plugins/tests/listeners_authentication/etc/Example_Permissions_Bob.p7s new file mode 100644 index 0000000..f5ab923 --- /dev/null +++ b/src/security/builtin_plugins/tests/listeners_authentication/etc/Example_Permissions_Bob.p7s @@ -0,0 +1,98 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----EDFB3CE1089204FED046E2D32968C669" + +This is an S/MIME signed message + +------EDFB3CE1089204FED046E2D32968C669 +Content-Type: text/plain + + + + + + /C=NL/ST=OV/L=Locality Name/OU=Organizational Unit Name/O=Example Organization/CN=Bob Example/emailAddress=bob@exampleltd.com + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + * + + + + + * + + + * + + + + + DENY + + + + +------EDFB3CE1089204FED046E2D32968C669 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIHiwYJKoZIhvcNAQcCoIIHfDCCB3gCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggRnMIIEYzCCA0ugAwIBAgIJAM3yAtULcaEIMA0GCSqGSIb3DQEB +CwUAMIHHMQswCQYDVQQGEwJOTDELMAkGA1UECAwCT1YxFjAUBgNVBAcMDUxvY2Fs +aXR5IE5hbWUxITAfBgNVBAsMGE9yZ2FuaXphdGlvbmFsIFVuaXQgTmFtZTEgMB4G +A1UECgwXRXhhbXBsZSBDQSBPcmdhbml6YXRpb24xHzAdBgNVBAMMFkV4YW1wbGUg +UGVybWlzc2lvbnMgQ0ExLTArBgkqhkiG9w0BCQEWHmF1dGhvcml0eUBwZXJtaXNz +aW9uc2NhbHRkLm9yZzAeFw0xOTAyMTIxMzUyMzJaFw0yOTAyMDkxMzUyMzJaMIHH +MQswCQYDVQQGEwJOTDELMAkGA1UECAwCT1YxFjAUBgNVBAcMDUxvY2FsaXR5IE5h +bWUxITAfBgNVBAsMGE9yZ2FuaXphdGlvbmFsIFVuaXQgTmFtZTEgMB4GA1UECgwX +RXhhbXBsZSBDQSBPcmdhbml6YXRpb24xHzAdBgNVBAMMFkV4YW1wbGUgUGVybWlz +c2lvbnMgQ0ExLTArBgkqhkiG9w0BCQEWHmF1dGhvcml0eUBwZXJtaXNzaW9uc2Nh +bHRkLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKD6nYCszMha +h3xGfJy8f3lowPHIj6zcldVYs5Krg7zXxZn+20lAMHUfgQcWZAauKbCnokYfTvXV +v0j9HCpQ3mRynNTyjLjc7HxAe6kfaJ75PoIoOMMQMEGvPOqRUq0tomVVJvcgzZZk +pwE30E6xvZrlQcrkQY/aOQ0sbje+RN8RKQ9vf6O45Np/0m2K5ohZPlBqg4F539v2 +iXGZczCr9AqAszc/7rOPX1aqZmmRDou0T+Zhx3ZZSAwZYQtr7uvvlUeGmDhNh+8p +LC+1FQPtkKmcVXO8oZWm5N8piOvH3M+v3qhyPtLv30cpl0bDiFl+PN7nZ6InOOtd +ZJVMa2rYCk8CAwEAAaNQME4wHQYDVR0OBBYEFA/CtiP8Z5Fk4aWDIb2j3FPwh9pg +MB8GA1UdIwQYMBaAFA/CtiP8Z5Fk4aWDIb2j3FPwh9pgMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQELBQADggEBACBupRddIR9zYBFLGFTzeiW+H1tRRKz+B3SWnCJH +89ijEdMYlKKLYT0R18lCV0vHnl29bU1CPlkLn+GQkvdfIjKguWEQKTP+GLzoa9TV +zOKAJ8NttCyW3YqriUOUGKqra1Fdt8nvrAyZUF+v/k8pTInmCvwu3l5HrVhkKHER +IbCIohKi/2mk1JZS9reWvZhqLoUIw5IDFlqtBDYOfMaqm8XF01YjEDBM6OuyQzYN +gDFVUZx0At4zzRjGTvqpLTkDYL1A3v4QYXZcwZiKeEVbFuNkauXgD+8pEZMB8yL4 +h1feIH+aucsAKBz1Ne5fTiTCannlKvLl8xWz5IdzP7gF0LIxggLoMIIC5AIBATCB +1TCBxzELMAkGA1UEBhMCTkwxCzAJBgNVBAgMAk9WMRYwFAYDVQQHDA1Mb2NhbGl0 +eSBOYW1lMSEwHwYDVQQLDBhPcmdhbml6YXRpb25hbCBVbml0IE5hbWUxIDAeBgNV +BAoMF0V4YW1wbGUgQ0EgT3JnYW5pemF0aW9uMR8wHQYDVQQDDBZFeGFtcGxlIFBl +cm1pc3Npb25zIENBMS0wKwYJKoZIhvcNAQkBFh5hdXRob3JpdHlAcGVybWlzc2lv +bnNjYWx0ZC5vcmcCCQDN8gLVC3GhCDANBglghkgBZQMEAgEFAKCB5DAYBgkqhkiG +9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xOTEyMDcxNjAxMjZa +MC8GCSqGSIb3DQEJBDEiBCCEqUh7CpMRXpSMDeuCmSMz+I6WXjXpO2HRkCdRSczj +1TB5BgkqhkiG9w0BCQ8xbDBqMAsGCWCGSAFlAwQBKjALBglghkgBZQMEARYwCwYJ +YIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqGSIb3DQMCAgIAgDANBggqhkiG9w0D +AgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIBKDANBgkqhkiG9w0BAQEFAASCAQAL +ExoTydhBE/8GgnqGp39cRVQ0Z1YIc55uACZK1V37R2b8rY4upLA7iHyzCBXQOwCz +mhjHfaNdW8twWru34EvD17RTfk49Lvmge4ceipgmqKwGVyTO57P5xzDaC+2F2KEi ++s6/YWIslixMhlQyuxZsmQDbRWcmQ1FRy7LJ80cctlDA44IviaEfv/u2+sqJgPNL +Z5AHMEv/qceKjtm/Wh7sdFhjfM4ZnfUWFB6Ni/sdNSmO9O3j9OHfpkzMJHxM4B5r +G5pMNDn2xibxwlx41he7mfENIjuk4Z3VDaTCTs++8GyivvvsCZSVimd0iuI1kVmd +JL58DFeKqgEZ358rN9/5 + +------EDFB3CE1089204FED046E2D32968C669-- + diff --git a/src/security/builtin_plugins/tests/listeners_authentication/etc/Identity_CA_Cert.pem b/src/security/builtin_plugins/tests/listeners_authentication/etc/Identity_CA_Cert.pem new file mode 100644 index 0000000..cce5c91 --- /dev/null +++ b/src/security/builtin_plugins/tests/listeners_authentication/etc/Identity_CA_Cert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEOTCCAyGgAwIBAgIJAPq0b61+PT2WMA0GCSqGSIb3DQEBCwUAMIGyMQswCQYD +VQQGEwJOTDELMAkGA1UECAwCT1YxFjAUBgNVBAcMDUxvY2FsaXR5IE5hbWUxITAf +BgNVBAsMGE9yZ2FuaXphdGlvbmFsIFVuaXQgTmFtZTEaMBgGA1UECgwRRXhhbXBs +ZSBTaWduZXIgQ0ExEzARBgNVBAMMCkV4YW1wbGUgQ0ExKjAoBgkqhkiG9w0BCQEW +G2F1dGhvcml0eUBpZGVudGl0eWNhbHRkLm9yZzAeFw0xOTAyMTIxMDIxNTJaFw0y +OTAyMDkxMDIxNTJaMIGyMQswCQYDVQQGEwJOTDELMAkGA1UECAwCT1YxFjAUBgNV +BAcMDUxvY2FsaXR5IE5hbWUxITAfBgNVBAsMGE9yZ2FuaXphdGlvbmFsIFVuaXQg +TmFtZTEaMBgGA1UECgwRRXhhbXBsZSBTaWduZXIgQ0ExEzARBgNVBAMMCkV4YW1w +bGUgQ0ExKjAoBgkqhkiG9w0BCQEWG2F1dGhvcml0eUBpZGVudGl0eWNhbHRkLm9y +ZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKCBJ1r/2AcSHorpA2G2 +WR0CvGHPhhY2x93twW91LCJVOVzO0LuOscZXSkWDtAhyhy1EZN6r+4aLbMku/wVJ +kdjHPD+WSVEZn70LxYSgxiUwXalpa5RQeTkEHll5cSgtE8kSD4/HIxBsbwizeDVV +g8SWpBVb044GM4O3TDbCug9F7GJFzqcbSHQZnHO+3nWu6f21BEU7PZjrFox1NREN +g3H7WmNISx4DOK9bJcWS/i4qJjTxjQPPFmzGvRgO2FfWP+xYb70x/iOeKsML2y+d +XZqL99yzfP1dnpDtBzCTqJJizfuNMD6gvIXyk2PUy3FpAYoI9BvUehdWCP/okikx +5jsCAwEAAaNQME4wHQYDVR0OBBYEFL7LTHLvMsEeUDjMYeW4+DcXn62PMB8GA1Ud +IwQYMBaAFL7LTHLvMsEeUDjMYeW4+DcXn62PMAwGA1UdEwQFMAMBAf8wDQYJKoZI +hvcNAQELBQADggEBAIDJ4g6aVGIVXDSQ5R2yY9I82zsRf3k+yRF/BBkqBP1XXYRA +6lk7Wk4y6+DmL9qbVG/xrkTCC066J8kVblOyfFP1LHAzlNOQE7aU+tyrAufW4fpz +f/Gv8PBQUTQGr8vNqLUuEdoQjzARm8g7L3qeXhIKjiWsWi99ibnm/jTjol1GleIX +RudKSSGyMcB2VgRjCEEIYrkXdkIfrznKcJxzUw3dsGx277dB+4iFLcqf1YDpoRe2 +aSwbtgx+lLZ4KXWtikBSmLSRBq9j2aGtKO08kru0U3jQo6B4Bvzp1KuJCBiktueY +yNRfgh8ggNERYF/SpVr/ivm3RM+mnWd3QpmVolw= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/listeners_authentication/etc/Identity_CA_Private_Key.pem b/src/security/builtin_plugins/tests/listeners_authentication/etc/Identity_CA_Private_Key.pem new file mode 100644 index 0000000..16bfbf7 --- /dev/null +++ b/src/security/builtin_plugins/tests/listeners_authentication/etc/Identity_CA_Private_Key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAoIEnWv/YBxIeiukDYbZZHQK8Yc+GFjbH3e3Bb3UsIlU5XM7Q +u46xxldKRYO0CHKHLURk3qv7hotsyS7/BUmR2Mc8P5ZJURmfvQvFhKDGJTBdqWlr +lFB5OQQeWXlxKC0TyRIPj8cjEGxvCLN4NVWDxJakFVvTjgYzg7dMNsK6D0XsYkXO +pxtIdBmcc77eda7p/bUERTs9mOsWjHU1EQ2DcftaY0hLHgM4r1slxZL+LiomNPGN +A88WbMa9GA7YV9Y/7FhvvTH+I54qwwvbL51dmov33LN8/V2ekO0HMJOokmLN+40w +PqC8hfKTY9TLcWkBigj0G9R6F1YI/+iSKTHmOwIDAQABAoIBAAc5iRH5jjnTQPiz +wGk3kg9SPjSQ6NI7KQf+WcSwm4n4GBrrXE31AF+TMk6qvQHcVeVdvMShLTNDN2Re +7y/Hvf7qCPY7x5UU+DHEQ+HSctjdsnmbuzHz5WEBpHQWmVdboBZe78BjEFr+5oiX +u4N7E/FXbo9fkMhF0y/MomucnE9vnhFsCj/Qz+gqKJDz7n+jY1G9loGJpoZoGllK +s2+HzbY5qVKrrpDzD5FO5i+M/Obk4uwZVDSnFL316SKe9MzdlrH9ochdtsGlver8 +YsYtetqHy4QgE/WZLSgwQoYY7nlKnkAKUnGvTJ8pnmO2FkO9SAQsBIl32rURMQFY +2C7ka5ECgYEAz13hOWwsefCkMTpXOXpeagCACN86Oqel+gV+UYDWnRdwDrUKBhjA +u40+NVaxuJSNKV3mC0N2PxwTuYzQ6BOQgmNzlxv0xyKwkGW/d6F8VunV2mqb3EAL +m9qzN1k08V30RikSMCt1OV5isuUiC4ox3ToboLTibXKnbEFWjT3juM8CgYEAxiW0 ++CvqJQjrjJ/valshCQDF4fYLa2uTJcdDifyU3HVTn06yy0z42tLBhHCv8RY/SBRK +IqR3RDhYJbBgLhG7oBDvoGWUEhdGJ+z6qcw9v1tDj9QD1bQF7RJvuh2JA7mhbFe5 +cIptcDJNRN7PCrjqGksQfy8Gg6ABOGFhz3xZPtUCgYBeFpKio1pq2a0mSPpashM0 +tZVicSbShk7g6q0t/e9ix8eoZKxvp7uLXcLkILnyrjR+mIRQiAOXDv5EKoh/RKFF +CCriXWTrFepXGlONzE/Gf8Lwn36oqMabqNe4PVmwSpkTXH9MK+u8Y/8UfLK92a5W +Wo8+k9RJJMSiceL7oyE4MQKBgQCkVg2bbkCJaraBMPxNxzrEzsFPwNKDyvqFcJhR +TwzfMuehzpF3D2WthvI8t4EUgJEHZNx/ksvf5qMkzv1V+BsWjDVRYC3IO0lSP7c9 +MEld9YE5PmvXx7DKiGnlgC1sy35X7wG7lvNhBDcVkX1BtU9jczJBaW0LqZ6Zdhq7 +DLSv6QKBgQDNZpHEwi2P2LdlTRgbc4IWYjZZJaj+RrG881lgi+v8SI4E8eizlxLw +9HlG1nydvRqtU3T5h8UuqLOlXbfvQ7GOxVO2uJjtjJHZ8KbsFUH5i3UwZ+llyrRW +Y1ydvvE9Hux6I7I3L42J11jphNYKw/YwARkp8/Bc/wzKsGlnh3Oh+w== +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/listeners_authentication/etc/Permissions_CA_Cert.pem b/src/security/builtin_plugins/tests/listeners_authentication/etc/Permissions_CA_Cert.pem new file mode 100644 index 0000000..7420bc4 --- /dev/null +++ b/src/security/builtin_plugins/tests/listeners_authentication/etc/Permissions_CA_Cert.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIJAM3yAtULcaEIMA0GCSqGSIb3DQEBCwUAMIHHMQswCQYD +VQQGEwJOTDELMAkGA1UECAwCT1YxFjAUBgNVBAcMDUxvY2FsaXR5IE5hbWUxITAf +BgNVBAsMGE9yZ2FuaXphdGlvbmFsIFVuaXQgTmFtZTEgMB4GA1UECgwXRXhhbXBs +ZSBDQSBPcmdhbml6YXRpb24xHzAdBgNVBAMMFkV4YW1wbGUgUGVybWlzc2lvbnMg +Q0ExLTArBgkqhkiG9w0BCQEWHmF1dGhvcml0eUBwZXJtaXNzaW9uc2NhbHRkLm9y +ZzAeFw0xOTAyMTIxMzUyMzJaFw0yOTAyMDkxMzUyMzJaMIHHMQswCQYDVQQGEwJO +TDELMAkGA1UECAwCT1YxFjAUBgNVBAcMDUxvY2FsaXR5IE5hbWUxITAfBgNVBAsM +GE9yZ2FuaXphdGlvbmFsIFVuaXQgTmFtZTEgMB4GA1UECgwXRXhhbXBsZSBDQSBP +cmdhbml6YXRpb24xHzAdBgNVBAMMFkV4YW1wbGUgUGVybWlzc2lvbnMgQ0ExLTAr +BgkqhkiG9w0BCQEWHmF1dGhvcml0eUBwZXJtaXNzaW9uc2NhbHRkLm9yZzCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKD6nYCszMhah3xGfJy8f3lowPHI +j6zcldVYs5Krg7zXxZn+20lAMHUfgQcWZAauKbCnokYfTvXVv0j9HCpQ3mRynNTy +jLjc7HxAe6kfaJ75PoIoOMMQMEGvPOqRUq0tomVVJvcgzZZkpwE30E6xvZrlQcrk +QY/aOQ0sbje+RN8RKQ9vf6O45Np/0m2K5ohZPlBqg4F539v2iXGZczCr9AqAszc/ +7rOPX1aqZmmRDou0T+Zhx3ZZSAwZYQtr7uvvlUeGmDhNh+8pLC+1FQPtkKmcVXO8 +oZWm5N8piOvH3M+v3qhyPtLv30cpl0bDiFl+PN7nZ6InOOtdZJVMa2rYCk8CAwEA +AaNQME4wHQYDVR0OBBYEFA/CtiP8Z5Fk4aWDIb2j3FPwh9pgMB8GA1UdIwQYMBaA +FA/CtiP8Z5Fk4aWDIb2j3FPwh9pgMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBACBupRddIR9zYBFLGFTzeiW+H1tRRKz+B3SWnCJH89ijEdMYlKKLYT0R +18lCV0vHnl29bU1CPlkLn+GQkvdfIjKguWEQKTP+GLzoa9TVzOKAJ8NttCyW3Yqr +iUOUGKqra1Fdt8nvrAyZUF+v/k8pTInmCvwu3l5HrVhkKHERIbCIohKi/2mk1JZS +9reWvZhqLoUIw5IDFlqtBDYOfMaqm8XF01YjEDBM6OuyQzYNgDFVUZx0At4zzRjG +TvqpLTkDYL1A3v4QYXZcwZiKeEVbFuNkauXgD+8pEZMB8yL4h1feIH+aucsAKBz1 +Ne5fTiTCannlKvLl8xWz5IdzP7gF0LI= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/listeners_authentication/src/listeners_authentication_utests.c b/src/security/builtin_plugins/tests/listeners_authentication/src/listeners_authentication_utests.c new file mode 100644 index 0000000..fb27369 --- /dev/null +++ b/src/security/builtin_plugins/tests/listeners_authentication/src/listeners_authentication_utests.c @@ -0,0 +1,2076 @@ +/** @file qos_utests.c + * @brief Unit tests for qos APIs + * + */ +#include + +#include "dds/ddsrt/time.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/misc.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/io.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/dds_security_api_authentication.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "config_env.h" + +static const char * ACCESS_PERMISSIONS_TOKEN_ID = "DDS:Access:Permissions:1.0"; +static const char * AUTH_PROTOCOL_CLASS_ID = "DDS:Auth:PKI-DH:1.0"; + +static const char * PROPERTY_IDENTITY_CA = "dds.sec.auth.identity_ca"; +static const char * PROPERTY_PRIVATE_KEY = "dds.sec.auth.private_key"; +static const char * PROPERTY_IDENTITY_CERT = "dds.sec.auth.identity_certificate"; +static const char * PROPERTY_PERMISSIONS_CA = "dds.sec.access.permissions_ca"; +static const char * PROPERTY_PERMISSIONS = "dds.sec.access.permissions"; +static const char * PROPERTY_GOVERNANCE = "dds.sec.access.governance"; + +static const char * PROPERTY_PERMISSIONS_CA_SN = "dds.perm_ca.sn"; +static const char * PROPERTY_PERMISSIONS_CA_ALGO = "dds.perm_ca.algo"; +static const char * PROPERTY_C_ID = "c.id"; +static const char * PROPERTY_C_PERM = "c.perm"; + + +static const char * SUBJECT_NAME_PERMISSIONS_CA = "/C=NL/ST=OV/L=Locality Name/OU=Organizational Unit Name/O=Example Signer CA/CN=Example CA/emailAddress=authority@identitycaltd.org"; +static const char * RSA_2048_ALGORITHM_NAME = "RSA-2048"; + +static const char * PERMISSIONS_CA_CERT_FILE = "Permissions_CA_Cert.pem"; +static const char * ALICE_PERMISSIONS_FILE = "Example_Permissions_Alice.p7s"; +static const char * BOB_PERMISSIONS_FILE = "Example_Permissions_Bob.p7s"; +static const char * ALICE_IDENTITY_CERT_FILE = "Example_Alice_Cert.pem"; +static const char * BOB_IDENTITY_CERT_FILE = "Example_Bob_Cert.pem"; +static const char * AUTH_DSIGN_ALGO_RSA_NAME = "RSASSA-PSS-SHA256"; +static const char * AUTH_KAGREE_ALGO_ECDH_NAME = "ECDH+prime256v1-CEUM"; +static DDS_Security_PermissionsHandle remote_permissions_handle = DDS_SECURITY_HANDLE_NIL; +static dds_security_authentication_listener auth_listener; +static dds_security_access_control_listener access_control_listener; + +#define IDENTITY_CA_FILE "Identity_CA_Cert.pem" +#define IDENTITY_CA_KEY_FILE "Identity_CA_Private_Key.pem" + +static const char *identity_ca =/*Identity_CA_Cert.pem*/ + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEOTCCAyGgAwIBAgIJAPq0b61+PT2WMA0GCSqGSIb3DQEBCwUAMIGyMQswCQYD\n" + "VQQGEwJOTDELMAkGA1UECAwCT1YxFjAUBgNVBAcMDUxvY2FsaXR5IE5hbWUxITAf\n" + "BgNVBAsMGE9yZ2FuaXphdGlvbmFsIFVuaXQgTmFtZTEaMBgGA1UECgwRRXhhbXBs\n" + "ZSBTaWduZXIgQ0ExEzARBgNVBAMMCkV4YW1wbGUgQ0ExKjAoBgkqhkiG9w0BCQEW\n" + "G2F1dGhvcml0eUBpZGVudGl0eWNhbHRkLm9yZzAeFw0xOTAyMTIxMDIxNTJaFw0y\n" + "OTAyMDkxMDIxNTJaMIGyMQswCQYDVQQGEwJOTDELMAkGA1UECAwCT1YxFjAUBgNV\n" + "BAcMDUxvY2FsaXR5IE5hbWUxITAfBgNVBAsMGE9yZ2FuaXphdGlvbmFsIFVuaXQg\n" + "TmFtZTEaMBgGA1UECgwRRXhhbXBsZSBTaWduZXIgQ0ExEzARBgNVBAMMCkV4YW1w\n" + "bGUgQ0ExKjAoBgkqhkiG9w0BCQEWG2F1dGhvcml0eUBpZGVudGl0eWNhbHRkLm9y\n" + "ZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKCBJ1r/2AcSHorpA2G2\n" + "WR0CvGHPhhY2x93twW91LCJVOVzO0LuOscZXSkWDtAhyhy1EZN6r+4aLbMku/wVJ\n" + "kdjHPD+WSVEZn70LxYSgxiUwXalpa5RQeTkEHll5cSgtE8kSD4/HIxBsbwizeDVV\n" + "g8SWpBVb044GM4O3TDbCug9F7GJFzqcbSHQZnHO+3nWu6f21BEU7PZjrFox1NREN\n" + "g3H7WmNISx4DOK9bJcWS/i4qJjTxjQPPFmzGvRgO2FfWP+xYb70x/iOeKsML2y+d\n" + "XZqL99yzfP1dnpDtBzCTqJJizfuNMD6gvIXyk2PUy3FpAYoI9BvUehdWCP/okikx\n" + "5jsCAwEAAaNQME4wHQYDVR0OBBYEFL7LTHLvMsEeUDjMYeW4+DcXn62PMB8GA1Ud\n" + "IwQYMBaAFL7LTHLvMsEeUDjMYeW4+DcXn62PMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n" + "hvcNAQELBQADggEBAIDJ4g6aVGIVXDSQ5R2yY9I82zsRf3k+yRF/BBkqBP1XXYRA\n" + "6lk7Wk4y6+DmL9qbVG/xrkTCC066J8kVblOyfFP1LHAzlNOQE7aU+tyrAufW4fpz\n" + "f/Gv8PBQUTQGr8vNqLUuEdoQjzARm8g7L3qeXhIKjiWsWi99ibnm/jTjol1GleIX\n" + "RudKSSGyMcB2VgRjCEEIYrkXdkIfrznKcJxzUw3dsGx277dB+4iFLcqf1YDpoRe2\n" + "aSwbtgx+lLZ4KXWtikBSmLSRBq9j2aGtKO08kru0U3jQo6B4Bvzp1KuJCBiktueY\n" + "yNRfgh8ggNERYF/SpVr/ivm3RM+mnWd3QpmVolw=\n" + "-----END CERTIFICATE-----\n"; + +static const char *alice_private_key = + "data:,-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEpAIBAAKCAQEA0Vn9YYllmrC/VVkxWFq6TzsmWn/niMydsE0hhm4Eam00gw3v\n" + "M4xScvBexI0td6tbStnWKz8vBiSVtWY1GDX8ICCBDufJcNIypu9L3DsjBoVTpcjx\n" + "XmfSpcxsepNaS7IqFPoRd+J+tzrl5qUR0Q52ObI02csp6CwecL8CvfXfc02U+tpP\n" + "b7iSsT/AcCeAAc10vdSXtnfcOGVLwy+D527kNr5r2VhE2FYdWbrGSOj8hw5eUfRs\n" + "KpnWlermWy1wzYfmMqkIII1hhY1sRDmMDrLpFeiYkf9B/7HQF+R2tFFFok1dYVpg\n" + "ZiZUNkONQnDQueThypzu3XB/PwHExILZnBwEtwIDAQABAoIBAHEVxCoQtuKlgOUQ\n" + "hfgtIiC0WdZe6unZZYCbWXWtLhNzI/964nAc51iRAQ/5Fstis7CuFONNgRA3aOsQ\n" + "57NJTgToqe4sRIL9+EB2WKsBAr19/Z46+i69tGq9DwfzWr4y4kpsfk0c+sftN8yr\n" + "9ADSaAhoe+X9uYhhdJwAgfGsw+Qa1BLM5jEexjcLwy1kqXwWKNHrPWU7NW40bPhV\n" + "Ne/UguklSp43sKoB1esTgRZe+OlQDCsQoXpyjtPYcKzF3Ion6e5rT8xQ1IkAtLTf\n" + "QJJTGMJGCguXxuDo2VRaa5pwbdRAamp63wD0IAPAf+ClCz4JLwOnOYsgSCZoY3l3\n" + "3GxWDAkCgYEA/scs7Ft50QOicnJ/DoCjxmpjba0hiqxbz0qAdCyl1llogUKuyCS7\n" + "sxQQvVTt6jk3gP0UYa3FJREToIGZuqaEu6qdY4GI61woNN5hXbkJC6G3FXI/VB8v\n" + "Actkas0kp6J8YWsmTqnsihE5Yii0WCBn+AnIpoU3S2N9WT7U8eA6B7sCgYEA0lsJ\n" + "xqB6NCkKbr+E+V0CGp+S+7zH5dxZtAhDPSKwy2kCYWtDlSVhAzXabTIzF2SW9tJQ\n" + "JV3FhRfiCWTBrBm/I7AmNbNtXnrexYyXPVBhN6uqzYCB8fcLy+HPNZYF3KtQtU3c\n" + "WxAyO6ZxSLgtcP3UB6J8Ac6CYB25cRWNsnrvETUCgYA1HpHfNbNQQNG9yuFyxJ9g\n" + "3w2b8Fzt7MG3lnDxx91Ls5h2WtDWKdJ4o9ZZozt3ejZ4TkvRkclo0QamkF7c65sB\n" + "BbGK7Zb+e1hmrXbfc5TPOAhUEF3jzByg4ycsnVjnGpmUNiLmg8ctginUrWfsd9U1\n" + "gdSz41KEBVo9ITyEsZtnwQKBgQCOgIfd3CcNIORlZC8D8wMS4BllmlzdFepa8OIE\n" + "D3UvR2MKdezho+HVl+zx3nkIFufCK3WJ6r19TVGeRXiCSyrWVWV9KaEkyR4TPAvU\n" + "yJgja5MZBj6BmXePVdjWl1w/Qns5Z5aoxg8Ro87IkaSPEBVMWsGhQ7HExT40IoLM\n" + "b0V3JQKBgQCnZRrzaY9xOy72rtyacWjQB2QxnmkZgwDUq0iQwU/EdP72fPV/TtG8\n" + "PxQqKVPM57XO7qDbyKBt9L3vvmkiC0bABlcMN7UX9H5cHGhnJn6+6muitJlxmtvU\n" + "IiwlYmN2hcA52Ft9cRVC8+8W6Knx019vBnJozjhzhy7wxwqggmxsxg==\n" + "-----END RSA PRIVATE KEY-----\n"; + +static const char *bob_private_key = + "-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEogIBAAKCAQEA5Piv5VnOqg9vAWXGrdxH2Ax1svypJNVmNUlM95qGQloeJQPk\n" + "jSzAEHIBVYAE0eU5gHL3l9EI2mw/bVLsT/REXipj9STPN9NYOVNH2yeD8+KHWNXX\n" + "miTYJ5YjHP9GHDdKiZ52dn7BYktqUlghlxuY0pjWrqhnNkcJep7YZq4QTbCQcyUV\n" + "l+9v+lE6/DuSG5K1KNRCQmmnRVjdWmGQogrW8eZ1xNFwHJuZYgKP/q7ieQSYI+YR\n" + "Mrt1pScjj6FjdL5OMYShrBO7OBYrwDjMnpmox9omF+1S1Gmi1y03b3m1COKX4lID\n" + "Qpc7gvpwq02ZozEX+kfIs0Ua8EKbVgi23V/2OQIDAQABAoIBACXLry1Kr8R+m7I9\n" + "XJhiXjGZjOworLr5xs9Q9DWC+lqFiahOhjGPi3yrdPDqGuGS1vUPBTO4O5/icm3X\n" + "XE6uYYKxuKJEmzf52PxNdPUGBtABOpo9YkN9hXizXcRxlt8deV5SG/ffYIibLke9\n" + "aH4K/iT1OarG/ZKGE1h8U/hPDz3jcVGpqhwn7K4RtRJO7brYKw1jDJwH64g5gDZ7\n" + "Y2zcj5zh1JsnOYPx/1HWxDDIbBN9RbOTyKZIMP9OwglbS5RhIblTgM8zT8ZEHQ1s\n" + "h5dF1jt5pKtcqQelYbfACsTmVCvtJR9Uz98mYE/xpwvJTXbzeycmEccdfuWWFkFB\n" + "xzQroKECgYEA/VeD9T3/zJ9uls0DBuj+LBu+7mL/RrPuoJrqBIuXvIvddYgmvEkf\n" + "IhB7OLgLeMv5KvHRn8XWoEcPGoglfbY4jqIML855gFolyXSNJlbSiOPit8Ea9dKi\n" + "60fHhaa1U+E2xdDOeUilQVCEgnnqSBls1kGqB+81os5GVgo7MzW1+Y0CgYEA51+2\n" + "PYKLC5KU8r/bWlwjF2DmVJq6tD3O8SonqKsPv9MwGz0AimLO+iNtvEkh2rLVidtK\n" + "oP0tvIgsu70xqgX4wRBpZB+rk5IS8y3dCVf6TGVFYK9La5/L5BHLAzbf5jybRzH7\n" + "lT3O94oE7w7gkUiexSM37Wp8FoQG4EPl7MXXBl0CgYBDLE5H232U4v0urQNNdL/Y\n" + "MC8rBELNm239VbYRKHY+PxOkU0p6CCViId6aRmp8SBE0KtQ7OfjTnKPLlCfksklC\n" + "wILctjGPL9fvF6FJdiHyvAHkWSZt4cDjA7BKps5ThFbCkr/8dp+itte7xNmy7lLm\n" + "aJjN68Zb+be6npHd3TL4DQKBgBxHXHTEIc52SfIpdNvkav2OgFhS2QLykvpy1ooM\n" + "7k3ZuAV8PTaswPNdpSngHl0mgmbpAIQQrahfVGhVxV4sgKzIHrl4DXZp4hsKvftI\n" + "X3U643Hfuu4ah8cGTbPE3zS6r5fSChfBiCxFGDlHrjbTk2Qw28MOwr/Vvyll4xI/\n" + "U/qZAoGARuIs5CqcL3NTLyXQGCa3OIeUoqlpMHyy9niJb/S4z6ew6BvI2/uuI//j\n" + "zyZyRdexTF7rOIFDMqsCz7EpJDO9jjwTeKGZ1n25kFJS2AXHhFIU9mdYF9rZ9yuE\n" + "yLB7ISyuiPNMhsOOHMHWWTKiqmQdGBc/HTCKRA1Pu34Bcem55PA=\n" + "-----END RSA PRIVATE KEY-----\n"; + +static const char *alice_csr = + "-----BEGIN CERTIFICATE REQUEST-----\n" + "MIIC9zCCAd8CAQAwgbExCzAJBgNVBAYTAk5MMQswCQYDVQQIDAJPVjEWMBQGA1UE\n" + "BwwNTG9jYWxpdHkgTmFtZTEhMB8GA1UECwwYT3JnYW5pemF0aW9uYWwgVW5pdCBO\n" + "YW1lMR0wGwYDVQQKDBRFeGFtcGxlIE9yZ2FuaXphdGlvbjEWMBQGA1UEAwwNQWxp\n" + "Y2UgRXhhbXBsZTEjMCEGCSqGSIb3DQEJARYUYWxpY2VAZXhhbXBsZWx0ZC5jb20w\n" + "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRWf1hiWWasL9VWTFYWrpP\n" + "OyZaf+eIzJ2wTSGGbgRqbTSDDe8zjFJy8F7EjS13q1tK2dYrPy8GJJW1ZjUYNfwg\n" + "IIEO58lw0jKm70vcOyMGhVOlyPFeZ9KlzGx6k1pLsioU+hF34n63OuXmpRHRDnY5\n" + "sjTZyynoLB5wvwK99d9zTZT62k9vuJKxP8BwJ4ABzXS91Je2d9w4ZUvDL4PnbuQ2\n" + "vmvZWETYVh1ZusZI6PyHDl5R9GwqmdaV6uZbLXDNh+YyqQggjWGFjWxEOYwOsukV\n" + "6JiR/0H/sdAX5Ha0UUWiTV1hWmBmJlQ2Q41CcNC55OHKnO7dcH8/AcTEgtmcHAS3\n" + "AgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAOqzDicnVFXBhsfRI/Gcmk0kyKAjg\n" + "UAfADqDT7EyqX31O4C+Flj+G++p4/Yo0W8yP01nSMOF5yB76Eep+hXuLldfL1aKs\n" + "krnZgIrCXyUSb5pVYHrbhI76eet6TMD8P9gj0okPLOfzyTHrQz9wCAv9FfiNl2y+\n" + "cK/meQPAByyxSiyW41owlHaMkSgIL/xULJHjR07QRCiKIAY3/mwUQ5I3k4qKibzQ\n" + "eV4Cus2SEqqXhNsFwZPWQZQmZOXLcEX7g9OsC4iVyGOunUwZdv8BRVThQk+5rGWk\n" + "dHjeWYmS7pWc8EjLnaSairQiw9tmZ0SQcNc7DjnPdkBU78MHxMW54sKBrw==\n" + "-----END CERTIFICATE REQUEST-----\n"; + + +static const char *bob_csr = + "-----BEGIN CERTIFICATE REQUEST-----\n" + "MIIC8zCCAdsCAQAwga0xCzAJBgNVBAYTAk5MMQswCQYDVQQIDAJPVjEWMBQGA1UE\n" + "BwwNTG9jYWxpdHkgTmFtZTEhMB8GA1UECwwYT3JnYW5pemF0aW9uYWwgVW5pdCBO\n" + "YW1lMR0wGwYDVQQKDBRFeGFtcGxlIE9yZ2FuaXphdGlvbjEUMBIGA1UEAwwLQm9i\n" + "IEV4YW1wbGUxITAfBgkqhkiG9w0BCQEWEmJvYkBleGFtcGxlbHRkLmNvbTCCASIw\n" + "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOT4r+VZzqoPbwFlxq3cR9gMdbL8\n" + "qSTVZjVJTPeahkJaHiUD5I0swBByAVWABNHlOYBy95fRCNpsP21S7E/0RF4qY/Uk\n" + "zzfTWDlTR9sng/Pih1jV15ok2CeWIxz/Rhw3SomednZ+wWJLalJYIZcbmNKY1q6o\n" + "ZzZHCXqe2GauEE2wkHMlFZfvb/pROvw7khuStSjUQkJpp0VY3VphkKIK1vHmdcTR\n" + "cBybmWICj/6u4nkEmCPmETK7daUnI4+hY3S+TjGEoawTuzgWK8A4zJ6ZqMfaJhft\n" + "UtRpotctN295tQjil+JSA0KXO4L6cKtNmaMxF/pHyLNFGvBCm1YItt1f9jkCAwEA\n" + "AaAAMA0GCSqGSIb3DQEBCwUAA4IBAQBr85eN2h2q1dLfSeaJHmyVqmwdj2igMOcK\n" + "4RllC2LZ1aorfCvMSb5VzAUbVDFwKJOCfM5vk4hXmt9Uxxmr5qHpnBWi5XGoevuf\n" + "iQ+hdZqS9HIn1/vzNyX6OlCJwVd4qo42RLJFnxyKYnFtZrhA/kdB33Rf+UyRxfoB\n" + "/Su7pUUR+iIMZeu/C3LT3cZy5phqaWzOsw83m3Hap/UzTt5WAhynRfaYRdXuwACU\n" + "QscNSTJsYUfSlynzxY2GHgOw3N34x5pLlVGdOBoG4BjjdZVTeyPc/KgpkUYFY3mD\n" + "jDnSobyp5xr4wcR4RHJCUxCd3/bAAmqKwXY+GnRvOrdKG35Eii0Z\n" + "-----END CERTIFICATE REQUEST-----\n"; + + +static char *bob_identity_cert = NULL; + +typedef enum { + HANDSHAKE_REQUEST, + HANDSHAKE_REPLY, + HANDSHAKE_FINAL +} HandshakeStep_t; + + +struct octet_seq { + unsigned char *data; + uint32_t length; +}; + +static struct plugins_hdl *plugins = NULL; +static dds_security_authentication *auth = NULL; +static dds_security_access_control *access_control = NULL; +static DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_IdentityHandle remote_identity_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_IdentityHandle remote_identity_handle2 = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_PermissionsHandle local_permissions_handle = DDS_SECURITY_HANDLE_NIL; +static char *path_to_etc_dir = NULL; +static char *g_path_build_dir = NULL; +static DDS_Security_IdentityHandle identity_handle_for_callback1=DDS_SECURITY_HANDLE_NIL; +static DDS_Security_IdentityHandle identity_handle_for_callback2=DDS_SECURITY_HANDLE_NIL; +static dds_time_t local_expiry_date; +static dds_time_t remote_expiry_date; + +#define HANDSHAKE_SIGNATURE_SIZE 6 + +#if DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN +static unsigned bswap4u (unsigned x) +{ + return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24); +} +#define toBE4u(x) bswap4u (x) +#define fromBE4u(x) bswap4u (x) +#else +#define toBE4u(x) (x) +#define fromBE4u(x) (x) +#endif + +static const char * PROPERTY_CERT_SUBJECT_NAME = "dds.cert.sn"; +static const char * PROPERTY_CERT_ALGORITHM = "dds.cert.algo"; +static const char * PROPERTY_CA_SUBJECT_NAME = "dds.ca.sn"; +static const char * PROPERTY_CA_ALGORITHM = "dds.ca.aglo"; + +static const char * AUTH_REQUEST_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+AuthReq"; +static const char * AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME = "future_challenge"; + +static const char * AUTH_HANDSHAKE_REQUEST_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+Req"; +static const char * AUTH_HANDSHAKE_REPLY_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+Reply"; +static const char * AUTH_HANDSHAKE_FINAL_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+Final"; +static DDS_Security_AuthRequestMessageToken g_local_auth_request_token = DDS_SECURITY_TOKEN_INIT; +static DDS_Security_AuthRequestMessageToken g_remote_auth_request_token = DDS_SECURITY_TOKEN_INIT; +static const DDS_Security_BinaryProperty_t *challenge1_predefined_glb = NULL; +static const DDS_Security_BinaryProperty_t *challenge2_predefined_glb = NULL; +static DDS_Security_OctetSeq serialized_participant_data = DDS_SECURITY_SEQUENCE_INIT; +static DDS_Security_ParticipantBuiltinTopicData *remote_participant_data1 = NULL; +static DDS_Security_ParticipantBuiltinTopicData *remote_participant_data2 = NULL; +static DDS_Security_ParticipantBuiltinTopicData *remote_participant_data3 = NULL; +static DDS_Security_GUID_t candidate_participant_guid; +static DDS_Security_GUID_t remote_participant_guid1; +static DDS_Security_GUID_t remote_participant_guid2; + +static EVP_PKEY *dh_modp_key = NULL; +static EVP_PKEY *dh_ecdh_key = NULL; +static struct octet_seq dh_modp_pub_key = {NULL, 0}; +static struct octet_seq dh_ecdh_pub_key = {NULL, 0}; +static struct octet_seq invalid_dh_pub_key = {NULL, 0}; + + +static void +dds_security_property_init( + DDS_Security_PropertySeq *seq, + DDS_Security_unsigned_long size) +{ + seq->_length = size; + seq->_maximum = size; + seq->_buffer = ddsrt_malloc(size * sizeof(DDS_Security_Property_t)); + memset(seq->_buffer, 0, size * sizeof(DDS_Security_Property_t)); +} + +static void +dds_security_property_deinit( + DDS_Security_PropertySeq *seq) +{ + uint32_t i; + + for (i = 0; i < seq->_length; i++) { + ddsrt_free(seq->_buffer[i].name); + ddsrt_free(seq->_buffer[i].value); + } + ddsrt_free(seq->_buffer); +} + +static void +reset_exception( + DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + + +static dds_time_t +get_certificate_expiry( + /*_In_*/ X509 *cert) +{ + dds_time_t expiry = DDS_TIME_INVALID; + ASN1_TIME *ans1; + + assert(cert); + + ans1 = X509_get_notAfter(cert); + if (ans1 != NULL) { + int days; + int seconds; + if (ASN1_TIME_diff(&days, &seconds, NULL, ans1) != 0) { + static const dds_duration_t secs_per_day = 86400; + dds_duration_t delta = DDS_SECS(((dds_duration_t)seconds + ((dds_duration_t)days * secs_per_day))); + expiry = dds_time() + delta; + { + BIO *b; + b = BIO_new_fp(stdout, BIO_NOCLOSE); + BIO_printf(b, "[asn1time] "); + ASN1_TIME_print(b, ans1); + BIO_printf(b, "\n"); + BIO_free(b); + } + } + } + + return expiry; +} + + +/* Generate a CA-signed certificate from CSR (Certificate Signing Request) */ +static DDS_Security_boolean create_certificate_from_csr(const char* csr, long valid_secs, + const char* outfile, dds_time_t *expiry) +{ + + ASN1_INTEGER *aserial = NULL; + EVP_PKEY *ca_privkey, *req_pubkey; + EVP_MD const *digest = NULL; + X509 *newcert, *cacert; + X509_NAME *name; + X509V3_CTX ctx; + BIO *fp; + BIO *reqbio = NULL; + BIO *outbio = NULL; + X509_REQ *certreq = NULL; + char *identity_ca_cert_file; + char *identity_ca_key_file; + char* certificate_file; + + outbio = BIO_new(BIO_s_file()); + + /* ---------------------------------------------------------- * + * Load the request data in a BIO, then in a x509_REQ struct. * + * ---------------------------------------------------------- */ + reqbio = BIO_new_mem_buf(csr, -1); + + if (!(certreq = PEM_read_bio_X509_REQ(reqbio, NULL, NULL, NULL))) { + BIO_printf(outbio, "Error can't read X509 request data into memory\n"); + return false; + } + + /* -------------------------------------------------------- * + * Load the signing CA Certificate file * + * ---------------------------------------------------------*/ + + ddsrt_asprintf(&identity_ca_cert_file, "%s%s", path_to_etc_dir, IDENTITY_CA_FILE); + + if (!(fp = BIO_new_file(identity_ca_cert_file, "r"))) { + BIO_printf(outbio, "Error reading CA cert file\n"); + return false; + } + + if (!(cacert = PEM_read_bio_X509(fp, NULL, NULL, NULL))) { + BIO_printf(outbio, "Error loading CA cert into memory\n"); + return false; + } + + BIO_free(fp); + + /* -------------------------------------------------------- * + * Import CA private key file for signing * + * ---------------------------------------------------------*/ + + ddsrt_asprintf(&identity_ca_key_file, "%s%s", path_to_etc_dir, IDENTITY_CA_KEY_FILE); + + if (!(fp = BIO_new_file(identity_ca_key_file, "r"))) { + BIO_printf(outbio, "Error reading CA private key file\n"); + return false; + } + + if (!(ca_privkey = PEM_read_bio_PrivateKey(fp, NULL, NULL, NULL))) { + BIO_printf(outbio, "Error importing key content from file\n"); + return false; + } + + BIO_free(fp); + + /* --------------------------------------------------------- * + * Build Certificate with data from request * + * ----------------------------------------------------------*/ + if (!(newcert = X509_new())) { + BIO_printf(outbio, "Error creating new X509 object\n"); + return false; + } + + if (X509_set_version(newcert, 2) != 1) { + BIO_printf(outbio, "Error setting certificate version\n"); + return false; + } + + /* --------------------------------------------------------- * + * set the certificate serial number here * + * If there is a problem, the value defaults to '0' * + * ----------------------------------------------------------*/ + aserial = ASN1_INTEGER_new(); + ASN1_INTEGER_set(aserial, 0); + if (!X509_set_serialNumber(newcert, aserial)) { + BIO_printf(outbio, "Error setting serial number of the certificate\n"); + return false; + } + + /* --------------------------------------------------------- * + * Extract the subject name from the request * + * ----------------------------------------------------------*/ + if (!(name = X509_REQ_get_subject_name(certreq))) + BIO_printf(outbio, "Error getting subject from cert request\n"); + + /* --------------------------------------------------------- * + * Set the new certificate subject name * + * ----------------------------------------------------------*/ + if (X509_set_subject_name(newcert, name) != 1) { + BIO_printf(outbio, "Error setting subject name of certificate\n"); + return false; + } + + /* --------------------------------------------------------- * + * Extract the subject name from the signing CA cert * + * ----------------------------------------------------------*/ + if (!(name = X509_get_subject_name(cacert))) { + BIO_printf(outbio, "Error getting subject from CA certificate\n"); + return false; + } + + /* --------------------------------------------------------- * + * Set the new certificate issuer name * + * ----------------------------------------------------------*/ + if (X509_set_issuer_name(newcert, name) != 1) { + BIO_printf(outbio, "Error setting issuer name of certificate\n"); + return false; + } + + /* --------------------------------------------------------- * + * Extract the public key data from the request * + * ----------------------------------------------------------*/ + if (!(req_pubkey = X509_REQ_get_pubkey(certreq))) { + BIO_printf(outbio, "Error unpacking public key from request\n"); + return false; + } + + /* --------------------------------------------------------- * + * Optionally: Use the public key to verify the signature * + * ----------------------------------------------------------*/ + if (X509_REQ_verify(certreq, req_pubkey) != 1) { + BIO_printf(outbio, "Error verifying signature on request\n"); + return false; + } + + /* --------------------------------------------------------- * + * Set the new certificate public key * + * ----------------------------------------------------------*/ + if (X509_set_pubkey(newcert, req_pubkey) != 1) { + BIO_printf(outbio, "Error setting public key of certificate\n"); + return false; + } + + /* ---------------------------------------------------------- * + * Set X509V3 start date (now) and expiration date (+365 days)* + * -----------------------------------------------------------*/ + if (!(X509_gmtime_adj(X509_get_notBefore(newcert), -10))) { + BIO_printf(outbio, "Error setting start time\n"); + return false; + } + + if (!(X509_gmtime_adj(X509_get_notAfter(newcert), valid_secs))) { + BIO_printf(outbio, "Error setting expiration time\n"); + return false; + } + + /* ----------------------------------------------------------- * + * Add X509V3 extensions * + * ------------------------------------------------------------*/ + X509V3_set_ctx(&ctx, cacert, newcert, NULL, NULL, 0); + + /* ----------------------------------------------------------- * + * Set digest type, sign new certificate with CA's private key * + * ------------------------------------------------------------*/ + digest = EVP_sha256(); + + if (!X509_sign(newcert, ca_privkey, digest)) { + BIO_printf(outbio, "Error signing the new certificate\n"); + return false; + } + + /* ------------------------------------------------------------ * + * write the certificate to file * + * -------------------------------------------------------------*/ + ddsrt_asprintf(&certificate_file, "%s%s", g_path_build_dir, outfile); + + if (!(fp = BIO_new_file(certificate_file, "w"))) { + BIO_printf(outbio, "Error opening certificate file for write\n"); + return false; + } + if (!PEM_write_bio_X509( fp, newcert)) { + BIO_printf(outbio, "Error writing the signed certificate\n"); + return false; + } + BIO_free(fp); + + *expiry = get_certificate_expiry( newcert ); + + EVP_PKEY_free(req_pubkey); + EVP_PKEY_free(ca_privkey); + X509_REQ_free(certreq); + ASN1_INTEGER_free( aserial ); + X509_free(newcert); + X509_free(cacert); + BIO_free_all(reqbio); + BIO_free_all(outbio); + ddsrt_free(certificate_file); + ddsrt_free( identity_ca_cert_file ); + ddsrt_free( identity_ca_key_file ); + return true; +} + +/* fills the participant properties and return identity cert expiry */ +static void +fill_participant_qos( + DDS_Security_Qos *qos, + long validity_duration, + const char *governance_filename, + dds_time_t *identity_expiry) +{ + char *permission_uri; + char *governance_uri; + char *permissions_ca_cert_file; + char *permissions_ca_uri; + char *identity_file; + char *identity_uri; + char *permissions_file; + + create_certificate_from_csr( alice_csr, validity_duration , ALICE_IDENTITY_CERT_FILE, identity_expiry); + + /*permissions ca cert*/ + ddsrt_asprintf(&permissions_ca_cert_file, "%s%s", path_to_etc_dir, PERMISSIONS_CA_CERT_FILE); + + ddsrt_asprintf(&permissions_ca_uri, "file:%s", permissions_ca_cert_file); + + /*Alice Identity*/ + ddsrt_asprintf(&identity_file, "%s%s", g_path_build_dir, ALICE_IDENTITY_CERT_FILE); + + ddsrt_asprintf(&identity_uri, "file:%s", identity_file); + + /*Alice Permissions */ + ddsrt_asprintf(&permissions_file, "%s%s", path_to_etc_dir, ALICE_PERMISSIONS_FILE); + + ddsrt_asprintf(&permission_uri, "file:%s", permissions_file); + + ddsrt_asprintf(&governance_uri, "file:%s%s", path_to_etc_dir, governance_filename); + + memset(qos, 0, sizeof(*qos)); + dds_security_property_init(&qos->property.value, 6); + qos->property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + qos->property.value._buffer[0].value = ddsrt_strdup(identity_uri); + qos->property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + qos->property.value._buffer[1].value = ddsrt_strdup(identity_ca); + qos->property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + qos->property.value._buffer[2].value = ddsrt_strdup(alice_private_key); + qos->property.value._buffer[3].name = ddsrt_strdup(PROPERTY_PERMISSIONS_CA); + qos->property.value._buffer[3].value = ddsrt_strdup(permissions_ca_uri); + qos->property.value._buffer[4].name = ddsrt_strdup(PROPERTY_PERMISSIONS); + qos->property.value._buffer[4].value = ddsrt_strdup(permission_uri); + qos->property.value._buffer[5].name = ddsrt_strdup(PROPERTY_GOVERNANCE); + qos->property.value._buffer[5].value = ddsrt_strdup(governance_uri); + + ddsrt_free(permission_uri); + ddsrt_free(governance_uri); + ddsrt_free( permissions_ca_cert_file ); + ddsrt_free( permissions_file ); + ddsrt_free ( identity_file ); + ddsrt_free( identity_uri ); + ddsrt_free( permissions_ca_uri ); + + +} + +static void +fill_permissions_token( + DDS_Security_PermissionsToken *token) +{ + memset(token, 0, sizeof(DDS_Security_PermissionsToken)); + + token->class_id = ddsrt_strdup(ACCESS_PERMISSIONS_TOKEN_ID); + token->properties._length = token->properties._maximum = 2; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(2); + + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_PERMISSIONS_CA_SN); + token->properties._buffer[0].value = ddsrt_strdup(SUBJECT_NAME_PERMISSIONS_CA); + + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_PERMISSIONS_CA_ALGO); + token->properties._buffer[1].value = ddsrt_strdup(RSA_2048_ALGORITHM_NAME); +} + + +static int +fill_peer_credential_token( + DDS_Security_AuthenticatedPeerCredentialToken *token) +{ + int result = 1; + char *permission_data; + char *permissions_ca_cert_file; + char *permissions_file; + + + /*permissions ca cert*/ + ddsrt_asprintf(&permissions_ca_cert_file, "%s%s", path_to_etc_dir, PERMISSIONS_CA_CERT_FILE); + + /*permissions ca key*/ + ddsrt_asprintf(&permissions_file, "%s%s", path_to_etc_dir, BOB_PERMISSIONS_FILE); + + + memset(token, 0, sizeof(DDS_Security_AuthenticatedPeerCredentialToken)); + + permission_data = load_file_contents(permissions_file); + + if (permission_data) { + token->class_id = ddsrt_strdup(AUTH_PROTOCOL_CLASS_ID); + token->properties._length = token->properties._maximum = 2; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(2); + + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_C_ID); + token->properties._buffer[0].value = ddsrt_strdup(&bob_identity_cert[0]); + + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_C_PERM); + token->properties._buffer[1].value = permission_data; + } else { + ddsrt_free(permission_data); + result = 0; + } + + ddsrt_free( permissions_ca_cert_file ); + ddsrt_free( permissions_file ); + return result; +} + + +static void +serializer_participant_data( + DDS_Security_ParticipantBuiltinTopicData *pdata, + unsigned char **buffer, + size_t *size) +{ + DDS_Security_Serializer serializer; + serializer = DDS_Security_Serializer_new(1024, 1024); + + DDS_Security_Serialize_ParticipantBuiltinTopicData(serializer, pdata); + DDS_Security_Serializer_buffer(serializer, buffer, size); + DDS_Security_Serializer_free(serializer); +} + +static void +initialize_identity_token( + DDS_Security_IdentityToken *token, + const char *certAlgo, + const char *caAlgo) +{ + memset(token, 0, sizeof(*token)); + + token->class_id = ddsrt_strdup(AUTH_PROTOCOL_CLASS_ID); + token->properties._maximum = 4; + token->properties._length = 4; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(4); + + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_CERT_SUBJECT_NAME); + token->properties._buffer[0].value = ddsrt_strdup("/C=NL/ST=OV/L=Locality Name/OU=Organizational Unit Name/O=Example Organization/CN=Bob Example/emailAddress=bob@exampleltd.com"); + token->properties._buffer[0].propagate = true; + + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_CERT_ALGORITHM); + token->properties._buffer[1].value = ddsrt_strdup(certAlgo); + token->properties._buffer[1].propagate = true; + + token->properties._buffer[2].name = ddsrt_strdup(PROPERTY_CA_SUBJECT_NAME); + token->properties._buffer[2].value = ddsrt_strdup("/C=NL/ST=OV/L=Locality Name/OU=Organizational Unit Name/O=Example Signer CA/CN=Example CA/emailAddress=authority@identitycaltd.org"); + token->properties._buffer[2].propagate = true; + + token->properties._buffer[3].name = ddsrt_strdup(PROPERTY_CA_ALGORITHM); + token->properties._buffer[3].value = ddsrt_strdup(caAlgo); + token->properties._buffer[3].propagate = true; +} + +static DDS_Security_long +validate_local_identity_and_permissions( uint32_t identity_expiry_duration, dds_time_t *identity_expiry ) +{ + DDS_Security_long res = DDS_SECURITY_ERR_OK_CODE; + DDS_Security_ValidationResult_t result; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb}; + DDS_Security_EntityId_t entityId = {{0xb0,0xb1,0xb2},0x1}; + DDS_Security_GUID_t local_participant_guid; + DDS_Security_ParticipantBuiltinTopicData *local_participant_data; + unsigned char *sdata; + size_t sz; + + memset(&local_participant_guid, 0, sizeof(local_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, identity_expiry_duration, "Example_Governance.p7s", identity_expiry ); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &local_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + res = DDS_SECURITY_ERR_UNDEFINED_CODE; + printf("validate_local_identity_failed: (%d) %s\n", (int)exception.code, exception.message ? exception.message : "Error message missing"); + } + + reset_exception(&exception); + + if (res == 0) { + local_permissions_handle = access_control->validate_local_permissions( + access_control, + auth, + local_identity_handle, + 0, + &participant_qos, + &exception); + + if (local_permissions_handle == DDS_SECURITY_HANDLE_NIL) { + printf("validate_local_permissions_failed: (%d) %s\n", (int)exception.code, exception.message ? exception.message : "Error message missing"); + if (exception.code == DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_CODE) { + /* This can happen on very slow platforms or when doing a valgrind run. */ + res = DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_CODE; + } else { + res = DDS_SECURITY_ERR_UNDEFINED_CODE; + } + } + } + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + local_participant_data = DDS_Security_ParticipantBuiltinTopicData_alloc(); + memcpy(&local_participant_data->key[0], &local_participant_guid, 12); + /* convert from big-endian format to native format */ + local_participant_data->key[0] = fromBE4u(local_participant_data->key[0]); + local_participant_data->key[1] = fromBE4u(local_participant_data->key[1]); + local_participant_data->key[2] = fromBE4u(local_participant_data->key[2]); + + initialize_identity_token(&local_participant_data->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + fill_permissions_token(&local_participant_data->permissions_token ); + + local_participant_data->security_info.participant_security_attributes = 0x01; + local_participant_data->security_info.plugin_participant_security_attributes = 0x02; + + serializer_participant_data(local_participant_data, &sdata, &sz); + + serialized_participant_data._length = serialized_participant_data._maximum = (DDS_Security_unsigned_long) sz; + serialized_participant_data._buffer = sdata; + + DDS_Security_ParticipantBuiltinTopicData_free(local_participant_data); + + + + return res; +} + +static void +clear_local_identity_and_permissions(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (local_permissions_handle != DDS_SECURITY_HANDLE_NIL) { + success = access_control->return_permissions_handle(access_control, local_permissions_handle, &exception); + if (!success) { + printf("return_permission_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } + + if (local_identity_handle != DDS_SECURITY_HANDLE_NIL) { + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } + + DDS_Security_OctetSeq_deinit(&serialized_participant_data); +} + +static int +set_path_to_etc_dir(void) +{ + int res = 0; + size_t len; + + len = 1024; + path_to_etc_dir = ddsrt_malloc(len); + snprintf(path_to_etc_dir, 1024, "%s/listeners_authentication/etc/", CONFIG_ENV_TESTS_DIR); + + return res; +} + +static void set_path_build_dir(void) +{ + ddsrt_asprintf(&g_path_build_dir, "%s/", CONFIG_ENV_BUILD_DIR); +} + +/* handshake helper functions */ + + +static DDS_Security_BinaryProperty_t * +find_binary_property( + DDS_Security_DataHolder *token, + const char *name) +{ + DDS_Security_BinaryProperty_t *result = NULL; + uint32_t i; + + for (i = 0; i < token->binary_properties._length && !result; i++) { + if (token->binary_properties._buffer[i].name && (strcmp(token->binary_properties._buffer[i].name, name) == 0)) { + result = &token->binary_properties._buffer[i]; + } + } + + return result; +} + + +static void +octet_seq_init( + struct octet_seq *seq, + unsigned char *data, + uint32_t size) +{ + seq->data = ddsrt_malloc(size); + memcpy(seq->data, data, size); + seq->length = size; +} + +static void +octet_seq_deinit( + struct octet_seq *seq) +{ + ddsrt_free(seq->data); +} +static char * +get_openssl_error_message_for_test( + void) +{ + BIO *bio = BIO_new(BIO_s_mem()); + char *msg; + char *buf = NULL; + size_t len; + + if (bio) { + ERR_print_errors(bio); + len = (uint32_t)BIO_get_mem_data (bio, &buf); + msg = ddsrt_malloc(len + 1); + memset(msg, 0, len+1); + memcpy(msg, buf, len); + BIO_free(bio); + } else { + msg = ddsrt_strdup("BIO_new failed"); + } + + return msg; +} + + +static const BIGNUM * +dh_get_public_key( + /*_In_ */DH *dhkey) +{ +#ifdef AUTH_INCLUDE_DH_ACCESSORS + const BIGNUM *pubkey, *privkey; + DH_get0_key(dhkey, &pubkey, &privkey); + return pubkey; +#else + return dhkey->pub_key; +#endif +} + + + +/* DH Helper Functions */ + +static int +create_dh_key_modp_2048( + EVP_PKEY **pkey) +{ + int r = 0; + EVP_PKEY *params = NULL; + EVP_PKEY_CTX *kctx = NULL; + DH *dh = NULL; + + *pkey = NULL; + + if ((params = EVP_PKEY_new()) == NULL) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate EVP_PKEY: %s", msg); + ddsrt_free(msg); + r = -1; + } else if ((dh = DH_get_2048_256()) == NULL) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate DH parameter: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_set1_DH(params, dh) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to set DH parameter to MODP_2048_256: %s", msg); + ddsrt_free(msg); + r = -1; + } else if ((kctx = EVP_PKEY_CTX_new(params, NULL)) == NULL) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate KEY context %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_keygen_init(kctx) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to initialize KEY context: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_keygen(kctx, pkey) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to generate :MODP_2048_256 keys %s", msg); + ddsrt_free(msg); + r = -1; + } + + if (params) EVP_PKEY_free(params); + if (kctx) EVP_PKEY_CTX_free(kctx); + if (dh) DH_free(dh); + + return r; +} + +static int +get_dh_public_key_modp_2048( + EVP_PKEY *pkey, + struct octet_seq *pubkey) +{ + int r = 0; + DH *dhkey; + unsigned char *buffer = NULL; + uint32_t size; + ASN1_INTEGER *asn1int; + + dhkey = EVP_PKEY_get1_DH(pkey); + if (!dhkey) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to get DH key from PKEY: %s", msg); + ddsrt_free(msg); + r = -1; + goto fail_get_dhkey; + } + + asn1int = BN_to_ASN1_INTEGER( dh_get_public_key(dhkey) , NULL); + if (!asn1int) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to convert DH key to ASN1 integer: %s", msg); + ddsrt_free(msg); + r = -1; + goto fail_get_pubkey; + } + + size = (uint32_t)i2d_ASN1_INTEGER(asn1int, &buffer); + octet_seq_init(pubkey, buffer, size); + + ASN1_INTEGER_free(asn1int); + OPENSSL_free(buffer); + +fail_get_pubkey: + DH_free(dhkey); +fail_get_dhkey: + return r; +} + +static int +create_dh_key_ecdh( + EVP_PKEY **pkey) +{ + int r = 0; + EVP_PKEY *params = NULL; + EVP_PKEY_CTX *pctx = NULL; + EVP_PKEY_CTX *kctx = NULL; + + *pkey = NULL; + + if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate DH parameter context: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_paramgen_init(pctx) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to initialize DH generation context: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to set DH generation parameter generation method: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_paramgen(pctx, ¶ms) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to generate DH parameters: %s", msg); + ddsrt_free(msg); + r = -1; + } else if ((kctx = EVP_PKEY_CTX_new(params, NULL)) == NULL) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate KEY context %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_keygen_init(kctx) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to initialize KEY context: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_keygen(kctx, pkey) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to generate :MODP_2048_256 keys %s", msg); + ddsrt_free(msg); + r = -1; + } + + if (kctx) EVP_PKEY_CTX_free(kctx); + if (params) EVP_PKEY_free(params); + if (pctx) EVP_PKEY_CTX_free(pctx); + + return r; +} + +static int +get_dh_public_key_ecdh( + EVP_PKEY *pkey, + struct octet_seq *pubkey) +{ + int r = 0; + EC_KEY *eckey = NULL; + const EC_GROUP *group = NULL; + const EC_POINT *point = NULL; + size_t sz; + + if (!(eckey = EVP_PKEY_get1_EC_KEY(pkey))) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to get EC key from PKEY: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (!(point = EC_KEY_get0_public_key(eckey))) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to get public key from ECKEY: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (!(group = EC_KEY_get0_group(eckey))) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to get group from ECKEY: %s", msg); + ddsrt_free(msg); + r = -1; + } else if ((sz = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, NULL, 0, NULL)) != 0) { + pubkey->data = ddsrt_malloc(sz); + pubkey->length = (uint32_t)EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, pubkey->data, sz, NULL); + if (pubkey->length == 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to serialize public EC key: %s", msg); + ddsrt_free(msg); + octet_seq_deinit(pubkey); + r = -1; + } + } else { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to serialize public EC key: %s", msg); + ddsrt_free(msg); + r = -1; + } + + if (eckey) EC_KEY_free(eckey); + + return r; +} + +CU_Init(ddssec_builtin_listeners_auth) +{ + int res = 0; + dds_openssl_init (); + + plugins = load_plugins(&access_control /* Access Control */, + &auth /* Authentication */, + NULL /* Cryptograpy */); + if (plugins) { + set_path_build_dir(); + res = set_path_to_etc_dir(); + if (res >= 0) { + res = create_dh_key_modp_2048(&dh_modp_key); + } + if (res >= 0) { + res = get_dh_public_key_modp_2048(dh_modp_key, &dh_modp_pub_key); + } + if (res >= 0) { + res = create_dh_key_ecdh(&dh_ecdh_key); + } + if (res >= 0) { + res = get_dh_public_key_ecdh(dh_ecdh_key, &dh_ecdh_pub_key); + } + if (res >= 0) { + octet_seq_init(&invalid_dh_pub_key, dh_modp_pub_key.data, dh_modp_pub_key.length); + invalid_dh_pub_key.data[0] = 0x08; + } + } else { + res = -1; + } + + dds_openssl_init (); + return res; +} + +CU_Clean(ddssec_builtin_listeners_auth) +{ + octet_seq_deinit(&dh_modp_pub_key); + octet_seq_deinit(&dh_ecdh_pub_key); + octet_seq_deinit(&invalid_dh_pub_key); + if (dh_modp_key) { + EVP_PKEY_free(dh_modp_key); + } + if (dh_ecdh_key) { + EVP_PKEY_free(dh_ecdh_key); + } + unload_plugins(plugins); + + ddsrt_free(path_to_etc_dir); + return 0; +} + + + +static void +set_binary_property_value( + DDS_Security_BinaryProperty_t *bp, + const char *name, + const unsigned char *data, + uint32_t length) +{ + assert(bp); + assert(name); + assert(data); + + bp->name = ddsrt_strdup(name); + bp->value._maximum = bp->value._length = length; + if (length) { + bp->value._buffer = ddsrt_malloc(length); + memcpy(bp->value._buffer, data, length); + } else { + bp->value._buffer = NULL; + } +} + +static void +set_binary_property_string( + DDS_Security_BinaryProperty_t *bp, + const char *name, + const char *data) +{ + uint32_t length; + + assert(bp); + assert(name); + assert(data); + + length = (uint32_t)strlen(data) + 1; + set_binary_property_value(bp, name, (const unsigned char *)data, length); +} + + +static DDS_Security_ValidationResult_t +create_asymmetrical_signature_for_test( + EVP_PKEY *pkey, + void *data, + size_t dataLen, + unsigned char **signature, + size_t *signatureLen, + DDS_Security_SecurityException *ex) +{ + DDS_Security_ValidationResult_t result = DDS_SECURITY_VALIDATION_OK; + EVP_MD_CTX *mdctx = NULL; + EVP_PKEY_CTX *kctx = NULL; + + if (!(mdctx = EVP_MD_CTX_create())) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to create signing context: %s", msg); + ddsrt_free(msg); + goto err_create_ctx; + } + + if (EVP_DigestSignInit(mdctx, &kctx, EVP_sha256(), NULL, pkey) != 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to initialize signing context: %s", msg); + ddsrt_free(msg); + goto err_sign; + } + + if (EVP_PKEY_CTX_set_rsa_padding(kctx, RSA_PKCS1_PSS_PADDING) < 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to initialize signing context: %s", msg); + ddsrt_free(msg); + goto err_sign; + } + + if (EVP_DigestSignUpdate(mdctx, data, dataLen) != 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to update signing context: %s", msg); + ddsrt_free(msg); + goto err_sign; + } + + if (EVP_DigestSignFinal(mdctx, NULL, signatureLen) != 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to finalize signing context: %s", msg); + ddsrt_free(msg); + goto err_sign; + } + + //*signature = ddsrt_malloc(sizeof(unsigned char) * (*signatureLen)); + *signature = OPENSSL_malloc(*signatureLen); + if (EVP_DigestSignFinal(mdctx, *signature, signatureLen) != 1) { + char *msg = get_openssl_error_message_for_test(); + result = DDS_SECURITY_VALIDATION_FAILED; + DDS_Security_Exception_set(ex, "Authentication", DDS_SECURITY_ERR_UNDEFINED_CODE, (int)result, "Failed to finalize signing context: %s", msg); + ddsrt_free(msg); + ddsrt_free(signature); + } + +err_sign: + EVP_MD_CTX_destroy(mdctx); +err_create_ctx: + return result; +} + + +static X509 * +load_certificate( + const char *data) +{ + X509 *cert = NULL; + BIO *bio; + + bio = BIO_new_mem_buf((void *) data, -1); + if (!bio) { + return NULL; + } + + cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); + + BIO_free(bio); + + return cert; +} + +static int +get_adjusted_participant_guid( + X509 *cert, + const DDS_Security_GUID_t *candidate, + DDS_Security_GUID_t *adjusted) +{ + int result = 0; + unsigned char high[SHA256_DIGEST_LENGTH], low[SHA256_DIGEST_LENGTH]; + unsigned char *subject; + DDS_Security_octet hb = 0x80; + X509_NAME *name; + unsigned char *tmp = NULL; + int i; + int sz; + + name = X509_get_subject_name(cert); + sz = i2d_X509_NAME(name, &tmp); + if (sz > 0) { + subject = ddsrt_malloc((size_t)sz); + memcpy(subject, tmp, (size_t)sz); + OPENSSL_free(tmp); + + SHA256(subject, (size_t)sz, high); + SHA256(&candidate->prefix[0], sizeof(DDS_Security_GuidPrefix_t), low); + + adjusted->entityId = candidate->entityId; + for (i = 0; i < 6; i++) { + adjusted->prefix[i] = hb | high[i]>>1; + hb = (DDS_Security_octet)(high[i]<<7); + } + for (i = 0; i < 6; i++) { + adjusted->prefix[i+6] = low[i]; + } + ddsrt_free(subject); + result = 1; + } + + return result; +} + +static DDS_Security_ValidationResult_t +create_signature_for_test( + EVP_PKEY *pkey, + const DDS_Security_BinaryProperty_t **binary_properties, + const uint32_t binary_properties_length, + unsigned char **signature, + size_t *signatureLen, + DDS_Security_SecurityException *ex) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_Serializer serializer; + unsigned char *buffer; + size_t size; + + serializer = DDS_Security_Serializer_new(4096, 4096); + + DDS_Security_Serialize_BinaryPropertyArray(serializer,binary_properties, binary_properties_length); + DDS_Security_Serializer_buffer(serializer, &buffer, &size); + + result = create_asymmetrical_signature_for_test(pkey, buffer, size, signature, signatureLen, ex); + + ddsrt_free(buffer); + DDS_Security_Serializer_free(serializer); + + return result; +} + + +static void +deinitialize_identity_token( + DDS_Security_IdentityToken *token) +{ + DDS_Security_DataHolder_deinit(token); +} + + + +static void +fill_auth_request_token( + DDS_Security_AuthRequestMessageToken *token) +{ + uint32_t i; + uint32_t len = 32; + unsigned char *challenge; + + challenge = ddsrt_malloc(len); + + for (i = 0; i < len; i++) { + challenge[i] = (unsigned char)(0xFF - i); + } + + memset(token, 0, sizeof(*token)); + + token->class_id = ddsrt_strdup(AUTH_REQUEST_TOKEN_CLASS_ID); + token->binary_properties._maximum = 1; + token->binary_properties._length = 1; + token->binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + token->binary_properties._buffer->name = ddsrt_strdup(AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + + token->binary_properties._buffer->value._maximum = len; + token->binary_properties._buffer->value._length = len; + token->binary_properties._buffer->value._buffer = challenge; +} + +static int +validate_remote_identity (const char *remote_id_certificate) +{ + int res = 0; + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityToken remote_identity_token; + static DDS_Security_AuthRequestMessageToken local_auth_request_token = DDS_SECURITY_TOKEN_INIT; + DDS_Security_GUID_t guid1; + DDS_Security_GUID_t guid2; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix1 = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab}; + DDS_Security_GuidPrefix_t prefix2 = {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb}; + DDS_Security_EntityId_t entityId = {{0xb0,0xb1,0xb2},0x1}; + X509 *cert; + + memcpy(&guid1.prefix, &prefix1, sizeof(prefix1)); + memcpy(&guid1.entityId, &entityId, sizeof(entityId)); + memcpy(&guid2.prefix, &prefix2, sizeof(prefix2)); + memcpy(&guid2.entityId, &entityId, sizeof(entityId)); + + if (local_identity_handle == DDS_SECURITY_HANDLE_NIL) { + return -1; + } + + cert = load_certificate(remote_id_certificate); + if (!cert) { + return -1; + } + + if (!get_adjusted_participant_guid(cert, &guid1, &remote_participant_guid1)) { + X509_free(cert); + return -1; + } + + if (!get_adjusted_participant_guid(cert, &guid2, &remote_participant_guid2)) { + X509_free(cert); + return -1; + } + + X509_free(cert); + + initialize_identity_token(&remote_identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &g_local_auth_request_token, + NULL, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid1, + &exception); + + if ((result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST) && + (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE)) { + printf("validate_remote_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + reset_exception(&exception); + fill_auth_request_token(&g_remote_auth_request_token); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle2, + &local_auth_request_token, + &g_remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid2, + &exception); + + if ((result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST) && + (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE)) { + printf("validate_remote_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + reset_exception(&exception); + deinitialize_identity_token(&remote_identity_token); + DDS_Security_DataHolder_deinit(&local_auth_request_token); + + remote_participant_data1 = DDS_Security_ParticipantBuiltinTopicData_alloc(); + memcpy(&remote_participant_data1->key[0], &remote_participant_guid1, 12); + remote_participant_data1->key[0] = fromBE4u(remote_participant_data1->key[0]); + remote_participant_data1->key[1] = fromBE4u(remote_participant_data1->key[1]); + remote_participant_data1->key[2] = fromBE4u(remote_participant_data1->key[2]); + + initialize_identity_token(&remote_participant_data1->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + fill_permissions_token(&remote_participant_data1->permissions_token ); + + remote_participant_data1->security_info.participant_security_attributes = 0x01; + remote_participant_data1->security_info.plugin_participant_security_attributes = 0x02; + + remote_participant_data2 = DDS_Security_ParticipantBuiltinTopicData_alloc(); + memcpy(&remote_participant_data2->key[0], &remote_participant_guid2, 12); + remote_participant_data2->key[0] = fromBE4u(remote_participant_data2->key[0]); + remote_participant_data2->key[1] = fromBE4u(remote_participant_data2->key[1]); + remote_participant_data2->key[2] = fromBE4u(remote_participant_data2->key[2]); + + initialize_identity_token(&remote_participant_data2->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + fill_permissions_token(&remote_participant_data2->permissions_token ); + + remote_participant_data2->security_info.participant_security_attributes = 0x01; + remote_participant_data2->security_info.plugin_participant_security_attributes = 0x02; + + remote_participant_data3 = DDS_Security_ParticipantBuiltinTopicData_alloc(); + memcpy(&remote_participant_data3->key[0], &candidate_participant_guid, 12); + + initialize_identity_token(&remote_participant_data3->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + fill_permissions_token(&remote_participant_data3->permissions_token ); + + remote_participant_data2->security_info.participant_security_attributes = 0x01; + remote_participant_data2->security_info.plugin_participant_security_attributes = 0x02; + + challenge1_predefined_glb = find_binary_property(&g_remote_auth_request_token, AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + challenge2_predefined_glb = challenge1_predefined_glb; + + return res; +} + +static void +release_remote_identities(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (remote_identity_handle != DDS_SECURITY_HANDLE_NIL) { + success = auth->return_identity_handle(auth, remote_identity_handle, &exception); + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } + + if (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL) { + success = auth->return_identity_handle(auth, remote_identity_handle2, &exception); + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } + + DDS_Security_DataHolder_deinit(&g_local_auth_request_token); + DDS_Security_DataHolder_deinit(&g_remote_auth_request_token); + + DDS_Security_ParticipantBuiltinTopicData_free(remote_participant_data1); + DDS_Security_ParticipantBuiltinTopicData_free(remote_participant_data2); + DDS_Security_ParticipantBuiltinTopicData_free(remote_participant_data3); +} + + +static void +fill_handshake_message_token( + DDS_Security_HandshakeMessageToken *token, + DDS_Security_ParticipantBuiltinTopicData *pdata, + const char *certificate, + const char *dsign, + const char *kagree, + const struct octet_seq *diffie_hellman1, + const unsigned char *challengeData, + unsigned int challengeDataSize, + const struct octet_seq *diffie_hellman2, + const unsigned char *challengeData2, + unsigned int challengeDataSize2, + const DDS_Security_BinaryProperty_t *hash1_from_request, + const DDS_Security_BinaryProperty_t *hash2_from_reply, + HandshakeStep_t step) +{ + DDS_Security_BinaryProperty_t *tokens; + DDS_Security_BinaryProperty_t *c_id; + DDS_Security_BinaryProperty_t *c_perm; + DDS_Security_BinaryProperty_t *c_pdata; + DDS_Security_BinaryProperty_t *c_dsign_algo; + DDS_Security_BinaryProperty_t *c_kagree_algo; + DDS_Security_BinaryProperty_t *hash_c1; + DDS_Security_BinaryProperty_t *hash_c2; + DDS_Security_BinaryProperty_t *dh1; + DDS_Security_BinaryProperty_t *dh2; + DDS_Security_BinaryProperty_t *challenge1; + DDS_Security_BinaryProperty_t *challenge2; + DDS_Security_BinaryProperty_t *signature; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + unsigned idx; + unsigned char *serialized_local_participant_data; + size_t serialized_local_participant_data_size; + /*unsigned hash[32];*/ + + switch( step ) + { + + case HANDSHAKE_REQUEST: + tokens = DDS_Security_BinaryPropertySeq_allocbuf(8); + c_id = &tokens[0]; + c_perm = &tokens[1]; + c_pdata = &tokens[2]; + c_dsign_algo = &tokens[3]; + c_kagree_algo = &tokens[4]; + hash_c1 = &tokens[5]; + dh1 = &tokens[6]; + challenge1 = &tokens[7]; + + serializer_participant_data(pdata, &serialized_local_participant_data, &serialized_local_participant_data_size); + + /* Store the Identity Certificate associated with the local identify in c.id property */ + if (certificate) { + set_binary_property_string(c_id, "c.id", certificate); + } else { + set_binary_property_string(c_id, "c.idx", "rubbish"); + } + + /* Store the permission document in the c.perm property */ + set_binary_property_string(c_perm, "c.perm", "permissions_document"); + + /* Store the provided local_participant_data in the c.pdata property */ + set_binary_property_value(c_pdata, "c.pdata", serialized_local_participant_data, (uint32_t)serialized_local_participant_data_size); + ddsrt_free(serialized_local_participant_data); + + /* Set the used signing algorithm descriptor in c.dsign_algo */ + if (dsign) { + set_binary_property_string(c_dsign_algo, "c.dsign_algo", dsign); + } else { + set_binary_property_string(c_dsign_algo, "c.dsign_algox", "rubbish"); + } + + /* Set the used key algorithm descriptor in c.kagree_algo */ + if (kagree) { + set_binary_property_string(c_kagree_algo, "c.kagree_algo", kagree); + } else { + set_binary_property_string(c_kagree_algo, "c.kagree_algox", "rubbish"); + } + + /* Calculate the hash_c1 */ + { + DDS_Security_BinaryPropertySeq bseq; + DDS_Security_Serializer serializer; + unsigned char hash1_sent_in_request_arr[32]; + unsigned char *buffer; + size_t size; + + bseq._length = bseq._maximum = 5; + bseq._buffer = tokens; + + serializer = DDS_Security_Serializer_new(1024, 1024); + + DDS_Security_Serialize_BinaryPropertySeq(serializer, &bseq); + DDS_Security_Serializer_buffer(serializer, &buffer, &size); + SHA256(buffer, size, hash1_sent_in_request_arr); + ddsrt_free(buffer); + DDS_Security_Serializer_free(serializer); + + set_binary_property_value(hash_c1, "hash_c1", hash1_sent_in_request_arr, sizeof(hash1_sent_in_request_arr)); + } + + /* Set the DH public key associated with the local participant in dh1 property */ + if (diffie_hellman1) { + set_binary_property_value(dh1, "dh1", diffie_hellman1->data, diffie_hellman1->length); + } else { + set_binary_property_string(dh1, "dh1x", "rubbish"); + } + + /* Set the challenge in challenge1 property */ + if (challengeData) { + set_binary_property_value(challenge1, "challenge1", challengeData, challengeDataSize); + } else { + set_binary_property_value(challenge1, "challenge1x", challenge1_predefined_glb->value._buffer, challenge1_predefined_glb->value._length); + } + + token->class_id = ddsrt_strdup(AUTH_HANDSHAKE_REQUEST_TOKEN_CLASS_ID); + token->binary_properties._length = token->binary_properties._maximum = 8; + token->binary_properties._buffer = tokens; + break; + + case HANDSHAKE_REPLY: + tokens = DDS_Security_BinaryPropertySeq_allocbuf(12); + idx = 0; + c_id = &tokens[idx++]; + c_perm = &tokens[idx++]; + c_pdata = &tokens[idx++]; + c_dsign_algo = &tokens[idx++]; + c_kagree_algo = &tokens[idx++]; + hash_c2 = &tokens[idx++]; + challenge2 = &tokens[idx++]; + dh2 = &tokens[idx++]; + challenge1 = &tokens[idx++]; + dh1 = &tokens[idx++]; + hash_c1 = &tokens[idx++] ; + signature = &tokens[idx++]; + + serializer_participant_data(pdata, &serialized_local_participant_data, &serialized_local_participant_data_size); + + /* Store the Identity Certificate associated with the local identify in c.id property */ + if (certificate) { + set_binary_property_string(c_id, "c.id", certificate); + } else { + set_binary_property_string(c_id, "c.idx", "rubbish"); + } + + /* Store the permission document in the c.perm property */ + set_binary_property_string(c_perm, "c.perm", "permissions_document"); + + /* Store the provided local_participant_data in the c.pdata property */ + set_binary_property_value(c_pdata, "c.pdata", serialized_local_participant_data, (uint32_t)serialized_local_participant_data_size); + ddsrt_free(serialized_local_participant_data); + + /* Set the used signing algorithm descriptor in c.dsign_algo */ + if (dsign) { + set_binary_property_string(c_dsign_algo, "c.dsign_algo", dsign); + } else { + set_binary_property_string(c_dsign_algo, "c.dsign_algox", "rubbish"); + } + + /* Set the used key algorithm descriptor in c.kagree_algo */ + if (kagree) { + set_binary_property_string(c_kagree_algo, "c.kagree_algo", kagree); + } else { + set_binary_property_string(c_kagree_algo, "c.kagree_algox", "rubbish"); + } + + CU_ASSERT_FATAL(hash1_from_request != NULL); + assert(hash1_from_request != NULL); // for Clang's static analyzer + + set_binary_property_value(hash_c1, "hash_c1", hash1_from_request->value._buffer, hash1_from_request->value._length); + + /* Calculate the hash_c2 */ + { + DDS_Security_BinaryPropertySeq bseq; + DDS_Security_Serializer serializer; + unsigned char hash2_sent_in_reply_arr[32]; + unsigned char *buffer; + size_t size; + + bseq._length = bseq._maximum = 5; + bseq._buffer = tokens; + + serializer = DDS_Security_Serializer_new(1024, 1024); + + DDS_Security_Serialize_BinaryPropertySeq(serializer, &bseq); + DDS_Security_Serializer_buffer(serializer, &buffer, &size); + SHA256(buffer, size, hash2_sent_in_reply_arr); + + ddsrt_free(buffer); + DDS_Security_Serializer_free(serializer); + + set_binary_property_value(hash_c2, "hash_c2", hash2_sent_in_reply_arr, sizeof(hash2_sent_in_reply_arr)); + } + + /* Set the challenge in challenge1 property */ + if (challengeData) { + set_binary_property_value(challenge1, "challenge1", challengeData, challengeDataSize); + } else { + set_binary_property_value(challenge1, "challenge1x", challenge2->value._buffer, challenge2->value._length); + } + + /* Set the challenge in challenge2 property */ + if (challengeData2) { + set_binary_property_value(challenge2, "challenge2", challengeData2, challengeDataSize2); + } else { + set_binary_property_value(challenge2, "challenge2x", challenge2->value._buffer, challenge2->value._length); + } + + + /* Set the DH public key associated with the local participant in dh1 property */ + if (diffie_hellman1) { + set_binary_property_value(dh1, "dh1", diffie_hellman1->data, diffie_hellman1->length); + } else { + set_binary_property_string(dh1, "dh1x", "rubbish"); + } + + /* Set the DH public key associated with the local participant in dh2 property */ + if (diffie_hellman2) { + set_binary_property_value(dh2, "dh2", diffie_hellman2->data, diffie_hellman2->length); + } else { + set_binary_property_string(dh2, "dh2x", "rubbish"); + } + + /* Calculate the signature */ + { + BIO *bio; + EVP_PKEY *private_key_x509; + unsigned char *sign; + size_t signlen; + DDS_Security_ValidationResult_t rc; + + const DDS_Security_BinaryProperty_t * binary_properties[ HANDSHAKE_SIGNATURE_SIZE ]; + + /* load certificate in buffer */ + bio = BIO_new_mem_buf((const char *) bob_private_key, -1); + assert( bio ); + private_key_x509 = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + assert (private_key_x509 ); + + binary_properties[0] = hash_c2; + binary_properties[1] = challenge2; + binary_properties[2] = dh2; + binary_properties[3] = challenge1; + binary_properties[4] = dh1; + binary_properties[5] = hash_c1; + + rc = create_signature_for_test(private_key_x509, binary_properties, HANDSHAKE_SIGNATURE_SIZE , &sign, &signlen, &exception); + if (rc != DDS_SECURITY_VALIDATION_OK) + { + printf("Exception: %s\n", exception.message); + } + CU_ASSERT_FATAL (rc == DDS_SECURITY_VALIDATION_OK); + assert(rc == DDS_SECURITY_VALIDATION_OK); // for Clang's static analyzer + + set_binary_property_value(signature, "signature", sign, (uint32_t)signlen); + + ddsrt_free(sign); + EVP_PKEY_free(private_key_x509); + BIO_free(bio); + } + + token->class_id = ddsrt_strdup(AUTH_HANDSHAKE_REPLY_TOKEN_CLASS_ID); + token->binary_properties._length = token->binary_properties._maximum = 12; + token->binary_properties._buffer = tokens; + break; + + case HANDSHAKE_FINAL: + tokens = DDS_Security_BinaryPropertySeq_allocbuf(7); + idx = 0; + signature = &tokens[idx++]; + hash_c1 = &tokens[idx++]; + challenge1 = &tokens[idx++]; + dh1 = &tokens[idx++]; + challenge2 = &tokens[idx++]; + dh2 = &tokens[idx++]; + hash_c2 = &tokens[idx++]; + + CU_ASSERT(hash1_from_request != NULL); + CU_ASSERT(hash2_from_reply != NULL); + + set_binary_property_value(hash_c1, "hash_c1", hash1_from_request->value._buffer, hash1_from_request->value._length); + set_binary_property_value(hash_c2, "hash_c2", hash2_from_reply->value._buffer, hash2_from_reply->value._length); + + printf("process: %s\n", hash_c1->name); + + /* Set the challenge in challenge1 property */ + if (challengeData) { + set_binary_property_value(challenge1, "challenge1", challengeData, challengeDataSize); + } else { + set_binary_property_value(challenge1, "challenge1x", challenge2->value._buffer, challenge2->value._length); + } + + /* Set the challenge in challenge2 property */ + if (challengeData2) { + set_binary_property_value(challenge2, "challenge2", challengeData2, challengeDataSize2); + } else { + set_binary_property_value(challenge2, "challenge2x", challenge2->value._buffer, challenge2->value._length); + } + + + /* Set the DH public key associated with the local participant in dh1 property */ + if (diffie_hellman1) { + set_binary_property_value(dh1, "dh1", diffie_hellman1->data, diffie_hellman1->length); + } else { + set_binary_property_string(dh1, "dh1x", "rubbish"); + } + + /* Set the DH public key associated with the local participant in dh2 property */ + if (diffie_hellman2) { + set_binary_property_value(dh2, "dh2", diffie_hellman2->data, diffie_hellman2->length); + } else { + set_binary_property_string(dh2, "dh2x", "rubbish"); + } + + /* Calculate the signature */ + { + BIO *bio; + EVP_PKEY *private_key_x509; + unsigned char *sign; + size_t signlen; + const DDS_Security_BinaryProperty_t * binary_properties[ HANDSHAKE_SIGNATURE_SIZE ]; + + /* load certificate in buffer */ + bio = BIO_new_mem_buf((const char *) bob_private_key, -1); + assert( bio ); + private_key_x509 = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + assert (private_key_x509 ); + + binary_properties[0] = hash_c1; + binary_properties[1] = challenge1; + binary_properties[2] = dh1; + binary_properties[3] = challenge2; + binary_properties[4] = dh2; + binary_properties[5] = hash_c2; + + if (create_signature_for_test(private_key_x509, binary_properties, HANDSHAKE_SIGNATURE_SIZE, &sign, &signlen, &exception) != DDS_SECURITY_VALIDATION_OK) + { + printf("Exception: %s\n", exception.message); + } + set_binary_property_value(signature, "signature", sign, (uint32_t)signlen); + + ddsrt_free(sign); + EVP_PKEY_free(private_key_x509); + BIO_free(bio); + } + token->class_id = ddsrt_strdup(AUTH_HANDSHAKE_FINAL_TOKEN_CLASS_ID); + token->binary_properties._length = token->binary_properties._maximum = 7; + token->binary_properties._buffer = tokens; + break; + } +} + + +static DDS_Security_boolean on_revoke_identity_cb(const dds_security_authentication *plugin, const DDS_Security_IdentityHandle handle) +{ + DDSRT_UNUSED_ARG (plugin); + if (identity_handle_for_callback1 == DDS_SECURITY_HANDLE_NIL) + identity_handle_for_callback1 = handle; + else if (identity_handle_for_callback2 == DDS_SECURITY_HANDLE_NIL) + identity_handle_for_callback2 = handle; + printf( "Listener called for handle: %lld Local:%lld Remote:%lld\n", (long long) handle, (long long) local_identity_handle, (long long) remote_identity_handle2); + + return true; +} + + +/* sets listener for authentication expiry and checks if the listener triggered after a while */ +CU_Test(ddssec_builtin_listeners_auth, local_remote_set_before_validation) +{ + DDS_Security_PermissionsHandle result; + DDS_Security_PermissionsToken permissions_token; + DDS_Security_AuthenticatedPeerCredentialToken credential_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_long valid; + int r; + dds_duration_t time_left = DDS_MSECS(10000); + DDS_Security_boolean local_expired = false; + DDS_Security_boolean remote_expired = false; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_reply_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_reply_token_out = DDS_SECURITY_TOKEN_INIT; + const DDS_Security_BinaryProperty_t *hash1_sent_in_request; + const DDS_Security_BinaryProperty_t *dh1; + const DDS_Security_BinaryProperty_t *challenge1_glb; + struct octet_seq dh1_pub_key; + char *remote_certificate_file; + + local_expiry_date = DDS_TIME_INVALID; + remote_expiry_date = DDS_TIME_INVALID; + + auth_listener.on_revoke_identity = &on_revoke_identity_cb; + + auth->set_listener( auth, &auth_listener, &exception); + access_control->set_listener( access_control, + &access_control_listener, + &exception); + + + valid = validate_local_identity_and_permissions( 3, &local_expiry_date); + if (valid == DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_CODE) { + /* This can happen on very slow platforms or when doing a valgrind run. + * Just take our losses and quit, simulating a success. */ + return; + } + CU_ASSERT_FATAL (valid == DDS_SECURITY_ERR_OK_CODE); + + /*Generate remote certificate*/ + create_certificate_from_csr( bob_csr, 4, BOB_IDENTITY_CERT_FILE, &remote_expiry_date ); + + ddsrt_asprintf(&remote_certificate_file, "%s%s", g_path_build_dir, BOB_IDENTITY_CERT_FILE); + bob_identity_cert = load_file_contents( remote_certificate_file ); + + validate_remote_identity( bob_identity_cert ); + + + /* Check if we actually have validate_remote_permissions function. */ + CU_ASSERT_FATAL (access_control != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (access_control->validate_remote_permissions != NULL); + CU_ASSERT_FATAL (access_control->return_permissions_handle != NULL); + + fill_permissions_token(&permissions_token); + r = fill_peer_credential_token(&credential_token); + CU_ASSERT_FATAL (r); + + + + /*handshake*/ + result = auth->begin_handshake_request( + auth, + &handshake_handle, + &handshake_token_out, + local_identity_handle, + remote_identity_handle2, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_request failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* get challenge 1 from the message */ + challenge1_glb = find_binary_property(&handshake_token_out, "challenge1"); + + /*Get DH1 value */ + dh1 = find_binary_property(&handshake_token_out, "dh1"); + + hash1_sent_in_request = find_binary_property(&handshake_token_out, "hash_c1"); + + CU_ASSERT_FATAL(dh1 != NULL); + assert(dh1 != NULL); // for Clang's static analyzer + CU_ASSERT_FATAL(dh1->value._length > 0); + CU_ASSERT_FATAL(dh1->value._buffer != NULL); + assert(dh1->value._length > 0 && dh1->value._buffer != NULL); // for Clang's static analyzer + + dh1_pub_key.data = dh1->value._buffer; + dh1_pub_key.length = dh1->value._length; + + /* prepare reply */ + fill_handshake_message_token( + &handshake_reply_token_in, remote_participant_data2, bob_identity_cert, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_ECDH_NAME, + &dh1_pub_key, challenge1_glb->value._buffer, challenge1_glb->value._length, + &dh_ecdh_pub_key, challenge2_predefined_glb->value._buffer, challenge2_predefined_glb->value._length, hash1_sent_in_request, NULL, HANDSHAKE_REPLY); + + reset_exception(&exception); + + result = auth->process_handshake( + auth, + &handshake_reply_token_out, + &handshake_reply_token_in, + handshake_handle, + &exception); + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE); + CU_ASSERT(handshake_handle != DDS_SECURITY_HANDLE_NIL); + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + if (result == 0) { + printf("validate_remote_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + //TODO: Clean-up before failing + CU_ASSERT_FATAL (exception.code == DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_CODE); +// goto end; + + } + + remote_permissions_handle = result; + + reset_exception(&exception); + + while( time_left > 0 && (!local_expired || !remote_expired) ){ + /* Normally, it is expected that the remote expiry is triggered before the + * local one. However, that can change on slow platforms. */ + // TODO: Check for time compare + if (remote_expiry_date < local_expiry_date) { + if (identity_handle_for_callback1 == remote_identity_handle2) { + remote_expired = true; + } + if (identity_handle_for_callback2 == local_identity_handle) { + local_expired = true; + } + } else { + if (identity_handle_for_callback2 == remote_identity_handle2) { + remote_expired = true; + } + if (identity_handle_for_callback1 == local_identity_handle) { + local_expired = true; + } + } + + dds_sleepfor(DDS_MSECS(100)); + time_left -= DDS_MSECS(100); + } + + CU_ASSERT (local_expired); + CU_ASSERT (remote_expired); + + + reset_exception(&exception); + + result = auth->return_handshake_handle(auth, handshake_handle, &exception); + release_remote_identities(); + + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *) &permissions_token); + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *) &credential_token); + + + CU_ASSERT_TRUE (result == 1); + + reset_exception(&exception); + + DDS_Security_DataHolder_deinit(&handshake_token_out); + DDS_Security_DataHolder_deinit(&handshake_reply_token_in); + DDS_Security_DataHolder_deinit(&handshake_reply_token_out); + + clear_local_identity_and_permissions(); + ddsrt_free( bob_identity_cert ); + ddsrt_free ( remote_certificate_file ); +} diff --git a/src/security/builtin_plugins/tests/preprocess_secure_submsg/src/preprocess_secure_submsg_utests.c b/src/security/builtin_plugins/tests/preprocess_secure_submsg/src/preprocess_secure_submsg_utests.c new file mode 100644 index 0000000..d8c5201 --- /dev/null +++ b/src/security/builtin_plugins/tests/preprocess_secure_submsg/src/preprocess_secure_submsg_utests.c @@ -0,0 +1,928 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +#define VALID_SMID_SEC_PREFIX 0x31 +#define INVALID_SMID_SEC_PREFIX 0x15 + + +typedef struct SubMessageHeader { + unsigned char kind; + unsigned char flags; + uint16_t octetsToNextSubMsg; +} SubMessageHeader; + +typedef struct CryptoHeader { + DDS_Security_CryptoTransformKind transform_id; + DDS_Security_CryptoTransformKeyId key_id; + unsigned char session_id[4]; + unsigned char initVectorSuffix[8]; +} CryptoHeader; + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_participant_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_handle = DDS_SECURITY_HANDLE_NIL; + +static DDS_Security_DatawriterCryptoHandle local_writer_crypto = 0; +static DDS_Security_DatawriterCryptoHandle remote_writer_crypto = 0; +static DDS_Security_DatareaderCryptoHandle local_reader_crypto = 0; +static DDS_Security_DatareaderCryptoHandle remote_reader_crypto = 0; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static DDS_Security_KeyMaterial_AES_GCM_GMAC writer_key_message; +static DDS_Security_KeyMaterial_AES_GCM_GMAC writer_key_payload; +static DDS_Security_KeyMaterial_AES_GCM_GMAC reader_key_message; + +static void allocate_shared_secret(void) +{ + int32_t i; + + shared_secret_handle_impl = ddsrt_malloc (sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc (TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle) shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + memset(&participant_security_attributes, 0, sizeof(participant_security_attributes)); + + local_participant_handle = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_participant_handle == DDS_SECURITY_HANDLE_NIL) { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_participant_handle ? 0 : -1; +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_participant_handle = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_handle, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_participant_handle == DDS_SECURITY_HANDLE_NIL) { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_participant_handle ? 0 : -1; +} + +static void prepare_endpoint_security_attributes( DDS_Security_EndpointSecurityAttributes *attributes){ + memset( attributes, 0 , sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; + +} + +static int register_local_datareader(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + memset(&datareader_properties, 0, sizeof(datareader_properties)); + prepare_endpoint_security_attributes( &datareader_security_attributes ); + + local_reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + + + if (local_reader_crypto == 0) + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + + return local_reader_crypto ? 0 : -1; +} + +static int register_remote_datareader(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + + memset (&datawriter_properties, 0, sizeof(datawriter_properties)); + remote_reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_crypto, + remote_participant_handle, + shared_secret_handle, + true, + &exception); + + if (remote_reader_crypto == 0) + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + + return remote_reader_crypto ? 0 : -1; +} + +static int register_local_datawriter(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + prepare_endpoint_security_attributes( &datawriter_security_attributes ); + + local_writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + + if (local_writer_crypto == 0) + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + + return local_writer_crypto ? 0 : -1; +} + +static int register_remote_datawriter(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + remote_writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_crypto, + remote_participant_handle, + shared_secret_handle, + &exception); + + if (remote_writer_crypto == 0) + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + + return remote_writer_crypto ? 0 : -1; +} + +static DDS_Security_boolean retrieve_datawriter_keys(DDS_Security_DatawriterCryptoTokenSeq *tokens) +{ + DDS_Security_boolean result = true; + DDS_Security_Deserializer deserializer; + DDS_Security_KeyMaterial_AES_GCM_GMAC *key_mat = &writer_key_message; + uint32_t i; + + for (i = 0; result && (i < tokens->_length); i++) { + const DDS_Security_OctetSeq *tdata = &tokens->_buffer[i].binary_properties._buffer[0].value; + + deserializer = DDS_Security_Deserializer_new(tdata->_buffer, tdata->_length); + + if (!deserializer) + result = false; + else if (!DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC(deserializer, key_mat)) + result = false; + + DDS_Security_Deserializer_free(deserializer); + key_mat = &writer_key_payload; + } + + return result; +} + +static DDS_Security_boolean retrieve_datareader_keys(DDS_Security_DatareaderCryptoTokenSeq *tokens) +{ + DDS_Security_boolean result = true; + const DDS_Security_OctetSeq *tdata = &tokens->_buffer[0].binary_properties._buffer[0].value; + DDS_Security_Deserializer deserializer; + DDS_Security_KeyMaterial_AES_GCM_GMAC *key_mat = &reader_key_message; + + deserializer = DDS_Security_Deserializer_new(tdata->_buffer, tdata->_length); + + if (!deserializer) + result = false; + else if (!DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC(deserializer, key_mat)) + result = false; + DDS_Security_Deserializer_free(deserializer); + + return result; +} + +static int set_remote_datawriter_tokens(void) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_writer_crypto, + remote_reader_crypto, + &exception); + + if (result) + result = retrieve_datawriter_keys(&tokens); + + if (result) { + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + } + + DDS_Security_DataHolderSeq_deinit((DDS_Security_DataHolderSeq*)&tokens); + + return result ? 0 : -1; +} + +static int set_remote_datareader_tokens(void) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoTokenSeq tokens; + + memset(&tokens, 0, sizeof(tokens)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->create_local_datareader_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_reader_crypto, + remote_writer_crypto, + &exception); + + if (result) + result = retrieve_datareader_keys(&tokens); + if (result) { + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + } + + DDS_Security_DataHolderSeq_deinit((DDS_Security_DataHolderSeq*)&tokens); + + return result ? 0 : -1; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + + +static void suite_preprocess_secure_submsg_init (void) +{ + allocate_shared_secret(); + memset(&writer_key_message, 0, sizeof(DDS_Security_KeyMaterial_AES_GCM_GMAC)); + memset(&writer_key_payload, 0, sizeof(DDS_Security_KeyMaterial_AES_GCM_GMAC)); + memset(&reader_key_message, 0, sizeof(DDS_Security_KeyMaterial_AES_GCM_GMAC)); + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptography */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_local_datawriter(), 0); + CU_ASSERT_EQUAL_FATAL (register_local_datareader(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_datareader(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_datawriter(), 0); + CU_ASSERT_EQUAL_FATAL (set_remote_datawriter_tokens(), 0); + CU_ASSERT_EQUAL_FATAL (set_remote_datareader_tokens(), 0); +} + +static void suite_preprocess_secure_submsg_fini (void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + if (remote_writer_crypto) { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, remote_writer_crypto, &exception); + reset_exception(&exception); + } + if (remote_reader_crypto) { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, remote_reader_crypto, &exception); + reset_exception(&exception); + } + if (local_reader_crypto) { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_reader_crypto, &exception); + reset_exception(&exception); + } + if (local_writer_crypto) { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, local_writer_crypto, &exception); + reset_exception(&exception); + } + if (remote_participant_handle) { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_participant_handle, &exception); + reset_exception(&exception); + } + if (local_participant_handle) { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_participant_handle, &exception); + reset_exception(&exception); + } + + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&reader_key_message); + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&writer_key_message); + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void create_encoded_submsg(DDS_Security_OctetSeq *msg, DDS_Security_CryptoTransformKeyId key_id, DDS_Security_CryptoTransformKind transform_kind, unsigned char msg_id, bool be) +{ + unsigned char *buffer; + uint32_t length = sizeof(SubMessageHeader) + sizeof(CryptoHeader) + 200; + SubMessageHeader *submsg; + CryptoHeader *crpthdr; + int swap = be ? (DDSRT_ENDIAN == DDSRT_LITTLE_ENDIAN) : (DDSRT_ENDIAN != DDSRT_LITTLE_ENDIAN); + + buffer = ddsrt_malloc(length); + submsg = (SubMessageHeader *) buffer; + crpthdr = (CryptoHeader *) (submsg + 1); + + submsg->kind = msg_id; + submsg->flags = be ? 0 : 1; + submsg->octetsToNextSubMsg = swap ? ddsrt_bswap2u((uint16_t)(length - 24)) : (uint16_t)(length - 24); + + memcpy(crpthdr->key_id, key_id, 4); + memcpy(crpthdr->transform_id, transform_kind, 4); + + msg->_buffer = buffer; + msg->_length = msg->_maximum = length; +} + +static void clear_encoded_submsg(DDS_Security_OctetSeq *msg) +{ + if (msg) { + ddsrt_free(msg->_buffer); + memset(msg, 0, sizeof(*msg)); + } +} + + +CU_Test(ddssec_builtin_preprocess_secure_submsg, writer_happy_day, .init = suite_preprocess_secure_submsg_init, .fini = suite_preprocess_secure_submsg_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecureSubmessageCategory_t category; + DDS_Security_OctetSeq message; + + CU_ASSERT_FATAL (crypto != NULL); + CU_ASSERT_FATAL (crypto->crypto_transform != NULL); + CU_ASSERT_FATAL (crypto->crypto_transform->preprocess_secure_submsg != NULL); + + create_encoded_submsg(&message, writer_key_message.sender_key_id, writer_key_message.transformation_kind, VALID_SMID_SEC_PREFIX, false); + + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT(writer_crypto == remote_writer_crypto); + CU_ASSERT(reader_crypto == local_reader_crypto); + CU_ASSERT(category == DDS_SECURITY_DATAWRITER_SUBMESSAGE); + + reset_exception(&exception); + + clear_encoded_submsg(&message); + + create_encoded_submsg(&message, writer_key_message.sender_key_id, writer_key_message.transformation_kind, VALID_SMID_SEC_PREFIX, true); + + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT(writer_crypto == remote_writer_crypto); + CU_ASSERT(reader_crypto == local_reader_crypto); + CU_ASSERT(category == DDS_SECURITY_DATAWRITER_SUBMESSAGE); + + reset_exception(&exception); + + clear_encoded_submsg(&message); +} + +CU_Test(ddssec_builtin_preprocess_secure_submsg, reader_happy_day, .init = suite_preprocess_secure_submsg_init, .fini = suite_preprocess_secure_submsg_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecureSubmessageCategory_t category; + DDS_Security_OctetSeq message; + + CU_ASSERT_FATAL (crypto != NULL); + CU_ASSERT_FATAL (crypto ->crypto_transform!= NULL); + CU_ASSERT_FATAL (crypto ->crypto_transform->preprocess_secure_submsg != NULL); + + create_encoded_submsg(&message, reader_key_message.sender_key_id, reader_key_message.transformation_kind, VALID_SMID_SEC_PREFIX, false); + + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT(writer_crypto == local_writer_crypto); + CU_ASSERT(reader_crypto == remote_reader_crypto); + CU_ASSERT(category == DDS_SECURITY_DATAREADER_SUBMESSAGE); + + reset_exception(&exception); + clear_encoded_submsg(&message); + create_encoded_submsg(&message, reader_key_message.sender_key_id, reader_key_message.transformation_kind, VALID_SMID_SEC_PREFIX, true); + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT(writer_crypto == local_writer_crypto); + CU_ASSERT(reader_crypto == remote_reader_crypto); + CU_ASSERT(category == DDS_SECURITY_DATAREADER_SUBMESSAGE); + + reset_exception(&exception); + clear_encoded_submsg(&message); +} + + +CU_Test(ddssec_builtin_preprocess_secure_submsg, invalid_args, .init = suite_preprocess_secure_submsg_init, .fini = suite_preprocess_secure_submsg_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecureSubmessageCategory_t category; + DDS_Security_OctetSeq message; + + CU_ASSERT_FATAL (crypto != NULL); + CU_ASSERT_FATAL (crypto ->crypto_transform!= NULL); + CU_ASSERT_FATAL (crypto ->crypto_transform->preprocess_secure_submsg != NULL); + + create_encoded_submsg(&message, writer_key_message.sender_key_id, reader_key_message.transformation_kind, VALID_SMID_SEC_PREFIX, false); + + /* writer handle = NULL. */ + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + NULL, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* reader handle = NULL. */ + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + NULL, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* category = NULL */ + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + NULL, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* message = NULL */ + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + NULL, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + #if 0 + /* unknown local_participant_handle */ + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + 1, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); +#endif + + /* remote_participant_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + 0, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* unknown remote_participant_handle */ + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + 1, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + clear_encoded_submsg(&message); +} + + +CU_Test(ddssec_builtin_preprocess_secure_submsg, invalid_message, .init = suite_preprocess_secure_submsg_init, .fini = suite_preprocess_secure_submsg_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecureSubmessageCategory_t category; + DDS_Security_OctetSeq message; + + CU_ASSERT_FATAL (crypto != NULL); + CU_ASSERT_FATAL (crypto ->crypto_transform!= NULL); + CU_ASSERT_FATAL (crypto ->crypto_transform->preprocess_secure_submsg != NULL); + + /* unknown key id */ + create_encoded_submsg(&message, writer_key_payload.sender_key_id, writer_key_payload.transformation_kind, VALID_SMID_SEC_PREFIX, false); + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + clear_encoded_submsg(&message); + + /* invalid transformation kind */ + { + DDS_Security_CryptoTransformKind kind = {5, 1, 3, 6}; + + create_encoded_submsg(&message, writer_key_message.sender_key_id, kind, VALID_SMID_SEC_PREFIX, false); + + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + clear_encoded_submsg(&message); + } + + /* not expected submessage id */ + { + DDS_Security_CryptoTransformKind kind = {5, 1, 3, 6}; + create_encoded_submsg(&message, writer_key_message.sender_key_id, kind, INVALID_SMID_SEC_PREFIX, false); + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + clear_encoded_submsg(&message); + } +} + + +CU_Test(ddssec_builtin_preprocess_secure_submsg, volatile_secure, .init = suite_preprocess_secure_submsg_init, .fini = suite_preprocess_secure_submsg_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatareaderCryptoHandle local_reader_crypto_vol; + DDS_Security_DatawriterCryptoHandle local_writer_crypto_vol; + DDS_Security_DatareaderCryptoHandle remote_reader_crypto_vol; + DDS_Security_DatawriterCryptoHandle remote_writer_crypto_vol; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_DatawriterCryptoHandle writer_crypto; + DDS_Security_DatareaderCryptoHandle reader_crypto; + DDS_Security_SecureSubmessageCategory_t category; + DDS_Security_CryptoTransformKeyId key_id = {0, 0, 0, 0}; + DDS_Security_OctetSeq message; + + CU_ASSERT_FATAL (crypto != NULL); + CU_ASSERT_FATAL (crypto->crypto_transform != NULL); + CU_ASSERT_FATAL (crypto->crypto_transform->preprocess_secure_submsg != NULL); + + datareader_properties._length = datareader_properties._maximum = 1; + datareader_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datareader_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datareader_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureReader"); + datareader_properties._buffer[0].propagate = false; + + prepare_endpoint_security_attributes( &datareader_security_attributes ); + prepare_endpoint_security_attributes( &datawriter_security_attributes ); + + datawriter_properties._length = datawriter_properties._maximum = 1; + datawriter_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datawriter_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datawriter_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureWriter"); + datawriter_properties._buffer[0].propagate = false; + + local_writer_crypto_vol = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + CU_ASSERT_FATAL(local_writer_crypto_vol != 0); + + local_reader_crypto_vol = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + CU_ASSERT_FATAL(local_reader_crypto_vol != 0); + + remote_writer_crypto_vol = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_crypto_vol, + remote_participant_handle, + shared_secret_handle, + &exception); + CU_ASSERT_FATAL(remote_writer_crypto_vol != 0); + + remote_reader_crypto_vol = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_crypto_vol, + remote_participant_handle, + shared_secret_handle, + true, + &exception); + CU_ASSERT_FATAL(remote_reader_crypto_vol != 0); + + create_encoded_submsg(&message, key_id, reader_key_message.transformation_kind, VALID_SMID_SEC_PREFIX, false); + + result = crypto->crypto_transform->preprocess_secure_submsg( + crypto->crypto_transform, + &writer_crypto, + &reader_crypto, + &category, + &message, + local_participant_handle, + remote_participant_handle, + &exception); + + if (!result) + printf("preprocess_secure_submsg: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + CU_ASSERT(((remote_datawriter_crypto *)writer_crypto)->is_builtin_participant_volatile_message_secure_writer); + CU_ASSERT(((local_datareader_crypto *)reader_crypto)->is_builtin_participant_volatile_message_secure_reader); + CU_ASSERT(category == DDS_SECURITY_DATAWRITER_SUBMESSAGE); + + reset_exception(&exception); + + if (remote_writer_crypto_vol) { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, remote_writer_crypto_vol, &exception); + reset_exception(&exception); + } + if (remote_reader_crypto_vol) { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, remote_reader_crypto_vol, &exception); + reset_exception(&exception); + } + if (local_reader_crypto_vol) { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_reader_crypto_vol, &exception); + reset_exception(&exception); + } + if (local_writer_crypto_vol) { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, local_writer_crypto_vol, &exception); + reset_exception(&exception); + } + + clear_encoded_submsg(&message); + DDS_Security_PropertySeq_deinit(&datareader_properties); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} diff --git a/src/security/builtin_plugins/tests/process_handshake/etc/trusted_ca_dir/identity_ca b/src/security/builtin_plugins/tests/process_handshake/etc/trusted_ca_dir/identity_ca new file mode 100644 index 0000000..f003d92 --- /dev/null +++ b/src/security/builtin_plugins/tests/process_handshake/etc/trusted_ca_dir/identity_ca @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkTCCAnmgAwIBAgIJAJvGJOEKNct1MA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV +BAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxGDAWBgNVBAMMD0NIQU01MDAgcm9vdCBjYTAeFw0xODAy +MTIxNTA1MDVaFw0yMDEyMDIxNTA1MDVaMF8xCzAJBgNVBAYTAk5MMRMwEQYDVQQI +DApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQx +GDAWBgNVBAMMD0NIQU01MDAgcm9vdCBjYTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAM/dCO4QAcCduw0NMqShDpTvGT6DClTFAJE8ZfuPCHKqNkicRbyj +sVXfF35Sdo6K92Ksz4G7i1RqJU2n8c7hg2EFUza0lIGgmTHV/DvFBcbAa0PpvdKS +XoPtSNDh65/GO1R7oeSFRzapqsLMPUwOWi46dYvRnPabxs21xHxn56JeuG74bad5 +PMTBvA2SiiTYPBlHGJS78GPo3BPMjL0MzPoMmumO8NSVYI+MEDY1lC4KkyZVKqtV +nIfaO/7adcM19xOAfAHkwhLGBC/bVAEqelev+GH/42xjNv532nM4/JVtBns+msR5 +DAYdtr6i82b7zhU1+lOOihv4lmQHoSnTya8CAwEAAaNQME4wHQYDVR0OBBYEFFYr +0CpiwxgFcZnW6IQEhxGv/vwiMB8GA1UdIwQYMBaAFFYr0CpiwxgFcZnW6IQEhxGv +/vwiMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKbBt0ht72fdtxwm +Kr0pOsKyDW0Rd5Ca5aDK4qAhDL0AD5+O6ShGYCnFNDGk3J5Yzawp8VoKrhDZZyUt +z2b0jNucVapAvPMA4066QxeIfvFmWcS73l7vjjeUoKWmNNGWprTg3RLsacTorKuY +ZRL7wsThfrhvg4B/OOIWKp5MEwIrUfnQzUca8getF2eyTt6QcMtE29AW5+01QTzj +fxZgzkmJFYBE2K/TLMDBDd+bz/8XnmPrJ01VUntXiXenTGTcIbJerB6GYQojjvhy +ZrOeuHTON1ndFiQkpeZA67ByZjkKVoJG3I8fwBjzcLE7u/QAQptVPjJXXcSpL7fA +a1tOvqw= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/process_handshake/etc/trusted_ca_dir/remote_identity_ca.crt b/src/security/builtin_plugins/tests/process_handshake/etc/trusted_ca_dir/remote_identity_ca.crt new file mode 100644 index 0000000..6b096a0 --- /dev/null +++ b/src/security/builtin_plugins/tests/process_handshake/etc/trusted_ca_dir/remote_identity_ca.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEKTCCAxGgAwIBAgIBATANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50 +aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu +Y29tMB4XDTE4MDMxMjAwMDAwMFoXDTI3MDMxMTIzNTk1OVowcjELMAkGA1UEBhMC +TkwxCzAJBgNVBAgTAk9WMRMwEQYDVQQKEwpBRExpbmsgSVNUMRkwFwYDVQQDExBJ +ZGVudGl0eSBDQSBUZXN0MSYwJAYJKoZIhvcNAQkBFhdpbmZvQGlzdC5hZGxpbmt0 +ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANa/ENFfGVXg +bPLTzBdDfiZQcp5dWZ//Pb8ErFOJu8uosVHFv8t69dgjHgNHB4OsjmjnR7GfKUZT +0cMvWJnjsC7DDlBwFET9rj4k40n96bbVCH9I7+tNhsoqzc6Eu+5h4sk7VfNGTM2Z +SyCd4GiSZRuA44rRbhXI7/LDpr4hY5J9ZDo5AM9ZyoLAoh774H3CZWD67S35XvUs +72dzE6uKG/vxBbvZ7eW2GLO6ewa9UxlnLVMPfJdpkp/xYXwwcPW2+2YXCge1ujxs +tjrOQJ5HUySh6DkE/kZpx8zwYWm9AaCrsvCIX1thsqgvKy+U5v1FS1L58eGc6s// +9yMgNhU29R0CAwEAAaOByTCBxjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRNVUJN +FzhJPReYT4QSx6dK53CXCTAfBgNVHSMEGDAWgBRNVUJNFzhJPReYT4QSx6dK53CX +CTAPBgNVHQ8BAf8EBQMDB/+AMGUGA1UdJQEB/wRbMFkGCCsGAQUFBwMBBggrBgEF +BQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkGCCsG +AQUFBwMNBggrBgEFBQcDDgYHKwYBBQIDBTANBgkqhkiG9w0BAQsFAAOCAQEAcOLF +ZYdJguj0uxeXB8v3xnUr1AWz9+gwg0URdfNLU2KvF2lsb/uznv6168b3/FcPgezN +Ihl9GqB+RvGwgXS/1UelCGbQiIUdsNxk246P4uOGPIyW32RoJcYPWZcpY+cw11tQ +NOnk994Y5/8ad1DmcxVLLqq5kwpXGWQufV1zOONq8B+mCvcVAmM4vkyF/de56Lwa +sAMpk1p77uhaDnuq2lIR4q3QHX2wGctFid5Q375DRscFQteY01r/dtwBBrMn0wuL +AMNx9ZGD+zAoOUaslpIlEQ+keAxk3jgGMWFMxF81YfhEnXzevSQXWpyek86XUyFL +O9IAQi5pa15gXjSbUg== +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/process_handshake/etc/trusted_ca_dir/root_CA_RSA.crt b/src/security/builtin_plugins/tests/process_handshake/etc/trusted_ca_dir/root_CA_RSA.crt new file mode 100644 index 0000000..61346df --- /dev/null +++ b/src/security/builtin_plugins/tests/process_handshake/etc/trusted_ca_dir/root_CA_RSA.crt @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEtjCCA56gAwIBAgIBATANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50 +aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu +Y29tMB4XDTE4MDYxMTAwMDAwMFoXDTI3MDYxMDIzNTk1OVowcjELMAkGA1UEBhMC +TkwxCzAJBgNVBAgTAk9WMRMwEQYDVQQKEwpBRExpbmsgSVNUMRkwFwYDVQQDExBJ +ZGVudGl0eSBDQSBUZXN0MSYwJAYJKoZIhvcNAQkBFhdpbmZvQGlzdC5hZGxpbmt0 +ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANRf3XKmM6O+ +WoYPNpOAdkGKKZHLJ8ZuPxVVBMX6oJAlcOmkhLzfkHSA+gl/OWaMOXIEtN512gyL +YszBf1RImwVzRjJFwIxzGzVQ68jYNj+qBbsOt+IG+hs3wgVCLFkCh+J7hXUgvk8A +eRM/SRrI42dQfcgKUAMNi4/iX6Vs+FV9pHB63L4PiLA9hfUE25sH6EsIC7icvGDJ +6cGG94glVSHDI1NtXfsNHY+NGY/jYKtQZklqU3lew5I60aJIsea+Wk6PJiz4hyXv +XVVmrcNeG1g4OEFgiSXZC2XknDw8t9+ELprGNvuJvTFxwPMAgLeF4IhEQC9dQY2W +BRwUxtZBzukCAwEAAaOCAVUwggFRMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFER4 +R6N3MQ1Wl7gn+R8wwHloDCVZMB8GA1UdIwQYMBaAFER4R6N3MQ1Wl7gn+R8wwHlo +DCVZMA8GA1UdDwEB/wQFAwMH/4Awge8GA1UdJQEB/wSB5DCB4QYIKwYBBQUHAwEG +CCsGAQUFBwMCBggrBgEFBQcDAwYIKwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3 +AgEVBgorBgEEAYI3AgEWBgorBgEEAYI3CgMBBgorBgEEAYI3CgMDBgorBgEEAYI3 +CgMEBglghkgBhvhCBAEGCysGAQQBgjcKAwQBBggrBgEFBQcDBQYIKwYBBQUHAwYG +CCsGAQUFBwMHBggrBgEFBQgCAgYKKwYBBAGCNxQCAgYIKwYBBQUHAwkGCCsGAQUF +BwMNBggrBgEFBQcDDgYHKwYBBQIDBTANBgkqhkiG9w0BAQsFAAOCAQEAwXuEWDG3 +aAyL+DsGr0B4YMLjHtx6FjzkJOpTtXQhkrtSMpD3Xytl7Wfz8lyWuTnbrk8F4gWO +IkJR/NdMGW27SmeYU0z7QAGRDwtHX6kqqizQbCwf4F6P/2QftcLp1VrlsIlb0gyx +gLjpGmn5TT7gj+ahW0iIRglOwhzCvkNu6agYpdGwVirSyLShy/Hq303DZSbVuktz +5/PmZKpufnoGqURNnJqbV4TQipE0FiDmp2o+gVgJ+DVRhiCdfk68Xp7+TlmxCDfZ +C3qb18qrwAZ4AL3T9/RlzfkXh4ME9V6wqa5Y6j7Vwx5Ef2OHL+mnMnoNSXDLRh6j +45ky66su5dROpA== +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/process_handshake/etc/trusted_ca_dir_not_matching/not_matching_trusted_ca.crt b/src/security/builtin_plugins/tests/process_handshake/etc/trusted_ca_dir_not_matching/not_matching_trusted_ca.crt new file mode 100644 index 0000000..35506b8 --- /dev/null +++ b/src/security/builtin_plugins/tests/process_handshake/etc/trusted_ca_dir_not_matching/not_matching_trusted_ca.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIENDCCAxygAwIBAgIBAjANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50 +aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu +Y29tMB4XDTE4MDYxMzAwMDAwMFoXDTI3MDYxMDIzNTk1OVowfTELMAkGA1UEBhMC +TkwxCzAJBgNVBAgTAk9WMRMwEQYDVQQKEwpBRExpbmsgSVNUMSQwIgYDVQQDExtJ +ZGVudGl0eSBDQSBUZXN0IFdpdGggQ2hhaW4xJjAkBgkqhkiG9w0BCQEWF2luZm9A +aXN0LmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA1r8Q0V8ZVeBs8tPMF0N+JlBynl1Zn/89vwSsU4m7y6ixUcW/y3r12CMeA0cH +g6yOaOdHsZ8pRlPRwy9YmeOwLsMOUHAURP2uPiTjSf3pttUIf0jv602GyirNzoS7 +7mHiyTtV80ZMzZlLIJ3gaJJlG4DjitFuFcjv8sOmviFjkn1kOjkAz1nKgsCiHvvg +fcJlYPrtLfle9SzvZ3MTq4ob+/EFu9nt5bYYs7p7Br1TGWctUw98l2mSn/FhfDBw +9bb7ZhcKB7W6PGy2Os5AnkdTJKHoOQT+RmnHzPBhab0BoKuy8IhfW2GyqC8rL5Tm +/UVLUvnx4Zzqz//3IyA2FTb1HQIDAQABo4HJMIHGMAwGA1UdEwQFMAMBAf8wHQYD +VR0OBBYEFE1VQk0XOEk9F5hPhBLHp0rncJcJMB8GA1UdIwQYMBaAFER4R6N3MQ1W +l7gn+R8wwHloDCVZMA8GA1UdDwEB/wQFAwMH/4AwZQYDVR0lAQH/BFswWQYIKwYB +BQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYIKwYBBQUHAwQGCCsGAQUFBwMIBggr +BgEFBQcDCQYIKwYBBQUHAw0GCCsGAQUFBwMOBgcrBgEFAgMFMA0GCSqGSIb3DQEB +CwUAA4IBAQCbl7ed4p66G6WquxO7ceZFvYKn3kDErjCfXHcqHxBnA2xTpoZCGj95 +Qpirqo6N4UcLX5sn3CmgyVk0dYvlti/53FJgZ9XQDNxBuEYWPkY7vO+Uo0WdYpGz +ZDNIUQpiPMA7bHvwKldTIs77xxtnw9kbBU2k0xQyb2tdZNfD5YqSI1MeUtpEpNFW +sbC8+mQ3clzWpjF8eHH1fFSAmlJ+z1Uqmtt2FK0vRz+MQcpydwvpMnfqGdcwhGPQ +X4HZreLObjBA8KUEkUB3+rZXuELBgkk/c8/jRZl7QF5jJDLQCCLg7KoYBKN2GuTt +/dzeSnP7VZm/nTL8wpCvKgSOwOGgklf2 +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/process_handshake/src/process_handshake_utests.c b/src/security/builtin_plugins/tests/process_handshake/src/process_handshake_utests.c new file mode 100644 index 0000000..d342cfb --- /dev/null +++ b/src/security/builtin_plugins/tests/process_handshake/src/process_handshake_utests.c @@ -0,0 +1,2438 @@ +#include +#include +#include + +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/openssl_support.h" +#include "common/src/handshake_helper.h" +#include "common/src/loader.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "config_env.h" + +#define HANDSHAKE_SIGNATURE_SIZE 6 + +static const char * AUTH_PROTOCOL_CLASS_ID = "DDS:Auth:PKI-DH:1.0"; +static const char * PERM_ACCESS_CLASS_ID = "DDS:Access:Permissions:1.0"; + +static const char * PROPERTY_IDENTITY_CA = "dds.sec.auth.identity_ca"; +static const char * PROPERTY_PRIVATE_KEY = "dds.sec.auth.private_key"; +static const char * PROPERTY_IDENTITY_CERT = "dds.sec.auth.identity_certificate"; +static const char * PROPERTY_TRUSTED_CA_DIR = "dds.sec.auth.trusted_ca_dir"; + +static const char * PROPERTY_CERT_SUBJECT_NAME = "dds.cert.sn"; +static const char * PROPERTY_CERT_ALGORITHM = "dds.cert.algo"; +static const char * PROPERTY_CA_SUBJECT_NAME = "dds.ca.sn"; +static const char * PROPERTY_CA_ALGORITHM = "dds.ca.aglo"; + +static const char * PROPERTY_PERM_CA_SUBJECT_NAME = "ds.perm_ca.sn"; + +static const char * SUBJECT_NAME_IDENTITY_CERT = "CN=CHAM-574 client,O=Some Company,ST=Some-State,C=NL"; +static const char * SUBJECT_NAME_IDENTITY_CA = "CN=CHAM-574 authority,O=Some Company,ST=Some-State,C=NL"; + +static const char * RSA_2048_ALGORITHM_NAME = "RSA-2048"; + +static const char * AUTH_REQUEST_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+AuthReq"; +static const char * AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME = "future_challenge"; + +static const char * AUTH_HANDSHAKE_REQUEST_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+Req"; +static const char * AUTH_HANDSHAKE_REPLY_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+Reply"; +static const char * AUTH_HANDSHAKE_FINAL_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+Final"; + +typedef enum { + HANDSHAKE_REQUEST, + HANDSHAKE_REPLY, + HANDSHAKE_FINAL +} HandshakeStep_t; + + +struct octet_seq { + unsigned char *data; + uint32_t length; +}; + +static const char * AUTH_DSIGN_ALGO_RSA_NAME = "RSASSA-PSS-SHA256"; +static const char * AUTH_KAGREE_ALGO_RSA_NAME = "DH+MODP-2048-256"; +static const char * AUTH_KAGREE_ALGO_ECDH_NAME = "ECDH+prime256v1-CEUM"; + + + +static const char *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-----\n"; + + +static const char *identity_ca = +"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-----\n"; + +static const char *remote_identity_certificate = +"-----BEGIN CERTIFICATE-----\n" +"MIIDcDCCAligAwIBAgIBBTANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL\n" +"MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50\n" +"aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu\n" +"Y29tMB4XDTE4MDMxMjAwMDAwMFoXDTI3MDMxMTIzNTk1OVowcDELMAkGA1UEBhMC\n" +"TkwxCzAJBgNVBAgTAk9WMQ8wDQYDVQQKEwZBRExpbmsxETAPBgNVBAsTCElTVCBU\n" +"ZXN0MREwDwYDVQQDEwhCb2IgVGVzdDEdMBsGCSqGSIb3DQEJARYOYm9iQGFkbGlu\n" +"ay5pc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDB5vqhuWnwhxXZ\n" +"qffPmfjzge7w91oX4ISlboIfBXp3sLj2mqLSsYhgBNJAn/Fl1OZeFw0d4gVibBgx\n" +"5Zdcjsi+ClvYK8H534iTJfNriMyhg4kSWxZF1Tixfw3FS7LqjKEY5ZNPfp5a4P+8\n" +"UveorYJusrnlv1DiF6aPhJQh8J62J6bhx62DNLO7dZbN0BUsnWtyDcfi5DOjf2/r\n" +"3lSRfecn3uBr1QYRaS5FrV+MSoGcjI3M75mei1TTUp7YT4ZWRR5rKUMql605xsms\n" +"d6sqJaKofYmw7wCuaVJ86pb/w8srdddKt21xUeQNMKn49H6raezMOE3U5BUMtZ+P\n" +"2OBLk/CPAgMBAAGjEzARMA8GA1UdDwEB/wQFAwMH/4AwDQYJKoZIhvcNAQELBQAD\n" +"ggEBAJV71Ckf1zsks5mJXqdUb8bTVHg4hN32pwjCL5c6W2XHAv+YHwE/fN3C1VIY\n" +"bC8zjUC9dCOyC2AvOQyZQ1eC/WoK6FlXjHVX2upL4lXQ9WL9ztt1mgdRrhvUPuUn\n" +"aBE8VgNU0t4jl93xMIaU8hB0kQsV+kdcN0cWbrF3mT4s9njRvopJ8hS2UE60V2wA\n" +"ceUOazH+QGPh1k0jkynrTlVR9GrpebQwZ2UFeinVO0km17IAyQkz+OmPc4jQLJMl\n" +"CmkbmMwowdLMKC6r/HyE87dN7NvFnRM5iByJklRwN7WDYZrl72HoUOlgTZ7PjW2G\n" +"jTxK8xXtDCXC/3CNpe0YFnOga8g=\n" +"-----END CERTIFICATE-----\n"; + + +static const char *private_key = + +"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-----\n"; + + +static char *remote_private_key = +"-----BEGIN RSA PRIVATE KEY-----\n" +"MIIEowIBAAKCAQEAweb6oblp8IcV2an3z5n484Hu8PdaF+CEpW6CHwV6d7C49pqi\n" +"0rGIYATSQJ/xZdTmXhcNHeIFYmwYMeWXXI7Ivgpb2CvB+d+IkyXza4jMoYOJElsW\n" +"RdU4sX8NxUuy6oyhGOWTT36eWuD/vFL3qK2CbrK55b9Q4hemj4SUIfCetiem4cet\n" +"gzSzu3WWzdAVLJ1rcg3H4uQzo39v695UkX3nJ97ga9UGEWkuRa1fjEqBnIyNzO+Z\n" +"notU01Ke2E+GVkUeaylDKpetOcbJrHerKiWiqH2JsO8ArmlSfOqW/8PLK3XXSrdt\n" +"cVHkDTCp+PR+q2nszDhN1OQVDLWfj9jgS5PwjwIDAQABAoIBAHfgWhED9VgL29le\n" +"uGMzmPLK4LM+6Qcb+kXghTeyhl1a928WeRVzRpG+SVJEz9QaBHYlICnaY2PO2kJ2\n" +"49YIPFkpRFDn9JuLs/7tFonj4Eb2cBbWE3YG9W7e0t+oBiv1117yB9m8uSAMPG7s\n" +"iEpTQvE3M7CzT8kHwCS4XXCCN0z7LqKyZ1heScjdfhV3D2TnFFjdtQ/9KfQa3hIc\n" +"6ftbpi4EKbfasspyqfrJ/cqjHzse9iEXLOZJhs+atBAKe/uJ4Hc3LRPbX4MPniAp\n" +"JJrldXFK9p+HILlbXvu+5n+DSGbZmT1x9a/E9suGyoJiASDH2Ax4yCVTi+v8C1R2\n" +"aKdU1LkCgYEA/3dFuM6zIHwiJ0GKT0gtJL6J3m+i51SNcRIm8deXt6HULMpUNajj\n" +"vZ1bgQm/h+uRBlPV3swkaVxvPTIabOTY4gmCBSzvVCSIAKHVc/+5Nkl9KruwSq4G\n" +"tctmXZ7ymMDi+6QGCJTJkAx6jptXyrzC00HOjXOwyQ+iDipqgr3A8FsCgYEAwk7B\n" +"2/hi569EIHFRT6nz/JMqQVPZ/MJDKoKhffTbnjQ5OAzpiVN6cyThMM1iVJEBFNhx\n" +"OEacy60Qj0TtR1oYrQSRSLm58TTxiuB4Pohbmg3iU+kSM/eTq/ups/Ul1oCs2eAb\n" +"POfweD3c4d4i7sN8bUNQXehiE4MOlK9TYQy39t0CgYAJht0mwy6S644qgJsz0bE9\n" +"SY3Cqc8daV3M9axWIIAb7QEImpMBXUcA7zlWWpK18ub5oW68XEiPVU8grRmnLfGY\n" +"nFoo70ANlz8rJt3a8ZJqn9r3GQC+CDdf2DH9E8xgPfE5CSjgcQwDPzPi1ZA0k02A\n" +"q1eUltfk55xXguVt8r2bOQKBgQC7+kldr1yv20VDRZ1uPnMGRLE6Zg6bkqw78gid\n" +"vEbDNK6uZP+BlTr/LgyVk/yu52Fucz6FPPrvqEw+7mXHA4ifya1r+BHFIn0S57os\n" +"dOp5jTkKCI9NqxQ3683vhRjH/dA7L63qLFDdYqvP74FID+LOKbMURn6rdbyjZ0J4\n" +"vz8yGQKBgHIzcKlQosRxf+KptOPMGRs30L9PnH+sNmTo2SmEzAGkBkt1msGRh/2l\n" +"uT3hOEhUXL9knRyXwQSXgrIwr9QwI5rGS5FAgX26TgBtPBDs2NuyyhhS5yxsiEPT\n" +"BR+EjQFW9dzRkpRJgvsG4DcNAhFn7fQqFNcWXgFWuBXmGNkdtEGR\n" +"-----END RSA PRIVATE KEY-----"; + +static const char *unrelated_identity = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIDpDCCAoygAwIBAgIJALE5lRKfYHAaMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV\n" + "BAYTAk5MMRMwEQYDVQQIDApPdmVyaWpzc2VsMRAwDgYDVQQHDAdIZW5nZWxvMQ8w\n" + "DQYDVQQKDAZBRExJTksxGDAWBgNVBAMMD0NIQU01MDAgUm9vdCBDQTAeFw0xODAy\n" + "MDkxNjIwNDNaFw0zODAyMDQxNjIwNDNaMF8xCzAJBgNVBAYTAk5MMRMwEQYDVQQI\n" + "DApPdmVyaWpzc2VsMRAwDgYDVQQHDAdIZW5nZWxvMQ8wDQYDVQQKDAZBRExJTksx\n" + "GDAWBgNVBAMMD0NIQU01MDAgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" + "ADCCAQoCggEBAN9/NbpJDHQYHh3cEByRxnHffxEe9Sapn08Ty5xYO8LDJ4V7vU32\n" + "/7291fITiHaovOoCRHAbKTaTtqJO56aGY45HON6KIqxljLQJJVGW/Nf2PNSHmFix\n" + "6D6bsoSOTPyKYqBNT6lB7NMn4QBTcsiE61El8p9WLQZHoYQJK5Psf7wkBqGBz8he\n" + "bcDWXFn7kIgnsaLrh77w2wi/y0MqpPwyeRInoZfYknzVNdxCPgq7csBYDoMgOgkV\n" + "G60ECXojHKz1HI4n0V8L8lZluSSVRNR0xvPFgBqO7b+Re7xb6iO9TNsFeoiMMNyp\n" + "EwM99CqPO0RRrAPiC7IDgcNGjxhne9EJFGsCAwEAAaNjMGEwHQYDVR0OBBYEFCst\n" + "gj5Ecm3HU/N7wxJluFo5+6XUMB8GA1UdIwQYMBaAFCstgj5Ecm3HU/N7wxJluFo5\n" + "+6XUMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB\n" + "CwUAA4IBAQCWibvYuPLpoNcsUdHbE7SnBbEQnDfBxBZN8xeWHwwAPEB+8eHhmIdZ\n" + "xDtCN61xr5QR+KzlEYFwKyHMp9GN3OPU1RndJrzaXz2ddAZVkBIvnQZ4JvFd+sBC\n" + "QQgEvL8GcwZPxnad/TRylM4ON3Kh0X9vfyrmWEoHephiE1LcENaFqcYr9xg3DJNh\n" + "XSrigMGZJ7IOHkvgaoneICOcYI42ZHS0fnt1G+01VKJXm3ndi5NL25GnOmlvV6yV\n" + "+1vcmdQc6YS8K8vHmrH4lX9iPfsOak6WSzzsXdqgpvyxtGJggcFaDTtmbWCAkJj0\n" + "B7DMeaVlLClGQaKZZ7aexEx9se+IyLn2\n" + "-----END CERTIFICATE-----\n"; + + +static const char *remote_identity_trusted = + "-----BEGIN CERTIFICATE-----\n" + "MIIDcDCCAligAwIBAgIBBTANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL\n" + "MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50\n" + "aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu\n" + "Y29tMB4XDTE4MDMxMjAwMDAwMFoXDTI3MDMxMTIzNTk1OVowcDELMAkGA1UEBhMC\n" + "TkwxCzAJBgNVBAgTAk9WMQ8wDQYDVQQKEwZBRExpbmsxETAPBgNVBAsTCElTVCBU\n" + "ZXN0MREwDwYDVQQDEwhCb2IgVGVzdDEdMBsGCSqGSIb3DQEJARYOYm9iQGFkbGlu\n" + "ay5pc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDB5vqhuWnwhxXZ\n" + "qffPmfjzge7w91oX4ISlboIfBXp3sLj2mqLSsYhgBNJAn/Fl1OZeFw0d4gVibBgx\n" + "5Zdcjsi+ClvYK8H534iTJfNriMyhg4kSWxZF1Tixfw3FS7LqjKEY5ZNPfp5a4P+8\n" + "UveorYJusrnlv1DiF6aPhJQh8J62J6bhx62DNLO7dZbN0BUsnWtyDcfi5DOjf2/r\n" + "3lSRfecn3uBr1QYRaS5FrV+MSoGcjI3M75mei1TTUp7YT4ZWRR5rKUMql605xsms\n" + "d6sqJaKofYmw7wCuaVJ86pb/w8srdddKt21xUeQNMKn49H6raezMOE3U5BUMtZ+P\n" + "2OBLk/CPAgMBAAGjEzARMA8GA1UdDwEB/wQFAwMH/4AwDQYJKoZIhvcNAQELBQAD\n" + "ggEBAJV71Ckf1zsks5mJXqdUb8bTVHg4hN32pwjCL5c6W2XHAv+YHwE/fN3C1VIY\n" + "bC8zjUC9dCOyC2AvOQyZQ1eC/WoK6FlXjHVX2upL4lXQ9WL9ztt1mgdRrhvUPuUn\n" + "aBE8VgNU0t4jl93xMIaU8hB0kQsV+kdcN0cWbrF3mT4s9njRvopJ8hS2UE60V2wA\n" + "ceUOazH+QGPh1k0jkynrTlVR9GrpebQwZ2UFeinVO0km17IAyQkz+OmPc4jQLJMl\n" + "CmkbmMwowdLMKC6r/HyE87dN7NvFnRM5iByJklRwN7WDYZrl72HoUOlgTZ7PjW2G\n" + "jTxK8xXtDCXC/3CNpe0YFnOga8g=\n" + "-----END CERTIFICATE-----\n"; + +static const char *remote_identity_untrusted = + "-----BEGIN CERTIFICATE-----\n" + "MIIELTCCAxWgAwIBAgIBATANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJOTDEL\n" + "MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGzAZBgNVBAMTEkJvYiBU\n" + "ZXN0IFVudHJ1c3RlZDEmMCQGCSqGSIb3DQEJARYXaW5mb0Bpc3QuYWRsaW5rdGVj\n" + "aC5jb20wHhcNMTgwNjIwMDAwMDAwWhcNMjcwNjE5MjM1OTU5WjB0MQswCQYDVQQG\n" + "EwJOTDELMAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGzAZBgNVBAMT\n" + "EkJvYiBUZXN0IFVudHJ1c3RlZDEmMCQGCSqGSIb3DQEJARYXaW5mb0Bpc3QuYWRs\n" + "aW5rdGVjaC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDB5vqh\n" + "uWnwhxXZqffPmfjzge7w91oX4ISlboIfBXp3sLj2mqLSsYhgBNJAn/Fl1OZeFw0d\n" + "4gVibBgx5Zdcjsi+ClvYK8H534iTJfNriMyhg4kSWxZF1Tixfw3FS7LqjKEY5ZNP\n" + "fp5a4P+8UveorYJusrnlv1DiF6aPhJQh8J62J6bhx62DNLO7dZbN0BUsnWtyDcfi\n" + "5DOjf2/r3lSRfecn3uBr1QYRaS5FrV+MSoGcjI3M75mei1TTUp7YT4ZWRR5rKUMq\n" + "l605xsmsd6sqJaKofYmw7wCuaVJ86pb/w8srdddKt21xUeQNMKn49H6raezMOE3U\n" + "5BUMtZ+P2OBLk/CPAgMBAAGjgckwgcYwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU\n" + "QpxLPHT5o/GQRwdBw2scINXnWlUwHwYDVR0jBBgwFoAUQpxLPHT5o/GQRwdBw2sc\n" + "INXnWlUwDwYDVR0PAQH/BAUDAwf/gDBlBgNVHSUBAf8EWzBZBggrBgEFBQcDAQYI\n" + "KwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwgGCCsGAQUFBwMJ\n" + "BggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggEB\n" + "ABcyab7F7OAsjUSW0YWkVRX1SUMkW25xLLs8koXhHrdnBqgnmOur0xO72/fmTTX9\n" + "KnCUmQj+dAOmmZrAaIZzqLtMyp4ibHZPfOBwmM0MFnyuwyEnCEYvjPN3FTB0HEgS\n" + "vCoFH1001LVi4oC1mEMxYaNW4/5Tgl+DTqGF+tctJe3hvbxh+Uu5M0320VAvASjt\n" + "cJ0me6Ug1FJJ60tgXgZ+M/8V6AXhrQGNgN6WkPMFbbLi5IyEld186QPeLdZ8vCtz\n" + "StjIV9HZGR1XLotlXarbjVtjxavZJjtwiySeYkAgG7Zjy7LalPSJiIdAD3R/ny+S\n" + "9kXDKiw/HgYxb8xiy9gdlSc=\n" + "-----END CERTIFICATE-----\n"; + + +static const char *remote_identity_trusted_expired = + "-----BEGIN CERTIFICATE-----\n" + "MIIEKTCCAxGgAwIBAgIBBjANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL\n" + "MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50\n" + "aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu\n" + "Y29tMB4XDTE4MDMwMTAwMDAwMFoXDTE4MDQyMzIzNTk1OVowcjELMAkGA1UEBhMC\n" + "TkwxCzAJBgNVBAgTAk9WMRMwEQYDVQQKEwpBRExpbmsgSVNUMRkwFwYDVQQDExBC\n" + "b2IgVGVzdCBFeHBpcmVkMSYwJAYJKoZIhvcNAQkBFhdpbmZvQGlzdC5hZGxpbmt0\n" + "ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMHm+qG5afCH\n" + "Fdmp98+Z+POB7vD3WhfghKVugh8FenewuPaaotKxiGAE0kCf8WXU5l4XDR3iBWJs\n" + "GDHll1yOyL4KW9grwfnfiJMl82uIzKGDiRJbFkXVOLF/DcVLsuqMoRjlk09+nlrg\n" + "/7xS96itgm6yueW/UOIXpo+ElCHwnrYnpuHHrYM0s7t1ls3QFSyda3INx+LkM6N/\n" + "b+veVJF95yfe4GvVBhFpLkWtX4xKgZyMjczvmZ6LVNNSnthPhlZFHmspQyqXrTnG\n" + "yax3qyoloqh9ibDvAK5pUnzqlv/Dyyt110q3bXFR5A0wqfj0fqtp7Mw4TdTkFQy1\n" + "n4/Y4EuT8I8CAwEAAaOByTCBxjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRCnEs8\n" + "dPmj8ZBHB0HDaxwg1edaVTAfBgNVHSMEGDAWgBRNVUJNFzhJPReYT4QSx6dK53CX\n" + "CTAPBgNVHQ8BAf8EBQMDB/+AMGUGA1UdJQEB/wRbMFkGCCsGAQUFBwMBBggrBgEF\n" + "BQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkGCCsG\n" + "AQUFBwMNBggrBgEFBQcDDgYHKwYBBQIDBTANBgkqhkiG9w0BAQsFAAOCAQEAdY5n\n" + "5ElOhpHq/YPWUs68t8HNIhqfokqjLZAgzNyU5QFppb9tPpmFCugerfjlScNwp5HB\n" + "X6/WjK4runDrgzXfmrBogR4Kscb1KJSm8KAmnzXVUNr1iyASlHxI7241kYdQvTH2\n" + "LL6b0kjsD5lKAnNh4id0SDHfy/CKg5d7dUxxO1mX48jUiIZtmFqgjej8tFLHy/w/\n" + "usI5ErlI0qzI6lkoRxPCEWLbXWeBDm3/smHeDbYa/+Lw4Bid8U1+ZSAuC1CT7a7F\n" + "O3gAjPUL0jzRztp5Yj3dYPV8YyJHLEKr75IXNedV9YKhT4f6kTS3UEjMTqYbYsix\n" + "MtqgY283RjsExzjNvw==\n" + "-----END CERTIFICATE-----\n"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_authentication *auth = NULL; +static DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_IdentityHandle remote_identity_handle1 = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_IdentityHandle remote_identity_handle2 = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_AuthRequestMessageToken g_local_auth_request_token = DDS_SECURITY_TOKEN_INIT; +static DDS_Security_AuthRequestMessageToken g_remote_auth_request_token = DDS_SECURITY_TOKEN_INIT; +static const DDS_Security_BinaryProperty_t *challenge1_predefined_glb = NULL; +static const DDS_Security_BinaryProperty_t *challenge2_predefined_glb = NULL; +static DDS_Security_OctetSeq serialized_participant_data = DDS_SECURITY_SEQUENCE_INIT; +static DDS_Security_ParticipantBuiltinTopicData *remote_participant_data1 = NULL; +static DDS_Security_ParticipantBuiltinTopicData *remote_participant_data2 = NULL; +static DDS_Security_ParticipantBuiltinTopicData *remote_participant_data3 = NULL; +static DDS_Security_GUID_t candidate_participant_guid; +static DDS_Security_GUID_t remote_participant_guid1; +static DDS_Security_GUID_t remote_participant_guid2; + +static EVP_PKEY *dh_modp_key = NULL; +static EVP_PKEY *dh_ecdh_key = NULL; +static struct octet_seq dh_modp_pub_key = {NULL, 0}; +static struct octet_seq dh_ecdh_pub_key = {NULL, 0}; +static struct octet_seq invalid_dh_pub_key = {NULL, 0}; + + +static void +octet_seq_init( + struct octet_seq *seq, + unsigned char *data, + uint32_t size) +{ + seq->data = ddsrt_malloc(size); + memcpy(seq->data, data, size); + seq->length = size; +} + +static void +octet_seq_deinit( + struct octet_seq *seq) +{ + ddsrt_free(seq->data); +} + +static void +serializer_participant_data( + DDS_Security_ParticipantBuiltinTopicData *pdata, + unsigned char **buffer, + size_t *size); + +static void +dds_security_property_init( + DDS_Security_PropertySeq *seq, + DDS_Security_unsigned_long size) +{ + seq->_length = size; + seq->_maximum = size; + seq->_buffer = ddsrt_malloc(size * sizeof(DDS_Security_Property_t)); + memset(seq->_buffer, 0, size * sizeof(DDS_Security_Property_t)); +} + +static void +dds_security_property_deinit( + DDS_Security_PropertySeq *seq) +{ + uint32_t i; + + for (i = 0; i < seq->_length; i++) { + ddsrt_free(seq->_buffer[i].name); + ddsrt_free(seq->_buffer[i].value); + } + ddsrt_free(seq->_buffer); +} + +static void +reset_exception( + DDS_Security_SecurityException *ex) +{ + ex->minor_code = 0; + ex->code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void +initialize_identity_token( + DDS_Security_IdentityToken *token, + const char *certAlgo, + const char *caAlgo) +{ + memset(token, 0, sizeof(*token)); + + token->class_id = ddsrt_strdup(AUTH_PROTOCOL_CLASS_ID); + token->properties._maximum = 4; + token->properties._length = 4; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(4); + + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_CERT_SUBJECT_NAME); + token->properties._buffer[0].value = ddsrt_strdup(SUBJECT_NAME_IDENTITY_CERT); + token->properties._buffer[0].propagate = true; + + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_CERT_ALGORITHM); + token->properties._buffer[1].value = ddsrt_strdup(certAlgo); + token->properties._buffer[1].propagate = true; + + token->properties._buffer[2].name = ddsrt_strdup(PROPERTY_CA_SUBJECT_NAME); + token->properties._buffer[2].value = ddsrt_strdup(SUBJECT_NAME_IDENTITY_CA); + token->properties._buffer[2].propagate = true; + + token->properties._buffer[3].name = ddsrt_strdup(PROPERTY_CA_ALGORITHM); + token->properties._buffer[3].value = ddsrt_strdup(caAlgo); + token->properties._buffer[3].propagate = true; +} + +static void +initialize_permissions_token( + DDS_Security_PermissionsToken *token, + const char *caAlgo) +{ + token->class_id = ddsrt_strdup(PERM_ACCESS_CLASS_ID); + token->properties._length = 2; + token->properties._maximum = 2; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(4); + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_CERT_SUBJECT_NAME); + token->properties._buffer[0].value = ddsrt_strdup(SUBJECT_NAME_IDENTITY_CA); + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_PERM_CA_SUBJECT_NAME); + token->properties._buffer[1].value = ddsrt_strdup(caAlgo); +} + + + +static void +fill_auth_request_token( + DDS_Security_AuthRequestMessageToken *token) +{ + uint32_t i; + uint32_t len = 32; + unsigned char *challenge; + + challenge = ddsrt_malloc(len); + + for (i = 0; i < len; i++) { + challenge[i] = (unsigned char)(0xFF - i); + } + + memset(token, 0, sizeof(*token)); + + token->class_id = ddsrt_strdup(AUTH_REQUEST_TOKEN_CLASS_ID); + token->binary_properties._maximum = 1; + token->binary_properties._length = 1; + token->binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + token->binary_properties._buffer->name = ddsrt_strdup(AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + + token->binary_properties._buffer->value._maximum = len; + token->binary_properties._buffer->value._length = len; + token->binary_properties._buffer->value._buffer = challenge; +} + + +static DDS_Security_BinaryProperty_t * +find_binary_property( + DDS_Security_DataHolder *token, + const char *name) +{ + DDS_Security_BinaryProperty_t *result = NULL; + uint32_t i; + + for (i = 0; i < token->binary_properties._length && !result; i++) { + if (token->binary_properties._buffer[i].name && (strcmp(token->binary_properties._buffer[i].name, name) == 0)) { + result = &token->binary_properties._buffer[i]; + } + } + + return result; +} + +static void +deinitialize_identity_token( + DDS_Security_IdentityToken *token) +{ + DDS_Security_DataHolder_deinit(token); +} + +static int +validate_local_identity(const char* trusted_ca_dir) +{ + int res = 0; + DDS_Security_ValidationResult_t result; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GUID_t local_participant_guid; + DDS_Security_GuidPrefix_t prefix = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb}; + DDS_Security_EntityId_t entityId = {{0xb0,0xb1,0xb2},0x1}; + DDS_Security_ParticipantBuiltinTopicData *local_participant_data; + unsigned char *sdata; + size_t size; + + memset(&local_participant_guid, 0, sizeof(local_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + memset(&participant_qos, 0, sizeof(participant_qos)); + if( trusted_ca_dir != NULL){ + char trusted_ca_dir_path[1024]; + dds_security_property_init(&participant_qos.property.value, 4); +#ifdef WIN32 + snprintf(trusted_ca_dir_path, 1024, "%s\\validate_begin_handshake_reply\\etc\\%s", CONFIG_ENV_TESTS_DIR, trusted_ca_dir); +#else + snprintf(trusted_ca_dir_path, 1024, "%s/validate_begin_handshake_reply/etc/%s", CONFIG_ENV_TESTS_DIR, trusted_ca_dir); +#endif + participant_qos.property.value._buffer[3].name = ddsrt_strdup(PROPERTY_TRUSTED_CA_DIR); + participant_qos.property.value._buffer[3].value = ddsrt_strdup(trusted_ca_dir_path); + } + else{ + dds_security_property_init(&participant_qos.property.value, 3); + } + participant_qos.property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + participant_qos.property.value._buffer[0].value = ddsrt_strdup(identity_certificate); + participant_qos.property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + participant_qos.property.value._buffer[1].value = ddsrt_strdup(identity_ca); + participant_qos.property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + participant_qos.property.value._buffer[2].value = ddsrt_strdup(private_key); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &local_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + res = -1; + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + local_participant_data = DDS_Security_ParticipantBuiltinTopicData_alloc(); + memcpy(&local_participant_data->key[0], &local_participant_guid, 12); + /* convert from big-endian format to native format */ + local_participant_data->key[0] = ddsrt_fromBE4u(local_participant_data->key[0]); + local_participant_data->key[1] = ddsrt_fromBE4u(local_participant_data->key[1]); + local_participant_data->key[2] = ddsrt_fromBE4u(local_participant_data->key[2]); + + initialize_identity_token(&local_participant_data->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + initialize_permissions_token(&local_participant_data->permissions_token, RSA_2048_ALGORITHM_NAME); + + local_participant_data->security_info.participant_security_attributes = 0x01; + local_participant_data->security_info.plugin_participant_security_attributes = 0x02; + + serializer_participant_data(local_participant_data, &sdata, &size); + + serialized_participant_data._length = serialized_participant_data._maximum = (DDS_Security_unsigned_long) size; + serialized_participant_data._buffer = sdata; + + DDS_Security_ParticipantBuiltinTopicData_free(local_participant_data); + + return res; +} + +static void +release_local_identity(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (local_identity_handle != DDS_SECURITY_HANDLE_NIL) { + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } + + DDS_Security_OctetSeq_deinit(&serialized_participant_data); +} + +static X509 * +load_certificate( + const char *data) +{ + X509 *cert = NULL; + BIO *bio; + + bio = BIO_new_mem_buf((void *) data, -1); + if (!bio) { + return NULL; + } + + cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); + + BIO_free(bio); + + return cert; +} + +static int +get_adjusted_participant_guid( + X509 *cert, + const DDS_Security_GUID_t *candidate, + DDS_Security_GUID_t *adjusted) +{ + int result = 0; + unsigned char high[SHA256_DIGEST_LENGTH], low[SHA256_DIGEST_LENGTH]; + unsigned char *subject; + DDS_Security_octet hb = 0x80; + X509_NAME *name; + unsigned char *tmp = NULL; + int i, sz; + + name = X509_get_subject_name(cert); + sz = i2d_X509_NAME(name, &tmp); + if (sz > 0) { + subject = ddsrt_malloc( (size_t)sz); + memcpy(subject, tmp, (size_t)sz); + OPENSSL_free(tmp); + + SHA256(subject, (size_t)sz, high); + SHA256(&candidate->prefix[0], sizeof(DDS_Security_GuidPrefix_t), low); + + adjusted->entityId = candidate->entityId; + for (i = 0; i < 6; i++) { + adjusted->prefix[i] = hb | high[i]>>1; + hb = (DDS_Security_octet)(high[i]<<7); + } + for (i = 0; i < 6; i++) { + adjusted->prefix[i+6] = low[i]; + } + ddsrt_free(subject); + result = 1; + } + + return result; +} + +static int +create_dh_key_modp_2048( + EVP_PKEY **pkey) +{ + int r = 0; + EVP_PKEY *params = NULL; + EVP_PKEY_CTX *kctx = NULL; + DH *dh = NULL; + + *pkey = NULL; + + if ((params = EVP_PKEY_new()) == NULL) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate EVP_PKEY: %s", msg); + ddsrt_free(msg); + r = -1; + } else if ((dh = DH_get_2048_256()) == NULL) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate DH parameter: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_set1_DH(params, dh) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to set DH parameter to MODP_2048_256: %s", msg); + ddsrt_free(msg); + r = -1; + } else if ((kctx = EVP_PKEY_CTX_new(params, NULL)) == NULL) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate KEY context %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_keygen_init(kctx) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to initialize KEY context: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_keygen(kctx, pkey) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to generate :MODP_2048_256 keys %s", msg); + ddsrt_free(msg); + r = -1; + } + + if (params) EVP_PKEY_free(params); + if (kctx) EVP_PKEY_CTX_free(kctx); + if (dh) DH_free(dh); + + return r; +} + +static int +get_dh_public_key_modp_2048( + EVP_PKEY *pkey, + struct octet_seq *pubkey) +{ + int r = 0; + DH *dhkey; + unsigned char *buffer = NULL; + uint32_t size; + ASN1_INTEGER *asn1int; + + dhkey = EVP_PKEY_get1_DH(pkey); + if (!dhkey) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to get DH key from PKEY: %s", msg); + ddsrt_free(msg); + r = -1; + goto fail_get_dhkey; + } + + asn1int = BN_to_ASN1_INTEGER( dh_get_public_key(dhkey) , NULL); + if (!asn1int) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to convert DH key to ASN1 integer: %s", msg); + ddsrt_free(msg); + r = -1; + goto fail_get_pubkey; + } + + size = (uint32_t) i2d_ASN1_INTEGER(asn1int, &buffer); + octet_seq_init(pubkey, buffer, size); + + ASN1_INTEGER_free(asn1int); + OPENSSL_free(buffer); + +fail_get_pubkey: + DH_free(dhkey); +fail_get_dhkey: + return r; +} + +static int +create_dh_key_ecdh( + EVP_PKEY **pkey) +{ + int r = 0; + EVP_PKEY *params = NULL; + EVP_PKEY_CTX *pctx = NULL; + EVP_PKEY_CTX *kctx = NULL; + + *pkey = NULL; + + if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate DH parameter context: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_paramgen_init(pctx) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to initialize DH generation context: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to set DH generation parameter generation method: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_paramgen(pctx, ¶ms) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to generate DH parameters: %s", msg); + ddsrt_free(msg); + r = -1; + } else if ((kctx = EVP_PKEY_CTX_new(params, NULL)) == NULL) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to allocate KEY context %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_keygen_init(kctx) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to initialize KEY context: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (EVP_PKEY_keygen(kctx, pkey) <= 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to generate :MODP_2048_256 keys %s", msg); + ddsrt_free(msg); + r = -1; + } + + if (kctx) EVP_PKEY_CTX_free(kctx); + if (params) EVP_PKEY_free(params); + if (pctx) EVP_PKEY_CTX_free(pctx); + + return r; +} + +static int +get_dh_public_key_ecdh( + EVP_PKEY *pkey, + struct octet_seq *pubkey) +{ + int r = 0; + EC_KEY *eckey = NULL; + const EC_GROUP *group = NULL; + const EC_POINT *point = NULL; + size_t sz; + + if (!(eckey = EVP_PKEY_get1_EC_KEY(pkey))) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to get EC key from PKEY: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (!(point = EC_KEY_get0_public_key(eckey))) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to get public key from ECKEY: %s", msg); + ddsrt_free(msg); + r = -1; + } else if (!(group = EC_KEY_get0_group(eckey))) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to get group from ECKEY: %s", msg); + ddsrt_free(msg); + r = -1; + } else if ((sz = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, NULL, 0, NULL)) != 0) { + pubkey->data = ddsrt_malloc(sz); + pubkey->length = (uint32_t) EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED, pubkey->data, sz, NULL); + if (pubkey->length == 0) { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to serialize public EC key: %s", msg); + ddsrt_free(msg); + octet_seq_deinit(pubkey); + r = -1; + } + } else { + char *msg = get_openssl_error_message_for_test(); + printf("Failed to serialize public EC key: %s", msg); + ddsrt_free(msg); + r = -1; + } + + if (eckey) EC_KEY_free(eckey); + + return r; +} + +static int +validate_remote_identities (const char *remote_id_certificate) +{ + int res = 0; + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityToken remote_identity_token; + static DDS_Security_AuthRequestMessageToken local_auth_request_token = DDS_SECURITY_TOKEN_INIT; + DDS_Security_GUID_t guid1; + DDS_Security_GUID_t guid2; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix1 = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab}; + DDS_Security_GuidPrefix_t prefix2 = {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb}; + DDS_Security_EntityId_t entityId = {{0xb0,0xb1,0xb2},0x1}; + X509 *cert; + + memcpy(&guid1.prefix, &prefix1, sizeof(prefix1)); + memcpy(&guid1.entityId, &entityId, sizeof(entityId)); + memcpy(&guid2.prefix, &prefix2, sizeof(prefix2)); + memcpy(&guid2.entityId, &entityId, sizeof(entityId)); + + if (local_identity_handle == DDS_SECURITY_HANDLE_NIL) { + return -1; + } + + cert = load_certificate(remote_id_certificate); + if (!cert) { + return -1; + } + + if (!get_adjusted_participant_guid(cert, &guid1, &remote_participant_guid1)) { + X509_free(cert); + return -1; + } + + if (!get_adjusted_participant_guid(cert, &guid2, &remote_participant_guid2)) { + X509_free(cert); + return -1; + } + + X509_free(cert); + + initialize_identity_token(&remote_identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle1, + &g_local_auth_request_token, + NULL, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid1, + &exception); + + if ((result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST) && + (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE)) { + printf("validate_remote_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + reset_exception(&exception); + + fill_auth_request_token(&g_remote_auth_request_token); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle2, + &local_auth_request_token, + &g_remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid2, + &exception); + + if ((result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST) && + (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE)) { + printf("validate_remote_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + reset_exception(&exception); + + deinitialize_identity_token(&remote_identity_token); + DDS_Security_DataHolder_deinit(&local_auth_request_token); + + remote_participant_data1 = DDS_Security_ParticipantBuiltinTopicData_alloc(); + memcpy(&remote_participant_data1->key[0], &remote_participant_guid1, 12); + remote_participant_data1->key[0] = ddsrt_fromBE4u(remote_participant_data1->key[0]); + remote_participant_data1->key[1] = ddsrt_fromBE4u(remote_participant_data1->key[1]); + remote_participant_data1->key[2] = ddsrt_fromBE4u(remote_participant_data1->key[2]); + + initialize_identity_token(&remote_participant_data1->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + initialize_permissions_token(&remote_participant_data1->permissions_token, RSA_2048_ALGORITHM_NAME); + + remote_participant_data1->security_info.participant_security_attributes = 0x01; + remote_participant_data1->security_info.plugin_participant_security_attributes = 0x02; + + remote_participant_data2 = DDS_Security_ParticipantBuiltinTopicData_alloc(); + memcpy(&remote_participant_data2->key[0], &remote_participant_guid2, 12); + remote_participant_data2->key[0] = ddsrt_fromBE4u(remote_participant_data2->key[0]); + remote_participant_data2->key[1] = ddsrt_fromBE4u(remote_participant_data2->key[1]); + remote_participant_data2->key[2] = ddsrt_fromBE4u(remote_participant_data2->key[2]); + + initialize_identity_token(&remote_participant_data2->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + initialize_permissions_token(&remote_participant_data2->permissions_token, RSA_2048_ALGORITHM_NAME); + + remote_participant_data2->security_info.participant_security_attributes = 0x01; + remote_participant_data2->security_info.plugin_participant_security_attributes = 0x02; + + remote_participant_data3 = DDS_Security_ParticipantBuiltinTopicData_alloc(); + memcpy(&remote_participant_data3->key[0], &candidate_participant_guid, 12); + + initialize_identity_token(&remote_participant_data3->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + initialize_permissions_token(&remote_participant_data3->permissions_token, RSA_2048_ALGORITHM_NAME); + + remote_participant_data2->security_info.participant_security_attributes = 0x01; + remote_participant_data2->security_info.plugin_participant_security_attributes = 0x02; + + challenge1_predefined_glb = find_binary_property(&g_remote_auth_request_token, AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + challenge2_predefined_glb = challenge1_predefined_glb; + + return res; +} + +static void +release_remote_identities(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL) { + success = auth->return_identity_handle(auth, remote_identity_handle1, &exception); + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } + if (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL) { + success = auth->return_identity_handle(auth, remote_identity_handle2, &exception); + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } + + DDS_Security_DataHolder_deinit(&g_local_auth_request_token); + DDS_Security_DataHolder_deinit(&g_remote_auth_request_token); + + DDS_Security_ParticipantBuiltinTopicData_free(remote_participant_data1); + DDS_Security_ParticipantBuiltinTopicData_free(remote_participant_data2); + DDS_Security_ParticipantBuiltinTopicData_free(remote_participant_data3); +} + +CU_Init(ddssec_builtin_process_handshake) +{ + int result = 0; + dds_openssl_init (); + + /* Only need the authentication plugin. */ + plugins = load_plugins(NULL /* Access Control */, + &auth /* Authentication */, + NULL /* Cryptograpy */); + if (plugins) { + result = validate_local_identity( NULL ); + if (result >= 0) { + result = validate_remote_identities( remote_identity_certificate ); + } + if (result >= 0) { + result = create_dh_key_modp_2048(&dh_modp_key); + } + if (result >= 0) { + result = get_dh_public_key_modp_2048(dh_modp_key, &dh_modp_pub_key); + } + if (result >= 0) { + result = create_dh_key_ecdh(&dh_ecdh_key); + } + if (result >= 0) { + result = get_dh_public_key_ecdh(dh_ecdh_key, &dh_ecdh_pub_key); + } + if (result >= 0) { + octet_seq_init(&invalid_dh_pub_key, dh_modp_pub_key.data, dh_modp_pub_key.length); + invalid_dh_pub_key.data[0] = 0x08; + } + } else { + result = -1; + } + + + return result; +} + +CU_Clean(ddssec_builtin_process_handshake) +{ + release_local_identity(); + release_remote_identities(); + unload_plugins(plugins); + octet_seq_deinit(&dh_modp_pub_key); + octet_seq_deinit(&dh_ecdh_pub_key); + octet_seq_deinit(&invalid_dh_pub_key); + if (dh_modp_key) { + EVP_PKEY_free(dh_modp_key); + } + if (dh_ecdh_key) { + EVP_PKEY_free(dh_ecdh_key); + } + return 0; +} + +static bool +compare_octet_seq( + const DDS_Security_OctetSeq *seq1, + const DDS_Security_OctetSeq *seq2) +{ + int r; + if (seq1 && seq2) { + r = (int)(seq2->_length - seq1->_length); + if (r == 0) { + r = memcmp(seq1->_buffer, seq2->_buffer, seq1->_length); + } + } else if (seq1 == seq2) { + r = 0; + } else { + r = (seq2 > seq1) ? 1 : -1; + } + return r; +} + +static void +serializer_participant_data( + DDS_Security_ParticipantBuiltinTopicData *pdata, + unsigned char **buffer, + size_t *size) +{ + DDS_Security_Serializer serializer; + serializer = DDS_Security_Serializer_new(1024, 1024); + + DDS_Security_Serialize_ParticipantBuiltinTopicData(serializer, pdata); + DDS_Security_Serializer_buffer(serializer, buffer, size); + DDS_Security_Serializer_free(serializer); +} + + +static void +set_binary_property_value( + DDS_Security_BinaryProperty_t *bp, + const char *name, + const unsigned char *data, + uint32_t length) +{ + assert(bp); + assert(name); + assert(data); + + bp->name = ddsrt_strdup(name); + bp->value._maximum = bp->value._length = length; + if (length) { + bp->value._buffer = ddsrt_malloc(length); + memcpy(bp->value._buffer, data, length); + } else { + bp->value._buffer = NULL; + } +} + +static void +set_binary_property_string( + DDS_Security_BinaryProperty_t *bp, + const char *name, + const char *data) +{ + uint32_t length; + + assert(bp); + assert(name); + assert(data); + + length = (uint32_t)strlen(data) + 1; + set_binary_property_value(bp, name, (const unsigned char *)data, length); +} + +static void +fill_handshake_message_token( + DDS_Security_HandshakeMessageToken *token, + DDS_Security_ParticipantBuiltinTopicData *pdata, + const char *certificate, + const char *dsign, + const char *kagree, + const struct octet_seq *diffie_hellman1, + const unsigned char *challengeData, + unsigned int challengeDataSize, + const struct octet_seq *diffie_hellman2, + const unsigned char *challengeData2, + unsigned int challengeDataSize2, + const DDS_Security_BinaryProperty_t *hash1_from_request, + const DDS_Security_BinaryProperty_t *hash2_from_reply, + HandshakeStep_t step) +{ + DDS_Security_BinaryProperty_t *tokens; + DDS_Security_BinaryProperty_t *c_id; + DDS_Security_BinaryProperty_t *c_perm; + DDS_Security_BinaryProperty_t *c_pdata; + DDS_Security_BinaryProperty_t *c_dsign_algo; + DDS_Security_BinaryProperty_t *c_kagree_algo; + DDS_Security_BinaryProperty_t *hash_c1; + DDS_Security_BinaryProperty_t *hash_c2; + DDS_Security_BinaryProperty_t *dh1; + DDS_Security_BinaryProperty_t *dh2; + DDS_Security_BinaryProperty_t *challenge1; + DDS_Security_BinaryProperty_t *challenge2; + DDS_Security_BinaryProperty_t *signature; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + unsigned idx; + unsigned char *serialized_local_participant_data; + size_t serialized_local_participant_data_size; + /*unsigned hash[32];*/ + + switch( step ) + { + + case HANDSHAKE_REQUEST: + tokens = DDS_Security_BinaryPropertySeq_allocbuf(8); + c_id = &tokens[0]; + c_perm = &tokens[1]; + c_pdata = &tokens[2]; + c_dsign_algo = &tokens[3]; + c_kagree_algo = &tokens[4]; + hash_c1 = &tokens[5]; + dh1 = &tokens[6]; + challenge1 = &tokens[7]; + + serializer_participant_data(pdata, &serialized_local_participant_data, &serialized_local_participant_data_size); + + /* Store the Identity Certificate associated with the local identify in c.id property */ + if (certificate) { + set_binary_property_string(c_id, "c.id", certificate); + } else { + set_binary_property_string(c_id, "c.idx", "rubbish"); + } + + /* Store the permission document in the c.perm property */ + set_binary_property_string(c_perm, "c.perm", "permissions_document"); + + /* Store the provided local_participant_data in the c.pdata property */ + set_binary_property_value(c_pdata, "c.pdata", serialized_local_participant_data, (uint32_t)serialized_local_participant_data_size); + ddsrt_free(serialized_local_participant_data); + + /* Set the used signing algorithm descriptor in c.dsign_algo */ + if (dsign) { + set_binary_property_string(c_dsign_algo, "c.dsign_algo", dsign); + } else { + set_binary_property_string(c_dsign_algo, "c.dsign_algox", "rubbish"); + } + + /* Set the used key algorithm descriptor in c.kagree_algo */ + if (kagree) { + set_binary_property_string(c_kagree_algo, "c.kagree_algo", kagree); + } else { + set_binary_property_string(c_kagree_algo, "c.kagree_algox", "rubbish"); + } + + /* Calculate the hash_c1 */ + { + DDS_Security_BinaryPropertySeq bseq; + DDS_Security_Serializer serializer; + unsigned char hash1_sentrequest_arr[32]; + unsigned char *buffer; + size_t size; + + bseq._length = bseq._maximum = 5; + bseq._buffer = tokens; + + serializer = DDS_Security_Serializer_new(1024, 1024); + + DDS_Security_Serialize_BinaryPropertySeq(serializer, &bseq); + DDS_Security_Serializer_buffer(serializer, &buffer, &size); + SHA256(buffer, size, hash1_sentrequest_arr); + ddsrt_free(buffer); + DDS_Security_Serializer_free(serializer); + + set_binary_property_value(hash_c1, "hash_c1", hash1_sentrequest_arr, sizeof(hash1_sentrequest_arr)); + } + + /* Set the DH public key associated with the local participant in dh1 property */ + if (diffie_hellman1) { + set_binary_property_value(dh1, "dh1", diffie_hellman1->data, diffie_hellman1->length); + } else { + set_binary_property_string(dh1, "dh1x", "rubbish"); + } + + /* Set the challenge in challenge1 property */ + if (challengeData) { + set_binary_property_value(challenge1, "challenge1", challengeData, challengeDataSize); + } else { + set_binary_property_value(challenge1, "challenge1x", challenge1_predefined_glb->value._buffer, challenge1_predefined_glb->value._length); + } + + token->class_id = ddsrt_strdup(AUTH_HANDSHAKE_REQUEST_TOKEN_CLASS_ID); + token->binary_properties._length = token->binary_properties._maximum = 8; + token->binary_properties._buffer = tokens; + break; + + case HANDSHAKE_REPLY: + tokens = DDS_Security_BinaryPropertySeq_allocbuf(12); + idx = 0; + c_id = &tokens[idx++]; + c_perm = &tokens[idx++]; + c_pdata = &tokens[idx++]; + c_dsign_algo = &tokens[idx++]; + c_kagree_algo = &tokens[idx++]; + hash_c2 = &tokens[idx++]; + challenge2 = &tokens[idx++]; + dh2 = &tokens[idx++]; + challenge1 = &tokens[idx++]; + dh1 = &tokens[idx++]; + hash_c1 = &tokens[idx++] ; + signature = &tokens[idx++]; + + serializer_participant_data(pdata, &serialized_local_participant_data, &serialized_local_participant_data_size); + + /* Store the Identity Certificate associated with the local identify in c.id property */ + if (certificate) { + set_binary_property_string(c_id, "c.id", certificate); + } else { + set_binary_property_string(c_id, "c.idx", "rubbish"); + } + + /* Store the permission document in the c.perm property */ + set_binary_property_string(c_perm, "c.perm", "permissions_document"); + + /* Store the provided local_participant_data in the c.pdata property */ + set_binary_property_value(c_pdata, "c.pdata", serialized_local_participant_data, (uint32_t )serialized_local_participant_data_size); + ddsrt_free(serialized_local_participant_data); + + /* Set the used signing algorithm descriptor in c.dsign_algo */ + if (dsign) { + set_binary_property_string(c_dsign_algo, "c.dsign_algo", dsign); + } else { + set_binary_property_string(c_dsign_algo, "c.dsign_algox", "rubbish"); + } + + /* Set the used key algorithm descriptor in c.kagree_algo */ + if (kagree) { + set_binary_property_string(c_kagree_algo, "c.kagree_algo", kagree); + } else { + set_binary_property_string(c_kagree_algo, "c.kagree_algox", "rubbish"); + } + + CU_ASSERT_FATAL(hash1_from_request != NULL); + assert(hash1_from_request != NULL); // for Clang's static analyzer + + set_binary_property_value(hash_c1, "hash_c1", hash1_from_request->value._buffer, hash1_from_request->value._length); + + /* Calculate the hash_c2 */ + { + DDS_Security_BinaryPropertySeq bseq; + DDS_Security_Serializer serializer; + unsigned char hash2_sentreply_arr[32]; + unsigned char *buffer; + size_t size; + + bseq._length = bseq._maximum = 5; + bseq._buffer = tokens; + + serializer = DDS_Security_Serializer_new(1024, 1024); + + DDS_Security_Serialize_BinaryPropertySeq(serializer, &bseq); + DDS_Security_Serializer_buffer(serializer, &buffer, &size); + SHA256(buffer, size, hash2_sentreply_arr); + + ddsrt_free(buffer); + DDS_Security_Serializer_free(serializer); + + set_binary_property_value(hash_c2, "hash_c2", hash2_sentreply_arr, sizeof(hash2_sentreply_arr)); + } + + /* Set the challenge in challenge1 property */ + if (challengeData) { + set_binary_property_value(challenge1, "challenge1", challengeData, challengeDataSize); + } else { + set_binary_property_value(challenge1, "challenge1x", challenge2->value._buffer, challenge2->value._length); + } + + /* Set the challenge in challenge2 property */ + if (challengeData2) { + set_binary_property_value(challenge2, "challenge2", challengeData2, challengeDataSize2); + } else { + set_binary_property_value(challenge2, "challenge2x", challenge2->value._buffer, challenge2->value._length); + } + + + /* Set the DH public key associated with the local participant in dh1 property */ + if (diffie_hellman1) { + set_binary_property_value(dh1, "dh1", diffie_hellman1->data, diffie_hellman1->length); + } else { + set_binary_property_string(dh1, "dh1x", "rubbish"); + } + + /* Set the DH public key associated with the local participant in dh2 property */ + if (diffie_hellman2) { + set_binary_property_value(dh2, "dh2", diffie_hellman2->data, diffie_hellman2->length); + } else { + set_binary_property_string(dh2, "dh2x", "rubbish"); + } + + /* Calculate the signature */ + { + BIO *bio; + EVP_PKEY *private_key_x509; + unsigned char *sign; + size_t signlen; + + const DDS_Security_BinaryProperty_t * binary_properties[ HANDSHAKE_SIGNATURE_SIZE ]; + + /* load certificate in buffer */ + bio = BIO_new_mem_buf((const char *) remote_private_key, -1); + assert( bio ); + private_key_x509 = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + assert (private_key_x509 ); + + binary_properties[0] = hash_c2; + binary_properties[1] = challenge2; + binary_properties[2] = dh2; + binary_properties[3] = challenge1; + binary_properties[4] = dh1; + binary_properties[5] = hash_c1; + + if (create_signature_for_test(private_key_x509, binary_properties, HANDSHAKE_SIGNATURE_SIZE , &sign, &signlen, &exception) != DDS_SECURITY_VALIDATION_OK) + { + printf("Exception: %s\n", exception.message); + } + set_binary_property_value(signature, "signature", sign, (uint32_t ) signlen); + + ddsrt_free(sign); + EVP_PKEY_free(private_key_x509); + BIO_free(bio); + } + + token->class_id = ddsrt_strdup(AUTH_HANDSHAKE_REPLY_TOKEN_CLASS_ID); + token->binary_properties._length = token->binary_properties._maximum = 12; + token->binary_properties._buffer = tokens; + break; + + case HANDSHAKE_FINAL: + tokens = DDS_Security_BinaryPropertySeq_allocbuf(7); + idx = 0; + signature = &tokens[idx++]; + hash_c1 = &tokens[idx++]; + challenge1 = &tokens[idx++]; + dh1 = &tokens[idx++]; + challenge2 = &tokens[idx++]; + dh2 = &tokens[idx++]; + hash_c2 = &tokens[idx++]; + + CU_ASSERT(hash1_from_request != NULL); + CU_ASSERT(hash2_from_reply != NULL); + + set_binary_property_value(hash_c1, "hash_c1", hash1_from_request->value._buffer, hash1_from_request->value._length); + set_binary_property_value(hash_c2, "hash_c2", hash2_from_reply->value._buffer, hash2_from_reply->value._length); + + printf("process: %s\n", hash_c1->name); + + /* Set the challenge in challenge1 property */ + if (challengeData) { + set_binary_property_value(challenge1, "challenge1", challengeData, challengeDataSize); + } else { + set_binary_property_value(challenge1, "challenge1x", challenge2->value._buffer, challenge2->value._length); + } + + /* Set the challenge in challenge2 property */ + if (challengeData2) { + set_binary_property_value(challenge2, "challenge2", challengeData2, challengeDataSize2); + } else { + set_binary_property_value(challenge2, "challenge2x", challenge2->value._buffer, challenge2->value._length); + } + + + /* Set the DH public key associated with the local participant in dh1 property */ + if (diffie_hellman1) { + set_binary_property_value(dh1, "dh1", diffie_hellman1->data, diffie_hellman1->length); + } else { + set_binary_property_string(dh1, "dh1x", "rubbish"); + } + + /* Set the DH public key associated with the local participant in dh2 property */ + if (diffie_hellman2) { + set_binary_property_value(dh2, "dh2", diffie_hellman2->data, diffie_hellman2->length); + } else { + set_binary_property_string(dh2, "dh2x", "rubbish"); + } + + /* Calculate the signature */ + { + BIO *bio; + EVP_PKEY *private_key_x509; + unsigned char *sign; + size_t signlen; + const DDS_Security_BinaryProperty_t * binary_properties[ HANDSHAKE_SIGNATURE_SIZE ]; + + /* load certificate in buffer */ + bio = BIO_new_mem_buf((const char *) remote_private_key, -1); + assert( bio ); + private_key_x509 = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); + assert (private_key_x509 ); + + binary_properties[0] = hash_c1; + binary_properties[1] = challenge1; + binary_properties[2] = dh1; + binary_properties[3] = challenge2; + binary_properties[4] = dh2; + binary_properties[5] = hash_c2; + + if (create_signature_for_test(private_key_x509, binary_properties, HANDSHAKE_SIGNATURE_SIZE, &sign, &signlen, &exception) != DDS_SECURITY_VALIDATION_OK) + { + printf("Exception: %s\n", exception.message); + } + set_binary_property_value(signature, "signature", sign, (uint32_t) signlen); + + ddsrt_free(sign); + EVP_PKEY_free(private_key_x509); + BIO_free(bio); + } + token->class_id = ddsrt_strdup(AUTH_HANDSHAKE_FINAL_TOKEN_CLASS_ID); + token->binary_properties._length = token->binary_properties._maximum = 7; + token->binary_properties._buffer = tokens; + break; + } +} + +static void +fill_handshake_message_token_default( + DDS_Security_HandshakeMessageToken *token, + DDS_Security_ParticipantBuiltinTopicData *pdata, + const unsigned char *challengeData, + unsigned int challengeDataSize) +{ + fill_handshake_message_token( + token, pdata, remote_identity_certificate, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + &dh_modp_pub_key, challengeData, challengeDataSize, NULL, NULL, 0, NULL, NULL, HANDSHAKE_REQUEST); +} + +static void +handshake_message_deinit( + DDS_Security_HandshakeMessageToken *token) +{ + DDS_Security_DataHolder_deinit(token); +} + +static bool +validate_handshake_token( + DDS_Security_HandshakeMessageToken *token, + const DDS_Security_OctetSeq *challenge1, + const DDS_Security_OctetSeq *challenge2, + HandshakeStep_t token_type) +{ + const DDS_Security_BinaryProperty_t *property; + const char * class_id; + + switch (token_type) + { + case HANDSHAKE_REQUEST: + class_id = AUTH_HANDSHAKE_REQUEST_TOKEN_CLASS_ID; + break; + case HANDSHAKE_REPLY: + class_id = AUTH_HANDSHAKE_REPLY_TOKEN_CLASS_ID; + break; + case HANDSHAKE_FINAL: + class_id = AUTH_HANDSHAKE_FINAL_TOKEN_CLASS_ID; + break; + default: + class_id = NULL; + CU_FAIL("HandshakeMessageToken invalid token type"); + } + + if (!token->class_id || strcmp(token->class_id, class_id) != 0) { + CU_FAIL("HandshakeMessageToken incorrect class_id"); + } else if ((property = find_binary_property(token, "hash_c2")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'hash_c2' not found"); + } else if ((property = find_binary_property(token, "dh2")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'dh2' not found"); + } else if ((property = find_binary_property(token, "hash_c1")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'hash_c1' not found"); + } else if ((property = find_binary_property(token, "dh1")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'dh1' not found"); + } else if ((property = find_binary_property(token, "challenge1")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'challenge1' not found"); + } else if (challenge1 && compare_octet_seq(challenge1, &property->value) != 0) { + CU_FAIL("HandshakeMessageToken incorrect property 'challenge1' incorrect value"); + } else if ((property = find_binary_property(token, "challenge2")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'challenge2' not found"); + } else if (challenge2 && compare_octet_seq(challenge2, &property->value) != 0) { + CU_FAIL("HandshakeMessageToken incorrect property 'challenge2' incorrect value"); + } else { + return true; + } + + return false; +} + +CU_Test(ddssec_builtin_process_handshake,happy_day_after_request ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_reply_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_reply_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + const DDS_Security_BinaryProperty_t *hash1_sentrequest; + const DDS_Security_BinaryProperty_t *dh1; + const DDS_Security_BinaryProperty_t *challenge1_glb; + struct octet_seq dh1_pub_key; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_request != NULL); + CU_ASSERT_FATAL (auth->process_handshake != NULL); + + result = auth->begin_handshake_request( + auth, + &handshake_handle, + &handshake_token_out, + local_identity_handle, + remote_identity_handle2, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_request failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* get challenge 1 from the message */ + challenge1_glb = find_binary_property(&handshake_token_out, "challenge1"); + + /*Get DH1 value */ + dh1 = find_binary_property(&handshake_token_out, "dh1"); + + hash1_sentrequest = find_binary_property(&handshake_token_out, "hash_c1"); + + CU_ASSERT_FATAL(dh1 != NULL); + assert(dh1 != NULL); // for Clang's static analyzer + CU_ASSERT_FATAL(dh1->value._length > 0); + CU_ASSERT_FATAL(dh1->value._buffer != NULL); + assert(dh1->value._length > 0 && dh1->value._buffer != NULL); // for Clang's static analyzer + + dh1_pub_key.data = dh1->value._buffer; + dh1_pub_key.length = dh1->value._length; + + /* prepare reply */ + fill_handshake_message_token( + &handshake_reply_token_in, remote_participant_data2, remote_identity_certificate, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_ECDH_NAME, + &dh1_pub_key, challenge1_glb->value._buffer, challenge1_glb->value._length, + &dh_ecdh_pub_key, challenge2_predefined_glb->value._buffer, challenge2_predefined_glb->value._length, hash1_sentrequest, NULL, HANDSHAKE_REPLY); + + reset_exception(&exception); + + result = auth->process_handshake( + auth, + &handshake_reply_token_out, + &handshake_reply_token_in, + handshake_handle, + &exception); + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE); + CU_ASSERT(handshake_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT(validate_handshake_token(&handshake_reply_token_out, &challenge1_glb->value, &challenge2_predefined_glb->value, HANDSHAKE_FINAL)); + + CU_ASSERT( check_shared_secret(auth, 1, dh1, dh_ecdh_key, handshake_handle)== 0); + + success= auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT_TRUE (success); + + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + handshake_message_deinit(&handshake_reply_token_in); + handshake_message_deinit(&handshake_reply_token_out); +} + +CU_Test(ddssec_builtin_process_handshake,happy_day_after_reply ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_final_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_final_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + const DDS_Security_BinaryProperty_t *hash1_sentrequest; + const DDS_Security_BinaryProperty_t *hash2_sentreply; + const DDS_Security_BinaryProperty_t *challenge2_glb; + const DDS_Security_BinaryProperty_t *dh2; + struct octet_seq dh2_pub_key; + + CU_ASSERT_FATAL (auth->process_handshake != NULL); + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + fill_handshake_message_token_default(&handshake_token_in, remote_participant_data1, challenge1_predefined_glb->value._buffer, challenge1_predefined_glb->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + CU_ASSERT(handshake_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT(validate_handshake_token(&handshake_token_out, &challenge1_predefined_glb->value, NULL, HANDSHAKE_REPLY)); + + hash1_sentrequest = find_binary_property(&handshake_token_out, "hash_c1"); + hash2_sentreply = find_binary_property(&handshake_token_out, "hash_c2"); + + /*Get DH2 value */ + dh2 = find_binary_property(&handshake_token_out, "dh2"); + + /* get challenge 2 from the message */ + challenge2_glb = find_binary_property(&handshake_token_out, "challenge2"); + + reset_exception(&exception); + + /* prepare final */ + dh2_pub_key.data = dh2->value._buffer; + dh2_pub_key.length = dh2->value._length; + + fill_handshake_message_token( + &handshake_final_token_in, NULL, remote_identity_certificate, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_ECDH_NAME, + &dh_modp_pub_key, challenge1_predefined_glb->value._buffer, challenge1_predefined_glb->value._length, + &dh2_pub_key, challenge2_glb->value._buffer, challenge2_glb->value._length, hash1_sentrequest, hash2_sentreply, HANDSHAKE_FINAL); + + result = auth->process_handshake( + auth, + &handshake_final_token_out, + &handshake_final_token_in, + handshake_handle, + &exception); + + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_OK); + + CU_ASSERT( check_shared_secret(auth, 0, dh2, dh_modp_key, handshake_handle)== 0); + + success= auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_handshake_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + handshake_message_deinit(&handshake_final_token_in); + handshake_message_deinit(&handshake_final_token_out); +} + +CU_Test(ddssec_builtin_process_handshake,invalid_arguments ) +{ + + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_final_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + const DDS_Security_BinaryProperty_t *hash1_sentrequest; + const DDS_Security_BinaryProperty_t *hash2_sentreply; + const DDS_Security_BinaryProperty_t *challenge2_glb; + const DDS_Security_BinaryProperty_t *dh2; + struct octet_seq dh2_pub_key; + DDS_Security_boolean success; + + CU_ASSERT_FATAL (auth->process_handshake != NULL); + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + fill_handshake_message_token_default(&handshake_token_in, remote_participant_data1, challenge1_predefined_glb->value._buffer, challenge1_predefined_glb->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + CU_ASSERT(handshake_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT(validate_handshake_token(&handshake_token_out, &challenge1_predefined_glb->value, NULL, HANDSHAKE_REPLY)); + + /*Get DH2 value */ + dh2 = find_binary_property(&handshake_token_out, "dh2"); + + hash1_sentrequest = find_binary_property(&handshake_token_out, "hash_c1"); + hash2_sentreply = find_binary_property(&handshake_token_out, "hash_c2"); + + /* get challenge 2 from the message */ + challenge2_glb = find_binary_property(&handshake_token_out, "challenge2"); + + reset_exception(&exception); + + /* prepare final */ + dh2_pub_key.data = dh2->value._buffer; + dh2_pub_key.length = dh2->value._length; + + fill_handshake_message_token( + &handshake_final_token_in, NULL, remote_identity_certificate, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + &dh_modp_pub_key, challenge1_predefined_glb->value._buffer, challenge1_predefined_glb->value._length, + &dh2_pub_key, challenge2_glb->value._buffer, challenge2_glb->value._length, + hash1_sentrequest, hash2_sentreply, HANDSHAKE_FINAL); + + + result = auth->process_handshake( + auth, + NULL, + &handshake_final_token_in, + handshake_handle, + &exception); + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->process_handshake( + auth, + &handshake_token_out, + NULL, + handshake_handle, + &exception); + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->process_handshake( + auth, + &handshake_token_out, + &handshake_final_token_in, + 0, + &exception); + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + success= auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT_TRUE (success); + + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + handshake_message_deinit(&handshake_final_token_in); +} + + +CU_Test(ddssec_builtin_process_handshake,invalid_certificate ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_reply_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_reply_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + const DDS_Security_BinaryProperty_t *hash1_sentrequest; + const DDS_Security_BinaryProperty_t *challenge1_glb; + const DDS_Security_BinaryProperty_t *dh1; + struct octet_seq dh1_pub_key; + DDS_Security_boolean success; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_request != NULL); + CU_ASSERT_FATAL (auth->process_handshake != NULL); + + result = auth->begin_handshake_request( + auth, + &handshake_handle, + &handshake_token_out, + local_identity_handle, + remote_identity_handle2, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_request failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + + /* get challenge 1 from the message */ + challenge1_glb = find_binary_property(&handshake_token_out, "challenge1"); + + /*Get DH1 value */ + dh1 = find_binary_property(&handshake_token_out, "dh1"); + + hash1_sentrequest = find_binary_property(&handshake_token_out, "hash_c1"); + + CU_ASSERT_FATAL(dh1 != NULL); + assert(dh1 != NULL); // for Clang's static analyzer + CU_ASSERT_FATAL(dh1->value._length > 0); + CU_ASSERT_FATAL(dh1->value._buffer != NULL); + assert(dh1->value._length > 0 && dh1->value._buffer != NULL); // for Clang's static analyzer + + /* prepare reply */ + dh1_pub_key.data = dh1->value._buffer; + dh1_pub_key.length = dh1->value._length; + + fill_handshake_message_token( + &handshake_reply_token_in, remote_participant_data2, unrelated_identity, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_ECDH_NAME, + &dh1_pub_key, challenge1_glb->value._buffer, challenge1_glb->value._length, + &dh_ecdh_pub_key, challenge2_predefined_glb->value._buffer, challenge2_predefined_glb->value._length, + hash1_sentrequest, NULL, HANDSHAKE_REPLY); + + reset_exception(&exception); + + result = auth->process_handshake( + auth, + &handshake_reply_token_out, + &handshake_reply_token_in, + handshake_handle, + &exception); + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + success= auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT_TRUE (success); + + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + handshake_message_deinit(&handshake_reply_token_in); +} + +CU_Test(ddssec_builtin_process_handshake,invalid_dsign_algo ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_reply_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_reply_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + const DDS_Security_BinaryProperty_t *hash1_sentrequest; + const DDS_Security_BinaryProperty_t *challenge1_glb; + const DDS_Security_BinaryProperty_t *dh1; + struct octet_seq dh1_pub_key; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_request != NULL); + CU_ASSERT_FATAL (auth->process_handshake != NULL); + + result = auth->begin_handshake_request( + auth, + &handshake_handle, + &handshake_token_out, + local_identity_handle, + remote_identity_handle2, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_request failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + + /* get challenge 1 from the message */ + challenge1_glb = find_binary_property(&handshake_token_out, "challenge1"); + + /*Get DH1 value */ + dh1 = find_binary_property(&handshake_token_out, "dh1"); + + hash1_sentrequest = find_binary_property(&handshake_token_out, "hash_c1"); + + CU_ASSERT_FATAL(dh1 != NULL); + assert(dh1 != NULL); // for Clang's static analyzer + CU_ASSERT_FATAL(dh1->value._length > 0); + CU_ASSERT_FATAL(dh1->value._buffer != NULL); + assert(dh1->value._length > 0 && dh1->value._buffer != NULL); // for Clang's static analyzer + + /* prepare reply */ + dh1_pub_key.data = dh1->value._buffer; + dh1_pub_key.length = dh1->value._length; + + fill_handshake_message_token( + &handshake_reply_token_in, remote_participant_data2, remote_identity_certificate, + "RSASSA-PSS-SHA128", AUTH_KAGREE_ALGO_RSA_NAME, + &dh1_pub_key, challenge1_glb->value._buffer, challenge1_glb->value._length, + &dh_modp_pub_key, challenge2_predefined_glb->value._buffer, challenge2_predefined_glb->value._length, + hash1_sentrequest, NULL, HANDSHAKE_REPLY); + + reset_exception(&exception); + + result = auth->process_handshake( + auth, + &handshake_reply_token_out, + &handshake_reply_token_in, + handshake_handle, + &exception); + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + handshake_message_deinit(&handshake_reply_token_in); +} + +CU_Test(ddssec_builtin_process_handshake,invalid_kagree_algo ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_reply_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_reply_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + const DDS_Security_BinaryProperty_t *hash1_sentrequest; + const DDS_Security_BinaryProperty_t *challenge1_glb; + const DDS_Security_BinaryProperty_t *dh1; + struct octet_seq dh1_pub_key; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_request != NULL); + CU_ASSERT_FATAL (auth->process_handshake != NULL); + + result = auth->begin_handshake_request( + auth, + &handshake_handle, + &handshake_token_out, + local_identity_handle, + remote_identity_handle2, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_request failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + + /* get challenge 1 from the message */ + challenge1_glb = find_binary_property(&handshake_token_out, "challenge1"); + + /*Get DH1 value */ + dh1 = find_binary_property(&handshake_token_out, "dh1"); + + hash1_sentrequest = find_binary_property(&handshake_token_out, "hash_c1"); + + CU_ASSERT_FATAL(dh1 != NULL); + assert (dh1 != NULL); // for Clang's static analyzer + CU_ASSERT_FATAL(dh1->value._length > 0); + CU_ASSERT_FATAL(dh1->value._buffer != NULL); + assert (dh1->value._length > 0 && dh1->value._buffer != NULL); // for Clang's static analyzer + + /* prepare reply */ + dh1_pub_key.data = dh1->value._buffer; + dh1_pub_key.length = dh1->value._length; + + fill_handshake_message_token( + &handshake_reply_token_in, remote_participant_data2, remote_identity_certificate, + AUTH_DSIGN_ALGO_RSA_NAME, "DH+MODP-2048-128", + &dh1_pub_key, challenge1_glb->value._buffer, challenge1_glb->value._length, + &dh_modp_pub_key, challenge2_predefined_glb->value._buffer, challenge2_predefined_glb->value._length, + hash1_sentrequest, NULL, HANDSHAKE_REPLY); + + reset_exception(&exception); + + result = auth->process_handshake( + auth, + &handshake_reply_token_out, + &handshake_reply_token_in, + handshake_handle, + &exception); + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + handshake_message_deinit(&handshake_reply_token_in); +} + +CU_Test(ddssec_builtin_process_handshake,invalid_diffie_hellman ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_reply_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_reply_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + const DDS_Security_BinaryProperty_t *hash1_sentrequest; + const DDS_Security_BinaryProperty_t *challenge1_glb; + const DDS_Security_BinaryProperty_t *dh1; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_request != NULL); + CU_ASSERT_FATAL (auth->process_handshake != NULL); + + result = auth->begin_handshake_request( + auth, + &handshake_handle, + &handshake_token_out, + local_identity_handle, + remote_identity_handle2, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_request failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + + /* get challenge 1 from the message */ + challenge1_glb = find_binary_property(&handshake_token_out, "challenge1"); + + /*Get DH1 value */ + dh1 = find_binary_property(&handshake_token_out, "dh1"); + + hash1_sentrequest = find_binary_property(&handshake_token_out, "hash_c1"); + + CU_ASSERT_FATAL(dh1 != NULL); + assert (dh1 != NULL); // for Clang's static analyzer + CU_ASSERT_FATAL(dh1->value._length > 0); + CU_ASSERT_FATAL(dh1->value._buffer != NULL); + assert (dh1->value._length > 0 && dh1->value._buffer != NULL); // for Clang's static analyzer + + /* prepare reply */ + fill_handshake_message_token( + &handshake_reply_token_in, remote_participant_data2, remote_identity_certificate, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + &invalid_dh_pub_key, challenge1_glb->value._buffer, challenge1_glb->value._length, + &dh_modp_pub_key, challenge2_predefined_glb->value._buffer, challenge2_predefined_glb->value._length, + hash1_sentrequest, NULL, HANDSHAKE_REPLY); + + reset_exception(&exception); + + result = auth->process_handshake( + auth, + &handshake_reply_token_out, + &handshake_reply_token_in, + handshake_handle, + &exception); + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + handshake_message_deinit(&handshake_reply_token_in); +} + + +CU_Test(ddssec_builtin_process_handshake,return_handle) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + fill_handshake_message_token_default(&handshake_token_in, remote_participant_data1, challenge1_predefined_glb->value._buffer, challenge1_predefined_glb->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle1, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_request failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL (result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + CU_ASSERT (handshake_handle != DDS_SECURITY_HANDLE_NIL); + + reset_exception(&exception); + + success = auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_handshake_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + success = auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT_FALSE (success); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + if (!success) { + printf("return_handshake_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); +} + + +CU_Test(ddssec_builtin_process_handshake,extended_certificate_check ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_reply_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_reply_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + const DDS_Security_BinaryProperty_t *hash1_sentrequest; + const DDS_Security_BinaryProperty_t *dh1; + const DDS_Security_BinaryProperty_t *challenge1_glb; + struct octet_seq dh1_pub_key; + + release_local_identity(); + release_remote_identities(); + + CU_ASSERT_FATAL( !validate_local_identity("trusted_ca_dir") ); + CU_ASSERT_FATAL( !validate_remote_identities( remote_identity_trusted ) ); + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_request != NULL); + CU_ASSERT_FATAL (auth->process_handshake != NULL); + + result = auth->begin_handshake_request( + auth, + &handshake_handle, + &handshake_token_out, + local_identity_handle, + remote_identity_handle2, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_request failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + assert(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); // for Clang's static analyzer + + /* get challenge 1 from the message */ + challenge1_glb = find_binary_property(&handshake_token_out, "challenge1"); + + /*Get DH1 value */ + dh1 = find_binary_property(&handshake_token_out, "dh1"); + + hash1_sentrequest = find_binary_property(&handshake_token_out, "hash_c1"); + + CU_ASSERT_FATAL(dh1 != NULL); + assert(dh1 != NULL); // for Clang's static analyzer + CU_ASSERT_FATAL(dh1->value._length > 0); + CU_ASSERT_FATAL(dh1->value._buffer != NULL); + assert(dh1->value._length > 0 && dh1->value._buffer != NULL); // for Clang's static analyzer + + dh1_pub_key.data = dh1->value._buffer; + dh1_pub_key.length = dh1->value._length; + + /* prepare reply */ + fill_handshake_message_token( + &handshake_reply_token_in, remote_participant_data2, remote_identity_trusted, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_ECDH_NAME, + &dh1_pub_key, challenge1_glb->value._buffer, challenge1_glb->value._length, + &dh_ecdh_pub_key, challenge2_predefined_glb->value._buffer, challenge2_predefined_glb->value._length, hash1_sentrequest, NULL, HANDSHAKE_REPLY); + + reset_exception(&exception); + + result = auth->process_handshake( + auth, + &handshake_reply_token_out, + &handshake_reply_token_in, + handshake_handle, + &exception); + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE); + CU_ASSERT(handshake_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT(validate_handshake_token(&handshake_reply_token_out, &challenge1_glb->value, &challenge2_predefined_glb->value, HANDSHAKE_FINAL)); + + CU_ASSERT( check_shared_secret(auth, 1, dh1, dh_ecdh_key, handshake_handle)== 0); + + success= auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT_TRUE (success); + + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + handshake_message_deinit(&handshake_reply_token_in); + handshake_message_deinit(&handshake_reply_token_out); + + + release_local_identity(); + release_remote_identities(); + + CU_ASSERT_FATAL( !validate_local_identity("trusted_ca_dir") ); + CU_ASSERT_FATAL( !validate_remote_identities( remote_identity_trusted_expired ) ); + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_request != NULL); + CU_ASSERT_FATAL (auth->process_handshake != NULL); + + result = auth->begin_handshake_request( + auth, + &handshake_handle, + &handshake_token_out, + local_identity_handle, + remote_identity_handle2, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_request failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* get challenge 1 from the message */ + challenge1_glb = find_binary_property(&handshake_token_out, "challenge1"); + + /*Get DH1 value */ + dh1 = find_binary_property(&handshake_token_out, "dh1"); + + hash1_sentrequest = find_binary_property(&handshake_token_out, "hash_c1"); + + CU_ASSERT_FATAL(dh1 != NULL); + assert (dh1 != NULL); // for Clang's static analyzer + CU_ASSERT_FATAL(dh1->value._length > 0); + CU_ASSERT_FATAL(dh1->value._buffer != NULL); + assert (dh1->value._length > 0 && dh1->value._buffer != NULL); // for Clang's static analyzer + + dh1_pub_key.data = dh1->value._buffer; + dh1_pub_key.length = dh1->value._length; + + /* prepare reply */ + fill_handshake_message_token( + &handshake_reply_token_in, remote_participant_data2, remote_identity_trusted_expired, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_ECDH_NAME, + &dh1_pub_key, challenge1_glb->value._buffer, challenge1_glb->value._length, + &dh_ecdh_pub_key, challenge2_predefined_glb->value._buffer, challenge2_predefined_glb->value._length, hash1_sentrequest, NULL, HANDSHAKE_REPLY); + + reset_exception(&exception); + + result = auth->process_handshake( + auth, + &handshake_reply_token_out, + &handshake_reply_token_in, + handshake_handle, + &exception); + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_FAILED); + + reset_exception(&exception); + + + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + handshake_message_deinit(&handshake_reply_token_in); + handshake_message_deinit(&handshake_reply_token_out); + + + + release_local_identity(); + release_remote_identities(); + + CU_ASSERT_FATAL( !validate_local_identity("trusted_ca_dir") ); + CU_ASSERT_FATAL( !validate_remote_identities( remote_identity_untrusted ) ); + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_request != NULL); + CU_ASSERT_FATAL (auth->process_handshake != NULL); + + result = auth->begin_handshake_request( + auth, + &handshake_handle, + &handshake_token_out, + local_identity_handle, + remote_identity_handle2, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_request failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* get challenge 1 from the message */ + challenge1_glb = find_binary_property(&handshake_token_out, "challenge1"); + + /*Get DH1 value */ + dh1 = find_binary_property(&handshake_token_out, "dh1"); + + hash1_sentrequest = find_binary_property(&handshake_token_out, "hash_c1"); + + CU_ASSERT_FATAL(dh1 != NULL); + assert (dh1 != NULL); // for Clang's static analyzer + CU_ASSERT_FATAL(dh1->value._length > 0); + CU_ASSERT_FATAL(dh1->value._buffer != NULL); + assert (dh1->value._length > 0 && dh1->value._buffer != NULL); // for Clang's static analyzer + + dh1_pub_key.data = dh1->value._buffer; + dh1_pub_key.length = dh1->value._length; + + /* prepare reply */ + fill_handshake_message_token( + &handshake_reply_token_in, remote_participant_data2, remote_identity_untrusted, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_ECDH_NAME, + &dh1_pub_key, challenge1_glb->value._buffer, challenge1_glb->value._length, + &dh_ecdh_pub_key, challenge2_predefined_glb->value._buffer, challenge2_predefined_glb->value._length, hash1_sentrequest, NULL, HANDSHAKE_REPLY); + + reset_exception(&exception); + + result = auth->process_handshake( + auth, + &handshake_reply_token_out, + &handshake_reply_token_in, + handshake_handle, + &exception); + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT_FATAL(exception.code != 0); + + + reset_exception(&exception); + + + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + handshake_message_deinit(&handshake_reply_token_in); + handshake_message_deinit(&handshake_reply_token_out); + +} diff --git a/src/security/builtin_plugins/tests/register_local_datareader/src/register_local_datareader_utests.c b/src/security/builtin_plugins/tests/register_local_datareader/src/register_local_datareader_utests.c new file mode 100644 index 0000000..9001047 --- /dev/null +++ b/src/security/builtin_plugins/tests/register_local_datareader/src/register_local_datareader_utests.c @@ -0,0 +1,322 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_objects.h" + +#if OPENSLL_VERSION_NUMBER >= 0x10002000L +#define AUTH_INCLUDE_EC +#endif + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle = DDS_SECURITY_HANDLE_NIL; +static dds_security_cryptography *crypto = NULL; +static DDS_Security_ParticipantCryptoHandle local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void suite_register_local_datareader_init(void) +{ + DDS_Security_IdentityHandle participant_identity = 5; //valid dummy value + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq participant_properties; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; //valid dummy value + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + /* Only need the crypto plugin. */ + CU_ASSERT_FATAL((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + + /* prepare test shared secret handle */ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(DDS_Security_octet)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL && crypto->crypto_key_factory != NULL && crypto->crypto_key_factory->register_local_participant != NULL); + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + CU_ASSERT_FATAL((local_participant_crypto_handle = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception)) != DDS_SECURITY_HANDLE_NIL) + + /* Now call the function. */ + remote_participant_crypto_handle = crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_crypto_handle, + participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); +} + +static void suite_register_local_datareader_fini(void) +{ + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = (DDS_Security_SharedSecretHandleImpl *)shared_secret_handle; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_participant_crypto_handle, &exception); + reset_exception(&exception); + + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_participant_crypto_handle, &exception); + reset_exception(&exception); + + unload_plugins(plugins); + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); + shared_secret_handle = DDS_SECURITY_HANDLE_NIL; + crypto = NULL; + local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; + remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +} + + + +static void prepare_endpoint_security_attributes(DDS_Security_EndpointSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; +} + +CU_Test(ddssec_builtin_register_local_datareader, happy_day, .init = suite_register_local_datareader_init, .fini = suite_register_local_datareader_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + local_datareader_crypto *reader_crypto; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datareader != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datareader_properties, 0, sizeof(datareader_properties)); + + prepare_endpoint_security_attributes(&datareader_security_attributes); + + /* Now call the function. */ + + result = crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT(result != 0); + assert(result != 0); // for Clang's static analyzer + + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + reader_crypto = (local_datareader_crypto *)result; + + CU_ASSERT_FATAL(reader_crypto->reader_key_material != NULL); + CU_ASSERT(master_salt_not_empty(reader_crypto->reader_key_material)); + CU_ASSERT(master_key_not_empty(reader_crypto->reader_key_material)); + CU_ASSERT(reader_crypto->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_register_local_datareader, builtin_endpoint, .init = suite_register_local_datareader_init, .fini = suite_register_local_datareader_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + local_datareader_crypto *reader_crypto; + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datareader_properties, 0, sizeof(datareader_properties)); + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datareader != NULL); + + datareader_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datareader_properties._length = datareader_properties._maximum = 1; + + datareader_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datareader_properties._buffer[0].value = ddsrt_strdup("BuiltinSecureEndpointName"); + + prepare_endpoint_security_attributes(&datareader_security_attributes); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + + if (exception.code != 0) + printf("register_local_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT(result != 0); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + assert(result != 0); // for Clang's static analyzer + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + reader_crypto = (local_datareader_crypto *)result; + CU_ASSERT_FATAL(reader_crypto->reader_key_material != NULL); + CU_ASSERT(master_salt_not_empty(reader_crypto->reader_key_material)); + CU_ASSERT(master_key_not_empty(reader_crypto->reader_key_material)); + CU_ASSERT(reader_crypto->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT); + CU_ASSERT(reader_crypto->is_builtin_participant_volatile_message_secure_reader == false); + + DDS_Security_PropertySeq_deinit(&datareader_properties); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_register_local_datareader, special_endpoint_name, .init = suite_register_local_datareader_init, .fini = suite_register_local_datareader_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datareader_properties, 0, sizeof(datareader_properties)); + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datareader != NULL); + + /*set special endpoint name*/ + datareader_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datareader_properties._length = datareader_properties._maximum = 1; + datareader_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datareader_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureReader"); + + prepare_endpoint_security_attributes(&datareader_security_attributes); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + + if (exception.code != 0) + printf("register_local_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result != 0); + assert(result != 0); // for Clang's static analyzer + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_OK_CODE); + CU_ASSERT_FATAL(((local_datareader_crypto *)result)->is_builtin_participant_volatile_message_secure_reader); + reset_exception(&exception); + DDS_Security_PropertySeq_deinit(&datareader_properties); +} + +CU_Test(ddssec_builtin_register_local_datareader, invalid_participant, .init = suite_register_local_datareader_init, .fini = suite_register_local_datareader_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datareader != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datareader_properties, 0, sizeof(datareader_properties)); + + prepare_endpoint_security_attributes(&datareader_security_attributes); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + 8, /*non existing handle*/ + &datareader_properties, + &datareader_security_attributes, + &exception); + + /* Invalid handle should be returned */ + CU_ASSERT(result == 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE); + CU_ASSERT_NSTRING_EQUAL_FATAL(exception.message, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE, sizeof(DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE)); + reset_exception(&exception); +} + diff --git a/src/security/builtin_plugins/tests/register_local_datawriter/src/register_local_datawriter_utests.c b/src/security/builtin_plugins/tests/register_local_datawriter/src/register_local_datawriter_utests.c new file mode 100644 index 0000000..80486e5 --- /dev/null +++ b/src/security/builtin_plugins/tests/register_local_datawriter/src/register_local_datawriter_utests.c @@ -0,0 +1,342 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_objects.h" + +#if OPENSLL_VERSION_NUMBER >= 0x10002000L +#define AUTH_INCLUDE_EC +#endif + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle = DDS_SECURITY_HANDLE_NIL; +static dds_security_cryptography *crypto = NULL; +static DDS_Security_ParticipantCryptoHandle local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void suite_register_local_datawriter_init(void) +{ + DDS_Security_IdentityHandle participant_identity = 5; //valid dummy value + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq participant_properties; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; //valid dummy value + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + + /* prepare test shared secret handle */ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(DDS_Security_octet)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (crypto != NULL && crypto->crypto_key_factory != NULL && crypto->crypto_key_factory->register_local_participant != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + local_participant_crypto_handle = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + CU_ASSERT_FATAL (local_participant_crypto_handle != DDS_SECURITY_HANDLE_NIL); + + /* Now call the function. */ + remote_participant_crypto_handle = crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_crypto_handle, + participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + CU_ASSERT_FATAL (remote_participant_crypto_handle != DDS_SECURITY_HANDLE_NIL); + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void suite_register_local_datawriter_fini(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_participant_crypto_handle, &exception); + reset_exception(&exception); + + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_participant_crypto_handle, &exception); + reset_exception(&exception); + + unload_plugins(plugins); + shared_secret_handle = DDS_SECURITY_HANDLE_NIL; + crypto = NULL; + local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; + remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +} + +static void prepare_endpoint_security_attributes(DDS_Security_EndpointSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; +} + +CU_Test(ddssec_builtin_register_local_datawriter, happy_day, .init = suite_register_local_datawriter_init, .fini = suite_register_local_datawriter_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + local_datawriter_crypto *writer_crypto; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datawriter != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + prepare_endpoint_security_attributes(&datawriter_security_attributes); + + datawriter_security_attributes.is_payload_protected = true; + datawriter_security_attributes.plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + if (exception.code != 0) + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT(result != 0); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + assert(result != 0); // for Clang's static analyzer + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + writer_crypto = (local_datawriter_crypto *)result; + + CU_ASSERT_FATAL(writer_crypto->writer_key_material_message != NULL); + CU_ASSERT_FATAL(writer_crypto->writer_key_material_payload != NULL); + + CU_ASSERT(master_salt_not_empty(writer_crypto->writer_key_material_message)); + CU_ASSERT(master_key_not_empty(writer_crypto->writer_key_material_message)); + + CU_ASSERT(master_salt_not_empty(writer_crypto->writer_key_material_payload)); + CU_ASSERT(master_key_not_empty(writer_crypto->writer_key_material_payload)); + + CU_ASSERT(writer_crypto->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT); + CU_ASSERT(writer_crypto->data_protectionKind == DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_register_local_datawriter, builtin_endpoint, .init = suite_register_local_datawriter_init, .fini = suite_register_local_datawriter_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + local_datawriter_crypto *writer_crypto; + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + prepare_endpoint_security_attributes(&datawriter_security_attributes); + datawriter_security_attributes.is_payload_protected = true; + datawriter_security_attributes.plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datawriter != NULL); + + datawriter_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datawriter_properties._length = datawriter_properties._maximum = 1; + datawriter_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datawriter_properties._buffer[0].value = ddsrt_strdup("BuiltinSecureEndpointName"); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + if (exception.code != 0) + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result != 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_OK_CODE); + assert(result != 0); // for Clang's static analyzer + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + writer_crypto = (local_datawriter_crypto *)result; + + CU_ASSERT_FATAL(writer_crypto->writer_key_material_message != NULL); + CU_ASSERT_FATAL(writer_crypto->writer_key_material_payload != NULL); + + CU_ASSERT(master_salt_not_empty(writer_crypto->writer_key_material_message)); + CU_ASSERT(master_key_not_empty(writer_crypto->writer_key_material_message)); + + CU_ASSERT(master_salt_not_empty(writer_crypto->writer_key_material_payload)); + CU_ASSERT(master_key_not_empty(writer_crypto->writer_key_material_payload)); + + CU_ASSERT_FATAL(writer_crypto->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT); + CU_ASSERT_FATAL(writer_crypto->data_protectionKind == DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT); + CU_ASSERT_FATAL(writer_crypto->is_builtin_participant_volatile_message_secure_writer == false); + + reset_exception(&exception); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_register_local_datawriter, special_endpoint_name, .init = suite_register_local_datawriter_init, .fini = suite_register_local_datawriter_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + memset(&datawriter_security_attributes, 0, sizeof(datawriter_security_attributes)); + prepare_endpoint_security_attributes(&datawriter_security_attributes); + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datawriter != NULL); + + /*set special endpoint name*/ + datawriter_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datawriter_properties._length = datawriter_properties._maximum = 1; + datawriter_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datawriter_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureWriter"); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + if (exception.code != 0) + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result != 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_OK_CODE); + assert(result != 0); // for Clang's static analyzer + CU_ASSERT_FATAL(((local_datawriter_crypto *)result)->is_builtin_participant_volatile_message_secure_writer); + + reset_exception(&exception); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_register_local_datawriter, invalid_participant, .init = suite_register_local_datawriter_init, .fini = suite_register_local_datawriter_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datawriter != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + prepare_endpoint_security_attributes(&datawriter_security_attributes); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + 8, /*non existing handle*/ + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + /* Invalid handle should be returned */ + CU_ASSERT(result == 0); + + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE); + CU_ASSERT_NSTRING_EQUAL_FATAL(exception.message, DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE, sizeof(DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_MESSAGE)); + + reset_exception(&exception); +} diff --git a/src/security/builtin_plugins/tests/register_local_participant/src/register_local_participant_utests.c b/src/security/builtin_plugins/tests/register_local_participant/src/register_local_participant_utests.c new file mode 100644 index 0000000..c3f39fc --- /dev/null +++ b/src/security/builtin_plugins/tests/register_local_participant/src/register_local_participant_utests.c @@ -0,0 +1,154 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#if OPENSLL_VERSION_NUMBER >= 0x10002000L +#define AUTH_INCLUDE_EC +#endif + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static void suite_register_local_participant_init(void) +{ + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); +} + +static void suite_register_local_participant_fini(void) +{ + unload_plugins(plugins); +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +CU_Test(ddssec_builtin_register_local_participant, happy_day, .init = suite_register_local_participant_init, .fini = suite_register_local_participant_fini) +{ + DDS_Security_ParticipantCryptoHandle hdl; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_IdentityHandle participant_identity = 5; //valid dummy value + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 2; /*dummy but valid */ + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_participant != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + + prepare_participant_security_attributes(&participant_security_attributes); + + /* Now call the function. */ + hdl = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (exception.code != 0) + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT(hdl != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + + reset_exception(&exception); + + (void)crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + hdl, + &exception); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_register_local_participant, empty_identity, .init = suite_register_local_participant_init, .fini = suite_register_local_participant_fini) +{ + DDS_Security_ParticipantCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_IdentityHandle participant_identity = 0; //empty identity + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + DDS_Security_PermissionsHandle participant_permissions = 2; /*dummy but valid */ + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_participant != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + if (exception.code != 0) + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(exception.code == DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE); + CU_ASSERT_FATAL(exception.message != NULL); + assert(exception.message != NULL); // for Clang's static analyzer + CU_ASSERT(!strcmp(exception.message, DDS_SECURITY_ERR_IDENTITY_EMPTY_MESSAGE)); + CU_ASSERT(result == 0); + + reset_exception(&exception); +} + diff --git a/src/security/builtin_plugins/tests/register_matched_remote_datareader/src/register_matched_remote_datareader_utests.c b/src/security/builtin_plugins/tests/register_matched_remote_datareader/src/register_matched_remote_datareader_utests.c new file mode 100644 index 0000000..1ed3591 --- /dev/null +++ b/src/security/builtin_plugins/tests/register_matched_remote_datareader/src/register_matched_remote_datareader_utests.c @@ -0,0 +1,392 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_objects.h" + +#if OPENSLL_VERSION_NUMBER >= 0x10002000L +#define AUTH_INCLUDE_EC +#endif + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle = DDS_SECURITY_HANDLE_NIL; +static dds_security_cryptography *crypto = NULL; +static DDS_Security_ParticipantCryptoHandle local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_DatawriterCryptoHandle local_writer_handle = DDS_SECURITY_HANDLE_NIL; + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static void prepare_endpoint_security_attributes(DDS_Security_EndpointSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; +} + +static void register_local_regular() +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + prepare_endpoint_security_attributes(&datawriter_security_attributes); + datawriter_security_attributes.is_payload_protected = true; + datawriter_security_attributes.plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_PAYLOAD_ENCRYPTED; + + /* Now call the function. */ + + local_writer_handle = crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); +} + +static void suite_register_matched_remote_datareader_init(void) +{ + DDS_Security_IdentityHandle participant_identity = 5; //valid dummy value + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq participant_properties; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; //valid dummy value + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + /* prepare test shared secret handle */ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(DDS_Security_octet)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (crypto != NULL && crypto->crypto_key_factory != NULL && crypto->crypto_key_factory->register_local_participant != NULL); + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + local_participant_crypto_handle = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + CU_ASSERT_FATAL (local_participant_crypto_handle != DDS_SECURITY_HANDLE_NIL); + + /* Now call the function. */ + remote_participant_crypto_handle = crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_crypto_handle, + participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + CU_ASSERT_FATAL (remote_participant_crypto_handle != DDS_SECURITY_HANDLE_NIL); + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void suite_register_matched_remote_datareader_fini(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + (void)crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + remote_participant_crypto_handle, + &exception); + (void)crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &exception); + unload_plugins(plugins); + shared_secret_handle = DDS_SECURITY_HANDLE_NIL; + crypto = NULL; + local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; + remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +CU_Test(ddssec_builtin_register_remote_datareader, happy_day, .init = suite_register_matched_remote_datareader_init, .fini = suite_register_matched_remote_datareader_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + bool unregister_result = false; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + remote_datareader_crypto *reader_crypto; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datareader != NULL); + + register_local_regular(); + + /* Now call the function. */ + + result = crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_handle, + remote_participant_crypto_handle, + shared_secret_handle, + true, + &exception); + + if (exception.code != 0) + printf("register_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result != 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_OK_CODE); + assert(result != 0); // for Clang's static analyzer + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + reader_crypto = (remote_datareader_crypto *)result; + CU_ASSERT_FATAL(reader_crypto->writer2reader_key_material_message != NULL); + CU_ASSERT_FATAL(reader_crypto->writer2reader_key_material_payload != NULL); + CU_ASSERT(master_salt_not_empty(reader_crypto->writer2reader_key_material_message)); + CU_ASSERT(master_key_not_empty(reader_crypto->writer2reader_key_material_message)); + CU_ASSERT(master_salt_not_empty(reader_crypto->writer2reader_key_material_payload)); + CU_ASSERT(master_key_not_empty(reader_crypto->writer2reader_key_material_payload)); + CU_ASSERT_FATAL(reader_crypto->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT); + reset_exception(&exception); + + unregister_result = crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, result, &exception); + CU_ASSERT_FATAL(unregister_result); +} + +/* test if function returns volatile secure reader crypto if the writer is volatile secure*/ +CU_Test(ddssec_builtin_register_remote_datareader, volatile_secure, .init = suite_register_matched_remote_datareader_init, .fini = suite_register_matched_remote_datareader_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + DDS_Security_DatawriterCryptoHandle local_volatile_secure_writer; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + + prepare_endpoint_security_attributes(&datawriter_security_attributes); + + datawriter_security_attributes.is_discovery_protected = true; + datawriter_security_attributes.is_submessage_protected = true; + + datawriter_properties._length = datawriter_properties._maximum = 1; + datawriter_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datawriter_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datawriter_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureWriter"); + datawriter_properties._buffer[0].propagate = false; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_datawriter != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datareader != NULL); + + local_volatile_secure_writer = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_volatile_secure_writer, + remote_participant_crypto_handle, + shared_secret_handle, + true, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result != 0); + assert(result != 0); // for Clang's static analyzer + CU_ASSERT_FATAL(((remote_datareader_crypto *)result)->is_builtin_participant_volatile_message_secure_reader); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_OK_CODE); + reset_exception(&exception); + + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, result, &exception); + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, local_volatile_secure_writer, &exception); + DDS_Security_PropertySeq_deinit(&datawriter_properties); +} + +CU_Test(ddssec_builtin_register_remote_datareader, with_origin_authentication, .init = suite_register_matched_remote_datareader_init, .fini = suite_register_matched_remote_datareader_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + bool unregister_result = false; + local_datawriter_crypto *writer_crypto; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + remote_datareader_crypto *reader_crypto; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datareader != NULL); + register_local_regular(); + + /*set writer protection kind */ + writer_crypto = (local_datawriter_crypto *)local_writer_handle; + writer_crypto->metadata_protectionKind = DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION; + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_handle, + remote_participant_crypto_handle, + shared_secret_handle, + true, + &exception); + + if (exception.code != 0) + printf("register_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT(result != 0); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + assert(result != 0); // for Clang's static analyzer + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + reader_crypto = (remote_datareader_crypto *)result; + CU_ASSERT_FATAL(reader_crypto->writer2reader_key_material_message != NULL); + CU_ASSERT_FATAL(reader_crypto->writer2reader_key_material_payload != NULL); + CU_ASSERT(master_salt_not_empty(reader_crypto->writer2reader_key_material_message)); + CU_ASSERT(master_key_not_empty(reader_crypto->writer2reader_key_material_message)); + CU_ASSERT(master_salt_not_empty(reader_crypto->writer2reader_key_material_payload)); + CU_ASSERT(master_key_not_empty(reader_crypto->writer2reader_key_material_payload)); + CU_ASSERT_FATAL(reader_crypto->metadata_protectionKind == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION); + reset_exception(&exception); + + /* test to unregister with local writer*/ + unregister_result = crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, local_writer_handle, &exception); + CU_ASSERT_FATAL(unregister_result); + + unregister_result = crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, result, &exception); + CU_ASSERT_FATAL(!unregister_result); + + reset_exception(&exception); +} + +/* test invalid parameter*/ +CU_Test(ddssec_builtin_register_remote_datareader, invalid_participant, .init = suite_register_matched_remote_datareader_init, .fini = suite_register_matched_remote_datareader_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datareader != NULL); + + register_local_regular(); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_handle, + 0, + shared_secret_handle, + true, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result == 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE); + reset_exception(&exception); +} + +/* test invalid parameter*/ +CU_Test(ddssec_builtin_register_remote_datareader, invalid_writer_properties, .init = suite_register_matched_remote_datareader_init, .fini = suite_register_matched_remote_datareader_fini) +{ + DDS_Security_DatawriterCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datareader != NULL); + register_local_regular(); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + 0, + remote_participant_crypto_handle, + shared_secret_handle, + true, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result == 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE); + reset_exception(&exception); +} diff --git a/src/security/builtin_plugins/tests/register_matched_remote_datawriter/src/register_matched_remote_datawriter_utests.c b/src/security/builtin_plugins/tests/register_matched_remote_datawriter/src/register_matched_remote_datawriter_utests.c new file mode 100644 index 0000000..6e4ac1a --- /dev/null +++ b/src/security/builtin_plugins/tests/register_matched_remote_datawriter/src/register_matched_remote_datawriter_utests.c @@ -0,0 +1,378 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "common/src/crypto_helper.h" +#include "crypto_objects.h" + +#if OPENSLL_VERSION_NUMBER >= 0x10002000L +#define AUTH_INCLUDE_EC +#endif + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle = DDS_SECURITY_HANDLE_NIL; +static dds_security_cryptography *crypto = NULL; +static DDS_Security_ParticipantCryptoHandle local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_DatareaderCryptoHandle local_reader_handle = DDS_SECURITY_HANDLE_NIL; + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static void prepare_endpoint_security_attributes(DDS_Security_EndpointSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + attributes->is_discovery_protected = true; + attributes->is_submessage_protected = true; + + attributes->plugin_endpoint_attributes |= DDS_SECURITY_PLUGIN_ENDPOINT_ATTRIBUTES_FLAG_IS_SUBMESSAGE_ENCRYPTED; +} + +static void register_local_regular() +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + memset(&datareader_properties, 0, sizeof(datareader_properties)); + + prepare_endpoint_security_attributes(&datareader_security_attributes); + + /* Now call the function. */ + + local_reader_handle = crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); +} + +static void suite_register_matched_remote_datawriter_init(void) +{ + DDS_Security_IdentityHandle participant_identity = 5; //valid dummy value + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq participant_properties; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; //valid dummy value + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + + /* prepare test shared secret handle */ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(DDS_Security_octet)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (crypto != NULL && crypto->crypto_key_factory != NULL && crypto->crypto_key_factory->register_local_participant != NULL) + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + + prepare_participant_security_attributes(&participant_security_attributes); + local_participant_crypto_handle = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + CU_ASSERT_FATAL (local_participant_crypto_handle != DDS_SECURITY_HANDLE_NIL); + + /* Now call the function. */ + remote_participant_crypto_handle = crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_participant_crypto_handle, + participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + CU_ASSERT_FATAL (remote_participant_crypto_handle != DDS_SECURITY_HANDLE_NIL); +} + +static void suite_register_matched_remote_datawriter_fini(void) +{ + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = (DDS_Security_SharedSecretHandleImpl *)shared_secret_handle; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + CU_ASSERT_EQUAL_FATAL (crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + remote_participant_crypto_handle, + &exception), true); + + CU_ASSERT_EQUAL_FATAL (crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &exception), true); + + unload_plugins(plugins); + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); + shared_secret_handle = DDS_SECURITY_HANDLE_NIL; + crypto = NULL; + local_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; + remote_participant_crypto_handle = DDS_SECURITY_HANDLE_NIL; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + + +CU_Test(ddssec_builtin_register_remote_datawriter, happy_day, .init = suite_register_matched_remote_datawriter_init, .fini = suite_register_matched_remote_datawriter_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + bool unregister_result = false; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + remote_datawriter_crypto *writer_crypto; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datawriter != NULL); + register_local_regular(); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_handle, + remote_participant_crypto_handle, + shared_secret_handle, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result != 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_OK_CODE); + assert(result != 0); // for Clang's static analyzer + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + writer_crypto = (remote_datawriter_crypto *)result; + CU_ASSERT_FATAL(writer_crypto->reader2writer_key_material != NULL); + assert(writer_crypto->reader2writer_key_material != NULL); // for Clang's static analyzer + CU_ASSERT(master_salt_not_empty(writer_crypto->reader2writer_key_material)); + CU_ASSERT(master_key_not_empty(writer_crypto->reader2writer_key_material)); + CU_ASSERT_FATAL(writer_crypto->reader2writer_key_material->receiver_specific_key_id == 0); + reset_exception(&exception); + + unregister_result = crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, result, &exception); + CU_ASSERT_FATAL(unregister_result); +} + +/* test if function returns volatile secure writer crypto if the reader is volatile secure*/ +CU_Test(ddssec_builtin_register_remote_datawriter, volatile_secure, .init = suite_register_matched_remote_datawriter_init, .fini = suite_register_matched_remote_datawriter_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + DDS_Security_DatareaderCryptoHandle local_volatile_secure_reader; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datawriter != NULL); + + datareader_properties._length = datareader_properties._maximum = 1; + datareader_properties._buffer = DDS_Security_PropertySeq_allocbuf(1); + datareader_properties._buffer[0].name = ddsrt_strdup("dds.sec.builtin_endpoint_name"); + datareader_properties._buffer[0].value = ddsrt_strdup("BuiltinParticipantVolatileMessageSecureReader"); + datareader_properties._buffer[0].propagate = false; + memset(&datareader_security_attributes, 0, sizeof(datareader_security_attributes)); + + datareader_security_attributes.is_discovery_protected = true; + datareader_security_attributes.is_submessage_protected = true; + + local_volatile_secure_reader = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_participant_crypto_handle, + &datareader_properties, + &datareader_security_attributes, + &exception); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_volatile_secure_reader, + remote_participant_crypto_handle, + shared_secret_handle, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result != 0); + assert(result != 0); // for Clang's static analyzer + CU_ASSERT_FATAL(((remote_datawriter_crypto *)result)->is_builtin_participant_volatile_message_secure_writer); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_OK_CODE); + reset_exception(&exception); + + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, result, &exception); + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_volatile_secure_reader, &exception); + DDS_Security_PropertySeq_deinit(&datareader_properties); +} + +CU_Test(ddssec_builtin_register_remote_datawriter, with_origin_authentication, .init = suite_register_matched_remote_datawriter_init, .fini = suite_register_matched_remote_datawriter_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + bool unregister_result = false; + local_datareader_crypto *reader_crypto; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + remote_datawriter_crypto *writer_crypto; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datawriter != NULL); + register_local_regular(); + + /*set reader protection kind */ + reader_crypto = (local_datareader_crypto *)local_reader_handle; + reader_crypto->metadata_protectionKind = DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION; + /* Now call the function. */ + + result = crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_handle, + remote_participant_crypto_handle, + shared_secret_handle, + &exception); + + if (exception.code != 0) + printf("register_remote_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result != 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_OK_CODE); + assert(result != 0); // for Clang's static analyzer + + /* NOTE: It would be better to check if the keys have been generated but there is no interface to get them from handle */ + writer_crypto = (remote_datawriter_crypto *)result; + CU_ASSERT_FATAL(writer_crypto->reader2writer_key_material != NULL); + assert(writer_crypto->reader2writer_key_material != NULL); // for Clang's static analyzer + CU_ASSERT(master_salt_not_empty(writer_crypto->reader2writer_key_material)); + CU_ASSERT(master_key_not_empty(writer_crypto->reader2writer_key_material)); + CU_ASSERT_FATAL(writer_crypto->reader2writer_key_material->receiver_specific_key_id != 0); + CU_ASSERT(master_receiver_specific_key_not_empty(writer_crypto->reader2writer_key_material)); + reset_exception(&exception); + + /*test unregister the local pair*/ + unregister_result = crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_reader_handle, &exception); + CU_ASSERT_FATAL(unregister_result); + + /* unregister remote should give error*/ + unregister_result = crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, result, &exception); + CU_ASSERT_FATAL(!unregister_result); + reset_exception(&exception); +} + +/* test invalid parameter*/ +CU_Test(ddssec_builtin_register_remote_datawriter, invalid_participant, .init = suite_register_matched_remote_datawriter_init, .fini = suite_register_matched_remote_datawriter_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datawriter != NULL); + register_local_regular(); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_handle, + 0, + shared_secret_handle, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result == 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE); + reset_exception(&exception); +} + +/* test invalid parameter */ +CU_Test(ddssec_builtin_register_remote_datawriter, invalid_writer_properties, .init = suite_register_matched_remote_datawriter_init, .fini = suite_register_matched_remote_datawriter_fini) +{ + DDS_Security_DatareaderCryptoHandle result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have the function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_matched_remote_datawriter != NULL); + register_local_regular(); + + /* Now call the function. */ + result = crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + 0, + remote_participant_crypto_handle, + shared_secret_handle, + &exception); + + /* A valid handle to be returned */ + CU_ASSERT_FATAL(result == 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_CRYPTO_HANDLE_CODE); + reset_exception(&exception); +} + diff --git a/src/security/builtin_plugins/tests/register_matched_remote_participant/src/register_matched_remote_participant_utests.c b/src/security/builtin_plugins/tests/register_matched_remote_participant/src/register_matched_remote_participant_utests.c new file mode 100644 index 0000000..43b4c53 --- /dev/null +++ b/src/security/builtin_plugins/tests/register_matched_remote_participant/src/register_matched_remote_participant_utests.c @@ -0,0 +1,225 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#if OPENSLL_VERSION_NUMBER >= 0x10002000L +#define AUTH_INCLUDE_EC +#endif + +#define TEST_SHARED_SECRET_SIZE 32 + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static void suite_register_matched_remote_participant_init(void) +{ + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); +} + +static void suite_register_matched_remote_participant_fini(void) +{ + unload_plugins(plugins); +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +CU_Test(ddssec_builtin_register_remote_participant, happy_day, .init = suite_register_matched_remote_participant_init, .fini = suite_register_matched_remote_participant_fini) +{ + DDS_Security_ParticipantCryptoHandle local_crypto_handle; + DDS_Security_ParticipantCryptoHandle remote_crypto_handle; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_IdentityHandle participant_identity = 5; //valid dummy value + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq participant_properties; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; /*valid dummy value */ + DDS_Security_SharedSecretHandle shared_secret_handle; + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + DDS_Security_PermissionsHandle participant_permissions = 2; /*valid but dummy value */ + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + /* prepare test shared secret handle */ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(DDS_Security_octet)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_participant != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + + prepare_participant_security_attributes(&participant_security_attributes); + local_crypto_handle = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + CU_ASSERT_FATAL(local_crypto_handle != DDS_SECURITY_HANDLE_NIL); + + /* Now call the function. */ + remote_crypto_handle = crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_crypto_handle, + participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (exception.code != 0) + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + + /* A valid handle to be returned */ + CU_ASSERT(remote_crypto_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_OK_CODE); + reset_exception(&exception); + + (void)crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + remote_crypto_handle, + &exception); + reset_exception(&exception); + + (void)crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + local_crypto_handle, + &exception); + reset_exception(&exception); + + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +CU_Test(ddssec_builtin_register_remote_participant, empty_identity, .init = suite_register_matched_remote_participant_init, .fini = suite_register_matched_remote_participant_fini) +{ + DDS_Security_ParticipantCryptoHandle local_crypto_handle; + DDS_Security_ParticipantCryptoHandle remote_crypto_handle; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_IdentityHandle participant_identity = 5; //empty identity + DDS_Security_IdentityHandle remote_participant_identity_empty = 0; //empty identity + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + DDS_Security_PermissionsHandle participant_permissions = 2; /*valid but dummy value */ + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + DDS_Security_SharedSecretHandle shared_secret_handle; + DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; //valid dummy value + + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(DDS_Security_octet)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_factory->register_local_participant != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + + prepare_participant_security_attributes(&participant_security_attributes); + + /* Now call the function. */ + local_crypto_handle = crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + remote_crypto_handle = crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_crypto_handle, + remote_participant_identity_empty, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (exception.code != 0) + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(remote_crypto_handle == DDS_SECURITY_HANDLE_NIL); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_IDENTITY_EMPTY_CODE); + CU_ASSERT(!strcmp(exception.message, DDS_SECURITY_ERR_IDENTITY_EMPTY_MESSAGE)); + reset_exception(&exception); + + (void)crypto->crypto_key_factory->unregister_participant( + crypto->crypto_key_factory, + local_crypto_handle, + &exception); + reset_exception(&exception); + + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + diff --git a/src/security/builtin_plugins/tests/set_remote_datareader_crypto_tokens/src/set_remote_datareader_crypto_tokens_utests.c b/src/security/builtin_plugins/tests/set_remote_datareader_crypto_tokens/src/set_remote_datareader_crypto_tokens_utests.c new file mode 100644 index 0000000..5cdb615 --- /dev/null +++ b/src/security/builtin_plugins/tests/set_remote_datareader_crypto_tokens/src/set_remote_datareader_crypto_tokens_utests.c @@ -0,0 +1,977 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 +#define CRYPTO_TRANSFORM_KIND(k) (*(uint32_t *)&((k)[0])) +#define CRYPTO_TRANSFORM_ID(k) (*(uint32_t *)&((k)[0])) + +static const char *CRYPTO_TOKEN_CLASS_ID = "DDS:Crypto:AES_GCM_GMAC"; +static const char *CRYPTO_TOKEN_PROPERTY_NAME = "dds.cryp.keymat"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_particpant_crypto = 0; +static DDS_Security_ParticipantCryptoHandle remote_particpant_crypto = 0; +static DDS_Security_DatawriterCryptoHandle remote_reader_crypto = 0; +static DDS_Security_DatareaderCryptoHandle local_writer_crypto = 0; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static void allocate_shared_secret(void) +{ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void +deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int +register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + local_particpant_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_particpant_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_particpant_crypto ? 0 : -1; +} + +static int +register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_particpant_crypto = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_particpant_crypto, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_particpant_crypto == 0) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_particpant_crypto ? 0 : -1; +} + +static int +register_local_datawriter(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datawriter_properties; + DDS_Security_EndpointSecurityAttributes datawriter_security_attributes; + + memset(&datawriter_properties, 0, sizeof(datawriter_properties)); + memset(&datawriter_security_attributes, 0, sizeof(DDS_Security_EndpointSecurityAttributes)); + + datawriter_security_attributes.is_discovery_protected = true; + datawriter_security_attributes.is_submessage_protected = true; + + local_writer_crypto = + crypto->crypto_key_factory->register_local_datawriter( + crypto->crypto_key_factory, + local_particpant_crypto, + &datawriter_properties, + &datawriter_security_attributes, + &exception); + + if (local_writer_crypto == 0) + { + printf("register_local_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_writer_crypto ? 0 : -1; +} + +static int +register_remote_datareader(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + remote_reader_crypto = + crypto->crypto_key_factory->register_matched_remote_datareader( + crypto->crypto_key_factory, + local_writer_crypto, + remote_particpant_crypto, + shared_secret_handle, + true, + &exception); + + if (remote_reader_crypto == 0) + { + printf("register_matched_remote_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_reader_crypto ? 0 : -1; +} + +static void +reset_exception( + DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void suite_set_remote_datareader_crypto_tokens_init(void) +{ + allocate_shared_secret(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_local_datawriter(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_datareader(), 0); +} + +static void suite_set_remote_datareader_crypto_tokens_fini(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + if (remote_reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, remote_reader_crypto, &exception); + reset_exception(&exception); + } + if (local_writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, local_writer_crypto, &exception); + reset_exception(&exception); + } + if (remote_particpant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_particpant_crypto, &exception); + reset_exception(&exception); + } + if (local_particpant_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_particpant_crypto, &exception); + reset_exception(&exception); + } + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void create_key_material(DDS_Security_OctetSeq *seq, bool include_specific_key) +{ + DDS_Security_KeyMaterial_AES_GCM_GMAC keymat; + DDS_Security_Serializer serializer; + unsigned char *buffer; + size_t length; + + memset(&keymat, 0, sizeof(keymat)); + + keymat.transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + RAND_bytes(keymat.sender_key_id, 4); + + keymat.master_salt._length = keymat.master_salt._maximum = DDS_SECURITY_MASTER_SALT_SIZE_256; + keymat.master_salt._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SALT_SIZE_256); + RAND_bytes(keymat.master_salt._buffer, DDS_SECURITY_MASTER_SALT_SIZE_256); + + keymat.master_sender_key._length = keymat.master_sender_key._maximum = DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256; + keymat.master_sender_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + RAND_bytes(keymat.master_sender_key._buffer, DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + + if (include_specific_key) + { + RAND_bytes(keymat.receiver_specific_key_id, 4); + keymat.master_receiver_specific_key._length = keymat.master_receiver_specific_key._maximum = DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256; + keymat.master_receiver_specific_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + RAND_bytes(keymat.master_receiver_specific_key._buffer, DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + } + + serializer = DDS_Security_Serializer_new(256, 256); + DDS_Security_Serialize_KeyMaterial_AES_GCM_GMAC(serializer, &keymat); + DDS_Security_Serializer_buffer(serializer, &buffer, &length); + DDS_Security_Serializer_free(serializer); + + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&keymat); + + seq->_length = seq->_maximum = (uint32_t)length; + seq->_buffer = buffer; +} + +static void init_key_material(DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat, bool include_specific_key) +{ + memset(keymat, 0, sizeof(*keymat)); + + keymat->transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + RAND_bytes(keymat->sender_key_id, 4); + + keymat->master_salt._length = keymat->master_salt._maximum = DDS_SECURITY_MASTER_SALT_SIZE_256; + keymat->master_salt._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SALT_SIZE_256); + RAND_bytes(keymat->master_salt._buffer, DDS_SECURITY_MASTER_SALT_SIZE_256); + + keymat->master_sender_key._length = keymat->master_sender_key._maximum = DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256; + keymat->master_sender_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + RAND_bytes(keymat->master_sender_key._buffer, DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + + if (include_specific_key) + { + RAND_bytes(keymat->receiver_specific_key_id, 4); + keymat->master_receiver_specific_key._length = keymat->master_receiver_specific_key._maximum = DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256; + keymat->master_receiver_specific_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + RAND_bytes(keymat->master_receiver_specific_key._buffer, DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + } +} + +static void deinit_key_material(DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat) +{ + ddsrt_free(keymat->master_salt._buffer); + ddsrt_free(keymat->master_sender_key._buffer); + ddsrt_free(keymat->master_receiver_specific_key._buffer); +} + +static void create_reader_tokens(DDS_Security_DatawriterCryptoTokenSeq *tokens) +{ + tokens->_length = tokens->_maximum = 1; + tokens->_buffer = DDS_Security_DataHolderSeq_allocbuf(1); + tokens->_buffer[0].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + tokens->_buffer[0].binary_properties._length = 1; + tokens->_buffer[0].binary_properties._maximum = 1; + tokens->_buffer[0].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + tokens->_buffer[0].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + create_key_material(&tokens->_buffer[0].binary_properties._buffer[0].value, false); +} + +static void create_reader_tokens_no_key_material(DDS_Security_DatawriterCryptoTokenSeq *tokens) +{ + tokens->_length = tokens->_maximum = 1; + tokens->_buffer = DDS_Security_DataHolderSeq_allocbuf(1); + tokens->_buffer[0].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + tokens->_buffer[0].binary_properties._length = 1; + tokens->_buffer[0].binary_properties._maximum = 1; + tokens->_buffer[0].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + tokens->_buffer[0].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); +} + +static void serialize_key_material(DDS_Security_OctetSeq *seq, DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat) +{ + DDS_Security_Serializer serializer; + unsigned char *buffer; + size_t length; + + serializer = DDS_Security_Serializer_new(256, 256); + DDS_Security_Serialize_KeyMaterial_AES_GCM_GMAC(serializer, keymat); + DDS_Security_Serializer_buffer(serializer, &buffer, &length); + DDS_Security_Serializer_free(serializer); + + seq->_length = seq->_maximum = (uint32_t) length; + seq->_buffer = buffer; +} + +CU_Test(ddssec_builtin_set_remote_datareader_crypto_tokens, happy_day, .init = suite_set_remote_datareader_crypto_tokens_init, .fini = suite_set_remote_datareader_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + create_reader_tokens(&tokens); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + DDS_Security_DataHolderSeq_deinit(&tokens); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_set_remote_datareader_crypto_tokens, single_token, .init = suite_set_remote_datareader_crypto_tokens_init, .fini = suite_set_remote_datareader_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens != NULL); + memset(&tokens, 0, sizeof(tokens)); + create_reader_tokens(&tokens); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + DDS_Security_DataHolderSeq_deinit(&tokens); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_set_remote_datareader_crypto_tokens, invalid_args, .init = suite_set_remote_datareader_crypto_tokens_init, .fini = suite_set_remote_datareader_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + create_reader_tokens(&tokens); + + /* invalid token seq = NULL */ + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + NULL, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + + reset_exception(&exception); + + /* invalid local_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + 0, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid remote_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + 0, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid local_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + 1, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid remote_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + 1, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + DDS_Security_DataHolderSeq_deinit(&tokens); +} + +CU_Test(ddssec_builtin_set_remote_datareader_crypto_tokens, invalid_tokens, .init = suite_set_remote_datareader_crypto_tokens_init, .fini = suite_set_remote_datareader_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + DDS_Security_DatawriterCryptoTokenSeq empty_tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + memset(&empty_tokens, 0, sizeof(empty_tokens)); + create_reader_tokens(&tokens); + + /* empty token sequence */ + { + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &empty_tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + } + + /* DDS_Security_DatawriterCryptoTokenSeq with empty token */ + { + empty_tokens._length = 1; + empty_tokens._buffer = DDS_Security_DataHolderSeq_allocbuf(1); + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &empty_tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_DataHolderSeq_deinit(&empty_tokens); + } + + /* invalid token class id */ + { + ddsrt_free(tokens._buffer[0].class_id); + tokens._buffer[0].class_id = ddsrt_strdup("invalid class"); + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + ddsrt_free(tokens._buffer[0].class_id); + tokens._buffer[0].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + } + + /* no key material, binary_property missing */ + { + tokens._buffer[0].binary_properties._length = 0; + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + tokens._buffer[0].binary_properties._length = 1; + } + + /* no key material, property is empty */ + { + DDS_Security_BinaryProperty_t *saved_buffer = tokens._buffer[0].binary_properties._buffer; + tokens._buffer[0].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + ddsrt_free(tokens._buffer[0].binary_properties._buffer); + tokens._buffer[0].binary_properties._buffer = saved_buffer; + } + + /* invalid property name */ + { + ddsrt_free(tokens._buffer[0].binary_properties._buffer[0].name); + tokens._buffer[0].binary_properties._buffer[0].name = ddsrt_strdup("invalid_key_mat_name"); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + ddsrt_free(tokens._buffer[0].binary_properties._buffer[0].name); + tokens._buffer[0].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); +} + +CU_Test(ddssec_builtin_set_remote_datareader_crypto_tokens, invalid_key_material, .init = suite_set_remote_datareader_crypto_tokens_init, .fini = suite_set_remote_datareader_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + DDS_Security_KeyMaterial_AES_GCM_GMAC keymat; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + create_reader_tokens_no_key_material(&tokens); + + /* empty key material */ + { + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + } + + /* invalid transform kind */ + { + init_key_material(&keymat, false); + keymat.transformation_kind[2] = 1; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* no master salt */ + { + init_key_material(&keymat, false); + + DDS_Security_OctetSeq_deinit(&keymat.master_salt); + keymat.master_salt._buffer = NULL; + keymat.master_salt._length = keymat.master_salt._maximum = 0; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* empty master salt */ + { + init_key_material(&keymat, false); + + memset(keymat.master_salt._buffer, 0, keymat.master_salt._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* incorrect master salt */ + { + init_key_material(&keymat, false); + + keymat.master_salt._length = 16; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* no master sender key */ + { + init_key_material(&keymat, false); + + DDS_Security_OctetSeq_deinit(&keymat.master_sender_key); + + keymat.master_sender_key._buffer = NULL; + keymat.master_sender_key._length = keymat.master_sender_key._maximum = 0; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* empty master sender key */ + { + init_key_material(&keymat, false); + + memset(keymat.master_sender_key._buffer, 0, keymat.master_sender_key._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* incorrect master sender key */ + { + init_key_material(&keymat, false); + + memset(keymat.master_sender_key._buffer, 0, keymat.master_sender_key._length); + keymat.master_sender_key._length = 16; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* no master receiver specific key */ + { + init_key_material(&keymat, true); + + DDS_Security_OctetSeq_deinit(&keymat.master_receiver_specific_key); + + keymat.master_receiver_specific_key._buffer = NULL; + keymat.master_receiver_specific_key._length = keymat.master_receiver_specific_key._maximum = 0; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* nempty master receiver specific key */ + { + init_key_material(&keymat, true); + + memset(keymat.master_receiver_specific_key._buffer, 0, keymat.master_receiver_specific_key._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* incorrect master receiver specific key */ + { + init_key_material(&keymat, true); + + memset(keymat.master_receiver_specific_key._buffer, 0, keymat.master_receiver_specific_key._length); + keymat.master_receiver_specific_key._length = 16; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* invalid key material */ + { + init_key_material(&keymat, true); + + memset(keymat.master_receiver_specific_key._buffer, 0, keymat.master_receiver_specific_key._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + RAND_bytes(tokens._buffer[0].binary_properties._buffer[0].value._buffer, (int) tokens._buffer[0].binary_properties._buffer[0].value._length); + + result = crypto->crypto_key_exchange->set_remote_datareader_crypto_tokens( + crypto->crypto_key_exchange, + local_writer_crypto, + remote_reader_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datareader_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); +} diff --git a/src/security/builtin_plugins/tests/set_remote_datawriter_crypto_tokens/src/set_remote_datawriter_crypto_tokens_utests.c b/src/security/builtin_plugins/tests/set_remote_datawriter_crypto_tokens/src/set_remote_datawriter_crypto_tokens_utests.c new file mode 100644 index 0000000..5816149 --- /dev/null +++ b/src/security/builtin_plugins/tests/set_remote_datawriter_crypto_tokens/src/set_remote_datawriter_crypto_tokens_utests.c @@ -0,0 +1,1026 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 +#define CRYPTO_TRANSFORM_KIND(k) (*(uint32_t *)&((k)[0])) +#define CRYPTO_TRANSFORM_ID(k) (*(uint32_t *)&((k)[0])) + +static const char *CRYPTO_TOKEN_CLASS_ID = "DDS:Crypto:AES_GCM_GMAC"; +static const char *CRYPTO_TOKEN_PROPERTY_NAME = "dds.cryp.keymat"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_particpant_crypto = 0; +static DDS_Security_ParticipantCryptoHandle remote_particpant_crypto = 0; +static DDS_Security_DatawriterCryptoHandle remote_writer_crypto = 0; +static DDS_Security_DatareaderCryptoHandle local_reader_crypto = 0; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle; + +static void allocate_shared_secret(void) +{ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + prepare_participant_security_attributes(&participant_security_attributes); + + local_particpant_crypto = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_particpant_crypto == 0) + { + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_particpant_crypto ? 0 : -1; +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_particpant_crypto = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_particpant_crypto, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_particpant_crypto == 0) + { + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_particpant_crypto ? 0 : -1; +} + +static int register_local_datareader(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq datareader_properties; + DDS_Security_EndpointSecurityAttributes datareader_security_attributes; + + memset(&datareader_properties, 0, sizeof(datareader_properties)); + memset(&datareader_security_attributes, 0, sizeof(datareader_security_attributes)); + datareader_security_attributes.is_discovery_protected = true; + datareader_security_attributes.is_submessage_protected = true; + + local_reader_crypto = + crypto->crypto_key_factory->register_local_datareader( + crypto->crypto_key_factory, + local_particpant_crypto, + &datareader_properties, + &datareader_security_attributes, + &exception); + + if (local_reader_crypto == 0) + { + printf("register_local_datareader: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return local_reader_crypto ? 0 : -1; +} + +static int register_remote_datawriter(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + remote_writer_crypto = + crypto->crypto_key_factory->register_matched_remote_datawriter( + crypto->crypto_key_factory, + local_reader_crypto, + remote_particpant_crypto, + shared_secret_handle, + &exception); + + if (remote_writer_crypto == 0) + { + printf("register_matched_remote_datawriter: %s\n", exception.message ? exception.message : "Error message missing"); + } + + return remote_writer_crypto ? 0 : -1; +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void suite_set_remote_datawriter_crypto_tokens_init(void) +{ + allocate_shared_secret(); + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_local_datareader(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_datawriter(), 0); +} + +static void suite_set_remote_datawriter_crypto_tokens_fini(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + if (remote_writer_crypto) + { + crypto->crypto_key_factory->unregister_datawriter(crypto->crypto_key_factory, remote_writer_crypto, &exception); + reset_exception(&exception); + } + if (local_reader_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_reader_crypto, &exception); + reset_exception(&exception); + } + if (remote_particpant_crypto) + { + crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_particpant_crypto, &exception); + reset_exception(&exception); + } + if (local_particpant_crypto) + { + crypto->crypto_key_factory->unregister_datareader(crypto->crypto_key_factory, local_particpant_crypto, &exception); + reset_exception(&exception); + } + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void create_key_material(DDS_Security_OctetSeq *seq, bool include_specific_key) +{ + DDS_Security_KeyMaterial_AES_GCM_GMAC keymat; + DDS_Security_Serializer serializer; + unsigned char *buffer; + size_t length; + + memset(&keymat, 0, sizeof(keymat)); + + keymat.transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + RAND_bytes(keymat.sender_key_id, 4); + + keymat.master_salt._length = keymat.master_salt._maximum = DDS_SECURITY_MASTER_SALT_SIZE_256; + keymat.master_salt._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SALT_SIZE_256); + RAND_bytes(keymat.master_salt._buffer, DDS_SECURITY_MASTER_SALT_SIZE_256); + + keymat.master_sender_key._length = keymat.master_sender_key._maximum = DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256; + keymat.master_sender_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + RAND_bytes(keymat.master_sender_key._buffer, DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + + if (include_specific_key) + { + RAND_bytes(keymat.receiver_specific_key_id, 4); + keymat.master_receiver_specific_key._length = keymat.master_receiver_specific_key._maximum = DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256; + keymat.master_receiver_specific_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + RAND_bytes(keymat.master_receiver_specific_key._buffer, DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + } + + serializer = DDS_Security_Serializer_new(256, 256); + DDS_Security_Serialize_KeyMaterial_AES_GCM_GMAC(serializer, &keymat); + DDS_Security_Serializer_buffer(serializer, &buffer, &length); + DDS_Security_Serializer_free(serializer); + + DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit(&keymat); + + seq->_length = seq->_maximum = (uint32_t) length; + seq->_buffer = buffer; +} + +static void init_key_material(DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat, bool include_specific_key) +{ + memset(keymat, 0, sizeof(*keymat)); + + keymat->transformation_kind[3] = CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + RAND_bytes(keymat->sender_key_id, 4); + + keymat->master_salt._length = keymat->master_salt._maximum = DDS_SECURITY_MASTER_SALT_SIZE_256; + keymat->master_salt._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SALT_SIZE_256); + RAND_bytes(keymat->master_salt._buffer, DDS_SECURITY_MASTER_SALT_SIZE_256); + + keymat->master_sender_key._length = keymat->master_sender_key._maximum = DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256; + keymat->master_sender_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + RAND_bytes(keymat->master_sender_key._buffer, DDS_SECURITY_MASTER_SENDER_KEY_SIZE_256); + + if (include_specific_key) + { + RAND_bytes(keymat->receiver_specific_key_id, 4); + keymat->master_receiver_specific_key._length = keymat->master_receiver_specific_key._maximum = DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256; + keymat->master_receiver_specific_key._buffer = DDS_Security_OctetSeq_allocbuf(DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + RAND_bytes(keymat->master_receiver_specific_key._buffer, DDS_SECURITY_MASTER_RECEIVER_SPECIFIC_KEY_SIZE_256); + } +} + +static void deinit_key_material(DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat) +{ + ddsrt_free(keymat->master_salt._buffer); + ddsrt_free(keymat->master_sender_key._buffer); + ddsrt_free(keymat->master_receiver_specific_key._buffer); +} + +static void create_writer_tokens(DDS_Security_DatawriterCryptoTokenSeq *tokens, uint32_t num) +{ + tokens->_length = tokens->_maximum = num; + tokens->_buffer = DDS_Security_DataHolderSeq_allocbuf(num); + for (uint32_t i = 0; i < num; i++) + { + tokens->_buffer[i].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + tokens->_buffer[i].binary_properties._length = 1; + tokens->_buffer[i].binary_properties._maximum = 1; + tokens->_buffer[i].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + tokens->_buffer[i].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + create_key_material(&tokens->_buffer[i].binary_properties._buffer[0].value, false); + } +} + +static void create_writer_tokens_no_key_material(DDS_Security_DatawriterCryptoTokenSeq *tokens, uint32_t num) +{ + tokens->_length = tokens->_maximum = num; + tokens->_buffer = DDS_Security_DataHolderSeq_allocbuf(num); + for (uint32_t i = 0; i < num; i++) + { + tokens->_buffer[i].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + tokens->_buffer[i].binary_properties._length = 1; + tokens->_buffer[i].binary_properties._maximum = 1; + tokens->_buffer[i].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + tokens->_buffer[i].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + } +} + +static void serialize_key_material(DDS_Security_OctetSeq *seq, DDS_Security_KeyMaterial_AES_GCM_GMAC *keymat) +{ + DDS_Security_Serializer serializer; + unsigned char *buffer; + size_t length; + + serializer = DDS_Security_Serializer_new(256, 256); + DDS_Security_Serialize_KeyMaterial_AES_GCM_GMAC(serializer, keymat); + DDS_Security_Serializer_buffer(serializer, &buffer, &length); + DDS_Security_Serializer_free(serializer); + + seq->_length = seq->_maximum = (uint32_t) length; + seq->_buffer = buffer; +} + +CU_Test(ddssec_builtin_set_remote_datawriter_crypto_tokens, happy_day, .init = suite_set_remote_datawriter_crypto_tokens_init, .fini = suite_set_remote_datawriter_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + + create_writer_tokens(&tokens, 2); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + DDS_Security_DataHolderSeq_deinit(&tokens); + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_set_remote_datawriter_crypto_tokens, single_token, .init = suite_set_remote_datawriter_crypto_tokens_init, .fini = suite_set_remote_datawriter_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens != NULL); + memset(&tokens, 0, sizeof(tokens)); + create_writer_tokens(&tokens, 1); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + DDS_Security_DataHolderSeq_deinit(&tokens); + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_set_remote_datawriter_crypto_tokens, invalid_args, .init = suite_set_remote_datawriter_crypto_tokens_init, .fini = suite_set_remote_datawriter_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_datawriter_crypto_tokens != NULL); + memset(&tokens, 0, sizeof(tokens)); + create_writer_tokens(&tokens, 2); + + /* invalid token seq = NULL */ + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + NULL, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid local_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + 0, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid remote_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + 0, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid local_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + 1, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid remote_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + 1, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_DataHolderSeq_deinit(&tokens); +} + +CU_Test(ddssec_builtin_set_remote_datawriter_crypto_tokens, invalid_tokens, .init = suite_set_remote_datawriter_crypto_tokens_init, .fini = suite_set_remote_datawriter_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + DDS_Security_DatawriterCryptoTokenSeq empty_tokens; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens != NULL); + + memset(&tokens, 0, sizeof(tokens)); + memset(&empty_tokens, 0, sizeof(empty_tokens)); + create_writer_tokens(&tokens, 2); + + /* empty token sequence */ + { + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &empty_tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + } + + /* DDS_Security_DatawriterCryptoTokenSeq with empty token */ + { + empty_tokens._length = 1; + empty_tokens._buffer = DDS_Security_DataHolderSeq_allocbuf(1); + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &empty_tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_DataHolderSeq_deinit(&empty_tokens); + } + + /* invalid token class id */ + { + ddsrt_free(tokens._buffer[0].class_id); + tokens._buffer[0].class_id = ddsrt_strdup("invalid class"); + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + } + + /* invalid token class id */ + { + ddsrt_free(tokens._buffer[0].class_id); + tokens._buffer[0].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + ddsrt_free(tokens._buffer[1].class_id); + tokens._buffer[1].class_id = ddsrt_strdup("invalid class"); + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + ddsrt_free(tokens._buffer[1].class_id); + tokens._buffer[1].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + } + + /* no key material, binary_property missing */ + { + tokens._buffer[0].binary_properties._length = 0; + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + tokens._buffer[0].binary_properties._length = 1; + } + + /* no key material, binary_property missing */ + { + tokens._buffer[1].binary_properties._length = 0; + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + tokens._buffer[1].binary_properties._length = 1; + } + + /* no key material, property is empty */ + { + DDS_Security_BinaryProperty_t *saved_buffer = tokens._buffer[0].binary_properties._buffer; + tokens._buffer[0].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + ddsrt_free(tokens._buffer[0].binary_properties._buffer); + tokens._buffer[0].binary_properties._buffer = saved_buffer; + } + + /* invalid property name */ + { + ddsrt_free(tokens._buffer[0].binary_properties._buffer[0].name); + tokens._buffer[0].binary_properties._buffer[0].name = ddsrt_strdup("invalid_key_mat_name"); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + ddsrt_free(tokens._buffer[0].binary_properties._buffer[0].name); + tokens._buffer[0].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + } + + /* invalid property name */ + { + ddsrt_free(tokens._buffer[1].binary_properties._buffer[0].name); + tokens._buffer[1].binary_properties._buffer[0].name = ddsrt_strdup("invalid_key_mat_name"); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + ddsrt_free(tokens._buffer[1].binary_properties._buffer[0].name); + tokens._buffer[1].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); +} + +CU_Test(ddssec_builtin_set_remote_datawriter_crypto_tokens, invalid_key_material, .init = suite_set_remote_datawriter_crypto_tokens_init, .fini = suite_set_remote_datawriter_crypto_tokens_fini) +{ + DDS_Security_boolean result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_DatawriterCryptoTokenSeq tokens; + DDS_Security_KeyMaterial_AES_GCM_GMAC keymat; + + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens != NULL); + memset(&tokens, 0, sizeof(tokens)); + create_writer_tokens_no_key_material(&tokens, 1); + + /* empty key material */ + { + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + } + + /* invalid transform kind */ + { + init_key_material(&keymat, false); + keymat.transformation_kind[2] = 1; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* no master salt */ + { + init_key_material(&keymat, false); + + DDS_Security_OctetSeq_deinit(&keymat.master_salt); + keymat.master_salt._buffer = NULL; + keymat.master_salt._length = keymat.master_salt._maximum = 0; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* empty master salt */ + { + init_key_material(&keymat, false); + + memset(keymat.master_salt._buffer, 0, keymat.master_salt._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* incorrect master salt */ + { + init_key_material(&keymat, false); + + keymat.master_salt._length = 16; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* no master sender key */ + { + init_key_material(&keymat, false); + + DDS_Security_OctetSeq_deinit(&keymat.master_sender_key); + + keymat.master_sender_key._buffer = NULL; + keymat.master_sender_key._length = keymat.master_sender_key._maximum = 0; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* empty master sender key */ + { + init_key_material(&keymat, false); + + memset(keymat.master_sender_key._buffer, 0, keymat.master_sender_key._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* incorrect master sender key */ + { + init_key_material(&keymat, false); + + memset(keymat.master_sender_key._buffer, 0, keymat.master_sender_key._length); + keymat.master_sender_key._length = 16; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* no master receiver specific key */ + { + init_key_material(&keymat, true); + + DDS_Security_OctetSeq_deinit(&keymat.master_receiver_specific_key); + + keymat.master_receiver_specific_key._buffer = NULL; + keymat.master_receiver_specific_key._length = keymat.master_receiver_specific_key._maximum = 0; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* nempty master receiver specific key */ + { + init_key_material(&keymat, true); + + memset(keymat.master_receiver_specific_key._buffer, 0, keymat.master_receiver_specific_key._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* incorrect master receiver specific key */ + { + init_key_material(&keymat, true); + + memset(keymat.master_receiver_specific_key._buffer, 0, keymat.master_receiver_specific_key._length); + keymat.master_receiver_specific_key._length = 16; + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + /* invalid key material */ + { + init_key_material(&keymat, true); + + memset(keymat.master_receiver_specific_key._buffer, 0, keymat.master_receiver_specific_key._length); + serialize_key_material(&tokens._buffer[0].binary_properties._buffer[0].value, &keymat); + + RAND_bytes(tokens._buffer[0].binary_properties._buffer[0].value._buffer, (int) tokens._buffer[0].binary_properties._buffer[0].value._length); + + result = crypto->crypto_key_exchange->set_remote_datawriter_crypto_tokens( + crypto->crypto_key_exchange, + local_reader_crypto, + remote_writer_crypto, + &tokens, + &exception); + + if (!result) + printf("set_remote_datawriter_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + DDS_Security_OctetSeq_deinit(&tokens._buffer[0].binary_properties._buffer[0].value); + deinit_key_material(&keymat); + } + + DDS_Security_DataHolderSeq_deinit(&tokens); +} diff --git a/src/security/builtin_plugins/tests/set_remote_participant_crypto_tokens/src/set_remote_participant_crypto_tokens_utests.c b/src/security/builtin_plugins/tests/set_remote_participant_crypto_tokens/src/set_remote_participant_crypto_tokens_utests.c new file mode 100644 index 0000000..ddaf325 --- /dev/null +++ b/src/security/builtin_plugins/tests/set_remote_participant_crypto_tokens/src/set_remote_participant_crypto_tokens_utests.c @@ -0,0 +1,541 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/core/shared_secret.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "crypto_objects.h" + +#define TEST_SHARED_SECRET_SIZE 32 + +static const char *CRYPTO_TOKEN_CLASS_ID = "DDS:Crypto:AES_GCM_GMA"; +static const char *CRYPTO_TOKEN_PROPERTY_NAME = "dds.cryp.keymat"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_cryptography *crypto = NULL; + +static DDS_Security_IdentityHandle local_participant_identity = 1; +static DDS_Security_IdentityHandle remote_participant_identity = 2; + +static DDS_Security_ParticipantCryptoHandle local_crypto_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoHandle remote_crypto_handle = DDS_SECURITY_HANDLE_NIL; + +static DDS_Security_SharedSecretHandleImpl *shared_secret_handle_impl = NULL; +static DDS_Security_SharedSecretHandle shared_secret_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_ParticipantCryptoTokenSeq tokens; + +static void allocate_shared_secret(void) +{ + shared_secret_handle_impl = ddsrt_malloc(sizeof(DDS_Security_SharedSecretHandleImpl)); + + shared_secret_handle_impl->shared_secret = ddsrt_malloc(TEST_SHARED_SECRET_SIZE * sizeof(unsigned char)); + shared_secret_handle_impl->shared_secret_size = TEST_SHARED_SECRET_SIZE; + for (int i = 0; i < shared_secret_handle_impl->shared_secret_size; i++) + { + shared_secret_handle_impl->shared_secret[i] = (unsigned char)(i % 20); + } + for (int i = 0; i < 32; i++) + { + shared_secret_handle_impl->challenge1[i] = (unsigned char)(i % 15); + shared_secret_handle_impl->challenge2[i] = (unsigned char)(i % 12); + } + shared_secret_handle = (DDS_Security_SharedSecretHandle)shared_secret_handle_impl; +} + +static void deallocate_shared_secret(void) +{ + ddsrt_free(shared_secret_handle_impl->shared_secret); + ddsrt_free(shared_secret_handle_impl); +} + +static void prepare_participant_security_attributes(DDS_Security_ParticipantSecurityAttributes *attributes) +{ + memset(attributes, 0, sizeof(DDS_Security_ParticipantSecurityAttributes)); + attributes->allow_unauthenticated_participants = false; + attributes->is_access_protected = false; + attributes->is_discovery_protected = false; + attributes->is_liveliness_protected = false; + attributes->is_rtps_protected = true; + attributes->plugin_participant_attributes = DDS_SECURITY_PARTICIPANT_ATTRIBUTES_FLAG_IS_VALID; + attributes->plugin_participant_attributes |= DDS_SECURITY_PLUGIN_PARTICIPANT_ATTRIBUTES_FLAG_IS_RTPS_ENCRYPTED; +} + +static int register_local_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle participant_permissions = 3; //valid dummy value + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantSecurityAttributes participant_security_attributes; + + memset(&participant_properties, 0, sizeof(participant_properties)); + memset(&tokens, 0, sizeof(tokens)); + + prepare_participant_security_attributes(&participant_security_attributes); + + local_crypto_handle = + crypto->crypto_key_factory->register_local_participant( + crypto->crypto_key_factory, + local_participant_identity, + participant_permissions, + &participant_properties, + &participant_security_attributes, + &exception); + + if (local_crypto_handle == DDS_SECURITY_HANDLE_NIL) + printf("register_local_participant: %s\n", exception.message ? exception.message : "Error message missing"); + + return local_crypto_handle ? 0 : -1; +} + +static int register_remote_participant(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PermissionsHandle remote_participant_permissions = 5; + + remote_crypto_handle = + crypto->crypto_key_factory->register_matched_remote_participant( + crypto->crypto_key_factory, + local_crypto_handle, + remote_participant_identity, + remote_participant_permissions, + shared_secret_handle, + &exception); + + if (remote_crypto_handle == DDS_SECURITY_HANDLE_NIL) + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + + return remote_crypto_handle ? 0 : -1; +} + +static int create_crypto_tokens(void) +{ + DDS_Security_boolean status; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + status = crypto->crypto_key_exchange->create_local_participant_crypto_tokens( + crypto->crypto_key_exchange, + &tokens, + local_crypto_handle, + remote_crypto_handle, + &exception); + if (!status) + printf("register_matched_remote_participant: %s\n", exception.message ? exception.message : "Error message missing"); + + return status ? 0 : -1; +} + +static void unregister_participants(void) +{ + DDS_Security_boolean status; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + if (tokens._length != 0) + { + status = crypto->crypto_key_exchange->return_crypto_tokens(crypto->crypto_key_exchange, &tokens, &exception); + if (!status) + printf("return_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + } + + if (local_crypto_handle) + { + status = crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, local_crypto_handle, &exception); + if (!status) + printf("unregister_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } + + if (remote_crypto_handle) + { + status = crypto->crypto_key_factory->unregister_participant(crypto->crypto_key_factory, remote_crypto_handle, &exception); + if (!status) + printf("unregister_participant: %s\n", exception.message ? exception.message : "Error message missing"); + } +} + +static void suite_set_remote_participant_crypto_tokens_init(void) +{ + allocate_shared_secret(); + + CU_ASSERT_FATAL ((plugins = load_plugins( + NULL /* Access Control */, + NULL /* Authentication */, + &crypto /* Cryptograpy */)) != NULL); + CU_ASSERT_EQUAL_FATAL (register_local_participant(), 0); + CU_ASSERT_EQUAL_FATAL (register_remote_participant(), 0); + CU_ASSERT_EQUAL_FATAL (create_crypto_tokens(), 0); +} + +static void suite_set_remote_participant_crypto_tokens_fini(void) +{ + unregister_participants(); + deallocate_shared_secret(); + unload_plugins(plugins); +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +CU_Test(ddssec_builtin_set_remote_participant_crypto_tokens, happy_day, .init = suite_set_remote_participant_crypto_tokens_init, .fini = suite_set_remote_participant_crypto_tokens_fini) +{ + DDS_Security_boolean result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->set_remote_participant_crypto_tokens != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + + /* Now call the function. */ + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT_FATAL(result); + CU_ASSERT(exception.code == 0); + CU_ASSERT(exception.message == NULL); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_set_remote_participant_crypto_tokens, invalid_args, .init = suite_set_remote_participant_crypto_tokens_init, .fini = suite_set_remote_participant_crypto_tokens_fini) +{ + DDS_Security_boolean result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq participant_properties; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_participant_crypto_tokens != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + + /* invalid token seq = NULL */ + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + NULL, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid local_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + 0, + remote_crypto_handle, + &tokens, + &exception); + if (!result) + printf("set_remote_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid remote_crypto_handle = DDS_SECURITY_HANDLE_NIL */ + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + 0, + &tokens, + &exception); + if (!result) + printf("set_remote_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid local_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + 1, + remote_crypto_handle, + &tokens, + &exception); + if (!result) + printf("set_remote_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid remote_crypto_handle = 1 */ + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + 1, + &tokens, + &exception); + if (!result) + printf("set_remote_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_set_remote_participant_crypto_tokens, invalid_tokens, .init = suite_set_remote_participant_crypto_tokens_init, .fini = suite_set_remote_participant_crypto_tokens_fini) +{ + DDS_Security_boolean result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_PropertySeq participant_properties; + DDS_Security_ParticipantCryptoTokenSeq invalid_tokens; + DDS_Security_KeyMaterial_AES_GCM_GMAC keymat; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL(crypto != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange != NULL); + CU_ASSERT_FATAL(crypto->crypto_key_exchange->create_local_participant_crypto_tokens != NULL); + + memset(&exception, 0, sizeof(DDS_Security_SecurityException)); + memset(&participant_properties, 0, sizeof(participant_properties)); + memset(&keymat, 0, sizeof(keymat)); + + memset(&invalid_tokens, 0, sizeof(invalid_tokens)); + + /* empty token sequence */ + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* DDS_Security_ParticipantCryptoTokenSeq with empty token */ + invalid_tokens._length = 1; + invalid_tokens._buffer = DDS_Security_DataHolderSeq_allocbuf(1); + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid token class id */ + invalid_tokens._buffer[0].class_id = ddsrt_strdup("invalid class"); + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + ddsrt_free(invalid_tokens._buffer[0].class_id); + reset_exception(&exception); + + /* no key material, binary_property missing */ + invalid_tokens._buffer[0].class_id = ddsrt_strdup(CRYPTO_TOKEN_CLASS_ID); + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* no key material, property is empty */ + invalid_tokens._buffer[0].binary_properties._length = 1; + invalid_tokens._buffer[0].binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* invalid property name */ + invalid_tokens._buffer[0].binary_properties._buffer[0].name = ddsrt_strdup("invalid_key_mat_name"); + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + ddsrt_free(invalid_tokens._buffer[0].binary_properties._buffer[0].name); + reset_exception(&exception); + + /* invalid property name */ + invalid_tokens._buffer[0].binary_properties._buffer[0].name = ddsrt_strdup(CRYPTO_TOKEN_PROPERTY_NAME); + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + /* empty key material */ + invalid_tokens._buffer[0].binary_properties._buffer[0].value._length = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._maximum = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._buffer = (unsigned char *)&keymat; + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + keymat.transformation_kind[3] = 5; + + /* invalid CryptoTransformKind */ + invalid_tokens._buffer[0].binary_properties._buffer[0].value._length = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._maximum = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._buffer = (unsigned char *)&keymat; + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + keymat.transformation_kind[3] = 2; + keymat.master_salt._length = 16; + keymat.master_salt._buffer = DDS_Security_OctetSeq_allocbuf(32); + + /* invalid master salt */ + invalid_tokens._buffer[0].binary_properties._buffer[0].value._length = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._maximum = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._buffer = (unsigned char *)&keymat; + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + keymat.master_salt._length = 32; + + /* invalid master salt */ + invalid_tokens._buffer[0].binary_properties._buffer[0].value._length = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._maximum = 1; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._buffer = (unsigned char *)&keymat; + result = crypto->crypto_key_exchange->set_remote_participant_crypto_tokens( + crypto->crypto_key_exchange, + local_crypto_handle, + remote_crypto_handle, + &invalid_tokens, + &exception); + if (!result) + printf("set_local_participant_crypto_tokens: %s\n", exception.message ? exception.message : "Error message missing"); + + CU_ASSERT(!result); + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + reset_exception(&exception); + + invalid_tokens._buffer[0].binary_properties._buffer[0].value._length = 0; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._maximum = 0; + invalid_tokens._buffer[0].binary_properties._buffer[0].value._buffer = NULL; + DDS_Security_ParticipantCryptoTokenSeq_deinit(&invalid_tokens); + DDS_Security_OctetSeq_deinit(&keymat.master_salt); +} diff --git a/src/security/builtin_plugins/tests/validate_begin_handshake_reply/etc/trusted_ca_dir/identity_ca b/src/security/builtin_plugins/tests/validate_begin_handshake_reply/etc/trusted_ca_dir/identity_ca new file mode 100644 index 0000000..7e2675c --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_begin_handshake_reply/etc/trusted_ca_dir/identity_ca @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEmTCCA4GgAwIBAgIIZ5gEIUFhO5wwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE +BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp +ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDIx +MjE1MDUwMFoYDzIyMjIwMjIyMjIyMjAwWjBfMQswCQYDVQQGEwJOTDETMBEGA1UE +CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk +MRgwFgYDVQQDEw9DSEFNNTAwIHJvb3QgY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQC6Fa3TheL+UrdZCp9GhU/2WbneP2t/avUa3muwDttPxeI2XU9k +ZjBR95mAXme4SPXHk5+YDN319AqIje3oKhzky/ngvKH2GkoJKYxWnuDBfMEHdViz +2Q9/xso2ZvH50ukwWa0pfx2/EVV1wRxeQcRd/UVfq3KTJizG0M88mOYvGEAw3LFf +zef7k1aCuOofQmBvLukUudcYpMzfyHFp7lQqU4CcrrR5RtmfiUfrWfdGLea2iPDB +pJgN8ESOMwEHtOTEBDclYnH9L4t7CHQz+fXXS5IWFsDK9fCMQjnxDsDVeNrNzTYL +FaZrMg9S6IUQCEsQWsnq5weS8omOpVLUm9klAgMBAAGjggFVMIIBUTAMBgNVHRME +BTADAQH/MB0GA1UdDgQWBBQg2FZB/j8uWDVnJhjwXkX278znSTAfBgNVHSMEGDAW +gBQg2FZB/j8uWDVnJhjwXkX278znSTAPBgNVHQ8BAf8EBQMDB/+AMIHvBgNVHSUB +Af8EgeQwgeEGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwME +BggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK +KwYBBAGCNwoDAwYKKwYBBAGCNwoDBAYJYIZIAYb4QgQBBgsrBgEEAYI3CgMEAQYI +KwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUIAgIGCisGAQQBgjcU +AgIGCCsGAQUFBwMJBggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZI +hvcNAQELBQADggEBAKHmwejWRwGE1wf1k2rG8SNRV/neGsZ6Qfqf6co3TpR/Wi1s +iZDvSeT/rbqNBS7z34xnG88NIUwu00y78e8Mfon31ZZbK4Uo7fla9/D3ukdJqPQC +LKdbKJjR2kH+KCukY/1rghjJ8/X+t2egBit0LCOdsFCl07Sfksb9kpGUIZSFcYYm +geqhjhoNwxazzHiw+QWHC5HG9248JIizBmy1aymNWuMnPudhjHAnPcsIlqMVNq3t +Rv9ap7S8JeCxHVRPJvJeCwXWvW3dW/v3xH52Yn/fqRblN1w9Fxz5NhopKx0gj/Jd +sw2N4Fk4gaOWEolFpa0bwNw8nAx7moehZpowzfw= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_begin_handshake_reply/etc/trusted_ca_dir/remote_ca.crt b/src/security/builtin_plugins/tests/validate_begin_handshake_reply/etc/trusted_ca_dir/remote_ca.crt new file mode 100644 index 0000000..6b096a0 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_begin_handshake_reply/etc/trusted_ca_dir/remote_ca.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEKTCCAxGgAwIBAgIBATANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50 +aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu +Y29tMB4XDTE4MDMxMjAwMDAwMFoXDTI3MDMxMTIzNTk1OVowcjELMAkGA1UEBhMC +TkwxCzAJBgNVBAgTAk9WMRMwEQYDVQQKEwpBRExpbmsgSVNUMRkwFwYDVQQDExBJ +ZGVudGl0eSBDQSBUZXN0MSYwJAYJKoZIhvcNAQkBFhdpbmZvQGlzdC5hZGxpbmt0 +ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANa/ENFfGVXg +bPLTzBdDfiZQcp5dWZ//Pb8ErFOJu8uosVHFv8t69dgjHgNHB4OsjmjnR7GfKUZT +0cMvWJnjsC7DDlBwFET9rj4k40n96bbVCH9I7+tNhsoqzc6Eu+5h4sk7VfNGTM2Z +SyCd4GiSZRuA44rRbhXI7/LDpr4hY5J9ZDo5AM9ZyoLAoh774H3CZWD67S35XvUs +72dzE6uKG/vxBbvZ7eW2GLO6ewa9UxlnLVMPfJdpkp/xYXwwcPW2+2YXCge1ujxs +tjrOQJ5HUySh6DkE/kZpx8zwYWm9AaCrsvCIX1thsqgvKy+U5v1FS1L58eGc6s// +9yMgNhU29R0CAwEAAaOByTCBxjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRNVUJN +FzhJPReYT4QSx6dK53CXCTAfBgNVHSMEGDAWgBRNVUJNFzhJPReYT4QSx6dK53CX +CTAPBgNVHQ8BAf8EBQMDB/+AMGUGA1UdJQEB/wRbMFkGCCsGAQUFBwMBBggrBgEF +BQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkGCCsG +AQUFBwMNBggrBgEFBQcDDgYHKwYBBQIDBTANBgkqhkiG9w0BAQsFAAOCAQEAcOLF +ZYdJguj0uxeXB8v3xnUr1AWz9+gwg0URdfNLU2KvF2lsb/uznv6168b3/FcPgezN +Ihl9GqB+RvGwgXS/1UelCGbQiIUdsNxk246P4uOGPIyW32RoJcYPWZcpY+cw11tQ +NOnk994Y5/8ad1DmcxVLLqq5kwpXGWQufV1zOONq8B+mCvcVAmM4vkyF/de56Lwa +sAMpk1p77uhaDnuq2lIR4q3QHX2wGctFid5Q375DRscFQteY01r/dtwBBrMn0wuL +AMNx9ZGD+zAoOUaslpIlEQ+keAxk3jgGMWFMxF81YfhEnXzevSQXWpyek86XUyFL +O9IAQi5pa15gXjSbUg== +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_begin_handshake_reply/etc/trusted_ca_dir/root_CA_RSA.crt b/src/security/builtin_plugins/tests/validate_begin_handshake_reply/etc/trusted_ca_dir/root_CA_RSA.crt new file mode 100644 index 0000000..61346df --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_begin_handshake_reply/etc/trusted_ca_dir/root_CA_RSA.crt @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEtjCCA56gAwIBAgIBATANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50 +aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu +Y29tMB4XDTE4MDYxMTAwMDAwMFoXDTI3MDYxMDIzNTk1OVowcjELMAkGA1UEBhMC +TkwxCzAJBgNVBAgTAk9WMRMwEQYDVQQKEwpBRExpbmsgSVNUMRkwFwYDVQQDExBJ +ZGVudGl0eSBDQSBUZXN0MSYwJAYJKoZIhvcNAQkBFhdpbmZvQGlzdC5hZGxpbmt0 +ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANRf3XKmM6O+ +WoYPNpOAdkGKKZHLJ8ZuPxVVBMX6oJAlcOmkhLzfkHSA+gl/OWaMOXIEtN512gyL +YszBf1RImwVzRjJFwIxzGzVQ68jYNj+qBbsOt+IG+hs3wgVCLFkCh+J7hXUgvk8A +eRM/SRrI42dQfcgKUAMNi4/iX6Vs+FV9pHB63L4PiLA9hfUE25sH6EsIC7icvGDJ +6cGG94glVSHDI1NtXfsNHY+NGY/jYKtQZklqU3lew5I60aJIsea+Wk6PJiz4hyXv +XVVmrcNeG1g4OEFgiSXZC2XknDw8t9+ELprGNvuJvTFxwPMAgLeF4IhEQC9dQY2W +BRwUxtZBzukCAwEAAaOCAVUwggFRMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFER4 +R6N3MQ1Wl7gn+R8wwHloDCVZMB8GA1UdIwQYMBaAFER4R6N3MQ1Wl7gn+R8wwHlo +DCVZMA8GA1UdDwEB/wQFAwMH/4Awge8GA1UdJQEB/wSB5DCB4QYIKwYBBQUHAwEG +CCsGAQUFBwMCBggrBgEFBQcDAwYIKwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3 +AgEVBgorBgEEAYI3AgEWBgorBgEEAYI3CgMBBgorBgEEAYI3CgMDBgorBgEEAYI3 +CgMEBglghkgBhvhCBAEGCysGAQQBgjcKAwQBBggrBgEFBQcDBQYIKwYBBQUHAwYG +CCsGAQUFBwMHBggrBgEFBQgCAgYKKwYBBAGCNxQCAgYIKwYBBQUHAwkGCCsGAQUF +BwMNBggrBgEFBQcDDgYHKwYBBQIDBTANBgkqhkiG9w0BAQsFAAOCAQEAwXuEWDG3 +aAyL+DsGr0B4YMLjHtx6FjzkJOpTtXQhkrtSMpD3Xytl7Wfz8lyWuTnbrk8F4gWO +IkJR/NdMGW27SmeYU0z7QAGRDwtHX6kqqizQbCwf4F6P/2QftcLp1VrlsIlb0gyx +gLjpGmn5TT7gj+ahW0iIRglOwhzCvkNu6agYpdGwVirSyLShy/Hq303DZSbVuktz +5/PmZKpufnoGqURNnJqbV4TQipE0FiDmp2o+gVgJ+DVRhiCdfk68Xp7+TlmxCDfZ +C3qb18qrwAZ4AL3T9/RlzfkXh4ME9V6wqa5Y6j7Vwx5Ef2OHL+mnMnoNSXDLRh6j +45ky66su5dROpA== +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_begin_handshake_reply/src/validate_begin_handshake_reply_utests.c b/src/security/builtin_plugins/tests/validate_begin_handshake_reply/src/validate_begin_handshake_reply_utests.c new file mode 100644 index 0000000..bd2021b --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_begin_handshake_reply/src/validate_begin_handshake_reply_utests.c @@ -0,0 +1,2091 @@ +#include +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/environ.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "config_env.h" + +static const char * AUTH_PROTOCOL_CLASS_ID = "DDS:Auth:PKI-DH:1.0"; +static const char * PERM_ACCESS_CLASS_ID = "DDS:Access:Permissions:1.0"; + +static const char * PROPERTY_IDENTITY_CA = "dds.sec.auth.identity_ca"; +static const char * PROPERTY_PRIVATE_KEY = "dds.sec.auth.private_key"; +static const char * PROPERTY_IDENTITY_CERT = "dds.sec.auth.identity_certificate"; +static const char * PROPERTY_TRUSTED_CA_DIR = "dds.sec.auth.trusted_ca_dir"; + +static const char * PROPERTY_CERT_SUBJECT_NAME = "dds.cert.sn"; +static const char * PROPERTY_CERT_ALGORITHM = "dds.cert.algo"; +static const char * PROPERTY_CA_SUBJECT_NAME = "dds.ca.sn"; +static const char * PROPERTY_CA_ALGORITHM = "dds.ca.aglo"; + +static const char * PROPERTY_PERM_CA_SUBJECT_NAME = "ds.perm_ca.sn"; + +static const char * SUBJECT_NAME_IDENTITY_CERT = "CN=CHAM-574 client,O=Some Company,ST=Some-State,C=NL"; +static const char * SUBJECT_NAME_IDENTITY_CA = "CN=CHAM-574 authority,O=Some Company,ST=Some-State,C=NL"; + +static const char * RSA_2048_ALGORITHM_NAME = "RSA-2048"; + +static const char * AUTH_REQUEST_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+AuthReq"; +static const char * AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME = "future_challenge"; + +static const char * AUTH_HANDSHAKE_REQUEST_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+Req"; +static const char * AUTH_HANDSHAKE_REPLY_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+Reply"; + + +static const char * AUTH_DSIGN_ALGO_RSA_NAME = "RSASSA-PSS-SHA256"; +static const char * AUTH_KAGREE_ALGO_RSA_NAME = "DH+MODP-2048-256"; + +static unsigned char *dh_pubkey_modp_2048_value = NULL; +static unsigned char *invalid_dh_pubkey_modp_2048_value = NULL; +static size_t dh_pubkey_modp_2048_length = 0; + +static const char *identity_certificate = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEQTCCAymgAwIBAgIINpuaAAnrQZIwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE3MDIy\n" + "MjIyMjIwMFoYDzIyMjIwMjIyMjIyMjAwWjBcMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRUwEwYDVQQDEwxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n" + "ggEKAoIBAQDCpVhivH/wBIyu74rvQncnSZqKyspN6CvD1pmV9wft5PHhVt9jV79v\n" + "gSub5LADoRHAgFdv9duYgBr17Ob6uRrIY4B18CcrCjhQcC4gjx8y2jl9PeYm+qYD\n" + "3o44FYBrBq0QCnrQgKsb/qX9Z+Mw/VUiw65x68W876LEHQQoEgT4kxSuagwBoVRk\n" + "ePD6fYAKmT4XS3x+O0v+rHESTcsKF6yMadgp7h3eH1b8kJTzSx8JV9Zzq++mxjox\n" + "qhbBVP5nDze2hhSIeCkCvSrx7efkgKS4AQXa5/Z44GiAu1TfXXUqdic9rxwD0edn\n" + "ajNElnZe7sjok/0yuqvH+2hSqpNva/zpAgMBAAGjggEAMIH9MAwGA1UdDwQFAwMH\n" + "/4AwgewGA1UdJQSB5DCB4QYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYI\n" + "KwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3AgEVBgorBgEEAYI3AgEWBgorBgEE\n" + "AYI3CgMBBgorBgEEAYI3CgMDBgorBgEEAYI3CgMEBglghkgBhvhCBAEGCysGAQQB\n" + "gjcKAwQBBggrBgEFBQcDBQYIKwYBBQUHAwYGCCsGAQUFBwMHBggrBgEFBQgCAgYK\n" + "KwYBBAGCNxQCAgYIKwYBBQUHAwkGCCsGAQUFBwMNBggrBgEFBQcDDgYHKwYBBQID\n" + "BTANBgkqhkiG9w0BAQsFAAOCAQEAawdHy0Xw7nTK2ltp91Ion6fJ7hqYuj///zr7\n" + "Adt6uonpDh/xl3esuwcFimIJrJrHujnGkL0nLddRCikmnzuBMNDWS6yq0/Ckl/YG\n" + "yjNr44dlX24wo+MVAgkj3/8CyWDZ3a8kBg9QT3bs2SqbjmhTrXN1DRyf9S5vJysE\n" + "I7V1gTN66BeKL64hOrAlRVrEu8Ds6TWL6Q/YH+61ViZkoLTeSaPjH4nknaFr4C35\n" + "iji0JhkyfRHRRVPHFnaj25AkxOrSV64qVKoTMjDl5fji5iMGtjm6iJ7q05ml/qDl\n" + "nLotHXemZNvYhbwUmRzbt4Dls9EMH4VRbP85I94nM5TAvtHVNA==\n" + "-----END CERTIFICATE-----\n"; + + +static const char *remote_identity_certificate = + "-----BEGIN CERTIFICATE-----\n" + "MIIEPTCCAyWgAwIBAgIIRmtzSKaI+rowDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDMy\n" + "MzEyMDEwMFoYDzIyMjIwMjIyMjIyMjAwWjBYMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MREwDwYDVQQDEwhDSEFNLTU3NzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" + "ggEBAMKlWGK8f/AEjK7viu9CdydJmorKyk3oK8PWmZX3B+3k8eFW32NXv2+BK5vk\n" + "sAOhEcCAV2/125iAGvXs5vq5GshjgHXwJysKOFBwLiCPHzLaOX095ib6pgPejjgV\n" + "gGsGrRAKetCAqxv+pf1n4zD9VSLDrnHrxbzvosQdBCgSBPiTFK5qDAGhVGR48Pp9\n" + "gAqZPhdLfH47S/6scRJNywoXrIxp2CnuHd4fVvyQlPNLHwlX1nOr76bGOjGqFsFU\n" + "/mcPN7aGFIh4KQK9KvHt5+SApLgBBdrn9njgaIC7VN9ddSp2Jz2vHAPR52dqM0SW\n" + "dl7uyOiT/TK6q8f7aFKqk29r/OkCAwEAAaOCAQAwgf0wDAYDVR0PBAUDAwf/gDCB\n" + "7AYDVR0lBIHkMIHhBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEF\n" + "BQcDBAYIKwYBBQUHAwgGCisGAQQBgjcCARUGCisGAQQBgjcCARYGCisGAQQBgjcK\n" + "AwEGCisGAQQBgjcKAwMGCisGAQQBgjcKAwQGCWCGSAGG+EIEAQYLKwYBBAGCNwoD\n" + "BAEGCCsGAQUFBwMFBggrBgEFBQcDBgYIKwYBBQUHAwcGCCsGAQUFCAICBgorBgEE\n" + "AYI3FAICBggrBgEFBQcDCQYIKwYBBQUHAw0GCCsGAQUFBwMOBgcrBgEFAgMFMA0G\n" + "CSqGSIb3DQEBCwUAA4IBAQAniERWU9f/ijm9t8xuyOujEKDJl0Ded4El9mM5UYPR\n" + "ZSnabPNKQjABBS4sVISIYVwfQxGkPgK0MeMBKqs/kWsZ4rp8h5hlZvxFX8H148mo\n" + "3apNgdc/VylDBW5Ltbrypn/dZh9hFZE8Y/Uvo9HPksVEkjYuFN5v7e8/mwxTcrZ1\n" + "BAZrTlDTiCR046NN1lUs/7oUaNCruFV7AU6RbGYnSzM6plPJHMRa9nzNeO0uPaHK\n" + "kNPe+/UGpMi7cpF9w0M5Z1wW+Nq45bBRejFLQkHSjOEeGL2zi7T1HFAHZQydd6Wo\n" + "zYffGTmyHqIjNArbOWEMYN6s1nqsQS+ifolr0MtfeHad\n" + "-----END CERTIFICATE-----\n"; + +static const char *identity_ca = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEmTCCA4GgAwIBAgIIZ5gEIUFhO5wwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDIx\n" + "MjE1MDUwMFoYDzIyMjIwMjIyMjIyMjAwWjBfMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRgwFgYDVQQDEw9DSEFNNTAwIHJvb3QgY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" + "DwAwggEKAoIBAQC6Fa3TheL+UrdZCp9GhU/2WbneP2t/avUa3muwDttPxeI2XU9k\n" + "ZjBR95mAXme4SPXHk5+YDN319AqIje3oKhzky/ngvKH2GkoJKYxWnuDBfMEHdViz\n" + "2Q9/xso2ZvH50ukwWa0pfx2/EVV1wRxeQcRd/UVfq3KTJizG0M88mOYvGEAw3LFf\n" + "zef7k1aCuOofQmBvLukUudcYpMzfyHFp7lQqU4CcrrR5RtmfiUfrWfdGLea2iPDB\n" + "pJgN8ESOMwEHtOTEBDclYnH9L4t7CHQz+fXXS5IWFsDK9fCMQjnxDsDVeNrNzTYL\n" + "FaZrMg9S6IUQCEsQWsnq5weS8omOpVLUm9klAgMBAAGjggFVMIIBUTAMBgNVHRME\n" + "BTADAQH/MB0GA1UdDgQWBBQg2FZB/j8uWDVnJhjwXkX278znSTAfBgNVHSMEGDAW\n" + "gBQg2FZB/j8uWDVnJhjwXkX278znSTAPBgNVHQ8BAf8EBQMDB/+AMIHvBgNVHSUB\n" + "Af8EgeQwgeEGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwME\n" + "BggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK\n" + "KwYBBAGCNwoDAwYKKwYBBAGCNwoDBAYJYIZIAYb4QgQBBgsrBgEEAYI3CgMEAQYI\n" + "KwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUIAgIGCisGAQQBgjcU\n" + "AgIGCCsGAQUFBwMJBggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZI\n" + "hvcNAQELBQADggEBAKHmwejWRwGE1wf1k2rG8SNRV/neGsZ6Qfqf6co3TpR/Wi1s\n" + "iZDvSeT/rbqNBS7z34xnG88NIUwu00y78e8Mfon31ZZbK4Uo7fla9/D3ukdJqPQC\n" + "LKdbKJjR2kH+KCukY/1rghjJ8/X+t2egBit0LCOdsFCl07Sfksb9kpGUIZSFcYYm\n" + "geqhjhoNwxazzHiw+QWHC5HG9248JIizBmy1aymNWuMnPudhjHAnPcsIlqMVNq3t\n" + "Rv9ap7S8JeCxHVRPJvJeCwXWvW3dW/v3xH52Yn/fqRblN1w9Fxz5NhopKx0gj/Jd\n" + "sw2N4Fk4gaOWEolFpa0bwNw8nAx7moehZpowzfw=\n" + "-----END CERTIFICATE-----\n"; + + +static const char *private_key = + "data:,-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEogIBAAKCAQEAwqVYYrx/8ASMru+K70J3J0maisrKTegrw9aZlfcH7eTx4Vbf\n" + "Y1e/b4Erm+SwA6ERwIBXb/XbmIAa9ezm+rkayGOAdfAnKwo4UHAuII8fMto5fT3m\n" + "JvqmA96OOBWAawatEAp60ICrG/6l/WfjMP1VIsOucevFvO+ixB0EKBIE+JMUrmoM\n" + "AaFUZHjw+n2ACpk+F0t8fjtL/qxxEk3LChesjGnYKe4d3h9W/JCU80sfCVfWc6vv\n" + "psY6MaoWwVT+Zw83toYUiHgpAr0q8e3n5ICkuAEF2uf2eOBogLtU3111KnYnPa8c\n" + "A9HnZ2ozRJZ2Xu7I6JP9Mrqrx/toUqqTb2v86QIDAQABAoIBAC1q32DKkx+yMBFx\n" + "m32QiLUGG6VfBC2BixS7MkMnzRXZYgcuehl4FBc0kLRjfB6cqsO8LqrVN1QyMBhK\n" + "GutN3c38SbE7RChqzhEW2+yE+Mao3Nk4ZEecHLiyaYT0n25ZtHAVwep823BAzwJ+\n" + "BykbM45VEpNKbG1VjSktjBa9faNyZiZAEJEjVyla+6R8N4kHV52LbZcLjvJv3IQ2\n" + "iPYRrmMyI5C23qTni0vy7yJbAXBo3CqgSlwie9FARBWT7Puu7F4mF1O1c/SnTysw\n" + "Tm3e5FzgfHipQbnRVn0w4rDprPMKmPxMnvf/Wkw0zVgNadp1Tc1I6Yj525DEQ07i\n" + "2gIn/gECgYEA4jNnY1u2Eu7x3pAQF3dRO0x35boVtuq9iwQk7q+uaZaK4RJRr+0Y\n" + "T68S3bPnfer6SHvcxtST89Bvs/j/Ky4SOaX037UYjFh6T7OIzPl+MzO1yb+VOBT6\n" + "D6FVGEJGp8ZAITU1OfJPeTYViUeEC8tHFGoKUCk50FbB6jOf1oKtv/ECgYEA3EnB\n" + "Y7kSbJJaUuj9ciFUL/pAno86Cim3VjegK1wKgEiyDb610bhoMErovPwfVJbtcttG\n" + "eKJNuwizkRcVbj+vpjDvqqaP5eMxLl6/Nd4haPMJYzGo88Z8NJpwFRNF2KEWjOpQ\n" + "2NEvoCeRtVulCJyka2Tpljzw8cOXkxhPOe2UhHkCgYBo3entj0QO7QXm56T+LAvV\n" + "0PK45xdQEO3EuCwjGAFk5C0IgUSrqeCeeIzniZMltj1IQ1wsNbtNynEu3530t8wt\n" + "O7oVyFBUKGSz9IjUdkpClJOPr6kPMfJoMqRPtdIpz+hFPPSrI6IikKdVWHloOlp+\n" + "pVaYqTQrWT1XRY2xli3VEQKBgGySmZN6Cx+h/oywswIGdUT0VdcQhq2to+QFpJba\n" + "VX6m1cM6hMip2Ag9U3qZ1SNPBBdBBfm9HQybHE3dj713/C2wHuAAGhpXIM1W+20k\n" + "X1knuC/AsSH9aQhQOf/ZMOq1crTfZBuI9q0782/sjGmzMsKPySU4QhUWruVb7OiD\n" + "NVkZAoGAEvihW7G+8/iOE40vGHyBqUeopAAWLciTAUIEwM/Oi3BYfNWNTWF/FWNc\n" + "nMvCZPYigY8C1vO+1iT2Frtd3CIU+f01Q3fJNJoRLlEiKLNZUJRF48OKUqjKSmsi\n" + "w6pucFO40z05YW7utApj4L82rZnOS0pd1tUI1yexqvj0i4ThJfk=\n" + "-----END RSA PRIVATE KEY-----\n"; + + +static const char *diffie_hellman_pubkey = + "-----BEGIN PUBLIC KEY-----\n" + "MIICJDCCARcGCSqGSIb3DQEDATCCAQgCggEBAJxLLigSIC7JjO/kdQ7LT1v0FPvM\n" + "Cq4hZrg6cX1IKzinaJJai3CcWpjMxoJ+jDBh2iekZavJli9qa400FC94UchqsE8s\n" + "I68LRbSkocvSWHOyayGrn04XLvhZPwulZFfEZ0xmg+vcTt2xS5IvX0qC1nrMpVu9\n" + "d9A93n+PZqRWJcJThoApChRT0lVp6CC9dn7oVnIPWyGfUZH9UOzXrx8Rq6wKnWPs\n" + "G0Igaia4uLDIqGKJ1Nr2HmLY8exKcK539X38I2NokzQrwhKdBlIXF5yYGhH+ib0U\n" + "yrdbK1kJBiaXh2CMMPQ7skXZDeQ/ixgTI/cXwaMC3ddE+7l/GTHo/azJawsCAQID\n" + "ggEFAAKCAQB3SB4wP5voPc5YcUpFiJXXlQe7DQxfzo5Mq1A/e8Raw/qzCkJMkcoT\n" + "v656vj4s7PbmzWLDLs0mAD7lU4U+HSnhuBmP46aIZVZORZqQmhzn073iqPiRN8eC\n" + "XPXgsMc8sgpbOoUGo89nuMGaucu2i4ZpLdJTkoFfC6wE2wZg11mr/hfX7+KmKSSp\n" + "V/+h6wROt824MijsuDjxHgZJWuM1jqzFq5skMJ84uwBF5LG3A6sTFnobBQXily5H\n" + "vYh/wWf+lRxeoNRW6B0t7xukZ+a71gg2Fxtm1f3RkLh4IcWfuYAcn5R9Hvgvx7Ex\n" + "DrqVRGbTZZa7fgtiQjj7HF6Cg/btOz2T\n" + "-----END PUBLIC KEY-----\n"; + +static const char *unrelated_identity = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIDpDCCAoygAwIBAgIJALE5lRKfYHAaMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV\n" + "BAYTAk5MMRMwEQYDVQQIDApPdmVyaWpzc2VsMRAwDgYDVQQHDAdIZW5nZWxvMQ8w\n" + "DQYDVQQKDAZBRExJTksxGDAWBgNVBAMMD0NIQU01MDAgUm9vdCBDQTAeFw0xODAy\n" + "MDkxNjIwNDNaFw0zODAyMDQxNjIwNDNaMF8xCzAJBgNVBAYTAk5MMRMwEQYDVQQI\n" + "DApPdmVyaWpzc2VsMRAwDgYDVQQHDAdIZW5nZWxvMQ8wDQYDVQQKDAZBRExJTksx\n" + "GDAWBgNVBAMMD0NIQU01MDAgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" + "ADCCAQoCggEBAN9/NbpJDHQYHh3cEByRxnHffxEe9Sapn08Ty5xYO8LDJ4V7vU32\n" + "/7291fITiHaovOoCRHAbKTaTtqJO56aGY45HON6KIqxljLQJJVGW/Nf2PNSHmFix\n" + "6D6bsoSOTPyKYqBNT6lB7NMn4QBTcsiE61El8p9WLQZHoYQJK5Psf7wkBqGBz8he\n" + "bcDWXFn7kIgnsaLrh77w2wi/y0MqpPwyeRInoZfYknzVNdxCPgq7csBYDoMgOgkV\n" + "G60ECXojHKz1HI4n0V8L8lZluSSVRNR0xvPFgBqO7b+Re7xb6iO9TNsFeoiMMNyp\n" + "EwM99CqPO0RRrAPiC7IDgcNGjxhne9EJFGsCAwEAAaNjMGEwHQYDVR0OBBYEFCst\n" + "gj5Ecm3HU/N7wxJluFo5+6XUMB8GA1UdIwQYMBaAFCstgj5Ecm3HU/N7wxJluFo5\n" + "+6XUMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB\n" + "CwUAA4IBAQCWibvYuPLpoNcsUdHbE7SnBbEQnDfBxBZN8xeWHwwAPEB+8eHhmIdZ\n" + "xDtCN61xr5QR+KzlEYFwKyHMp9GN3OPU1RndJrzaXz2ddAZVkBIvnQZ4JvFd+sBC\n" + "QQgEvL8GcwZPxnad/TRylM4ON3Kh0X9vfyrmWEoHephiE1LcENaFqcYr9xg3DJNh\n" + "XSrigMGZJ7IOHkvgaoneICOcYI42ZHS0fnt1G+01VKJXm3ndi5NL25GnOmlvV6yV\n" + "+1vcmdQc6YS8K8vHmrH4lX9iPfsOak6WSzzsXdqgpvyxtGJggcFaDTtmbWCAkJj0\n" + "B7DMeaVlLClGQaKZZ7aexEx9se+IyLn2\n" + "-----END CERTIFICATE-----\n"; + + +static const char *remote_identity_trusted = + "-----BEGIN CERTIFICATE-----\n" + "MIIDcDCCAligAwIBAgIBBTANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL\n" + "MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50\n" + "aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu\n" + "Y29tMB4XDTE4MDMxMjAwMDAwMFoXDTI3MDMxMTIzNTk1OVowcDELMAkGA1UEBhMC\n" + "TkwxCzAJBgNVBAgTAk9WMQ8wDQYDVQQKEwZBRExpbmsxETAPBgNVBAsTCElTVCBU\n" + "ZXN0MREwDwYDVQQDEwhCb2IgVGVzdDEdMBsGCSqGSIb3DQEJARYOYm9iQGFkbGlu\n" + "ay5pc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDB5vqhuWnwhxXZ\n" + "qffPmfjzge7w91oX4ISlboIfBXp3sLj2mqLSsYhgBNJAn/Fl1OZeFw0d4gVibBgx\n" + "5Zdcjsi+ClvYK8H534iTJfNriMyhg4kSWxZF1Tixfw3FS7LqjKEY5ZNPfp5a4P+8\n" + "UveorYJusrnlv1DiF6aPhJQh8J62J6bhx62DNLO7dZbN0BUsnWtyDcfi5DOjf2/r\n" + "3lSRfecn3uBr1QYRaS5FrV+MSoGcjI3M75mei1TTUp7YT4ZWRR5rKUMql605xsms\n" + "d6sqJaKofYmw7wCuaVJ86pb/w8srdddKt21xUeQNMKn49H6raezMOE3U5BUMtZ+P\n" + "2OBLk/CPAgMBAAGjEzARMA8GA1UdDwEB/wQFAwMH/4AwDQYJKoZIhvcNAQELBQAD\n" + "ggEBAJV71Ckf1zsks5mJXqdUb8bTVHg4hN32pwjCL5c6W2XHAv+YHwE/fN3C1VIY\n" + "bC8zjUC9dCOyC2AvOQyZQ1eC/WoK6FlXjHVX2upL4lXQ9WL9ztt1mgdRrhvUPuUn\n" + "aBE8VgNU0t4jl93xMIaU8hB0kQsV+kdcN0cWbrF3mT4s9njRvopJ8hS2UE60V2wA\n" + "ceUOazH+QGPh1k0jkynrTlVR9GrpebQwZ2UFeinVO0km17IAyQkz+OmPc4jQLJMl\n" + "CmkbmMwowdLMKC6r/HyE87dN7NvFnRM5iByJklRwN7WDYZrl72HoUOlgTZ7PjW2G\n" + "jTxK8xXtDCXC/3CNpe0YFnOga8g=\n" + "-----END CERTIFICATE-----\n"; + +static const char *remote_identity_untrusted = + "-----BEGIN CERTIFICATE-----\n" + "MIIELTCCAxWgAwIBAgIBATANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJOTDEL\n" + "MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGzAZBgNVBAMTEkJvYiBU\n" + "ZXN0IFVudHJ1c3RlZDEmMCQGCSqGSIb3DQEJARYXaW5mb0Bpc3QuYWRsaW5rdGVj\n" + "aC5jb20wHhcNMTgwNjIwMDAwMDAwWhcNMjcwNjE5MjM1OTU5WjB0MQswCQYDVQQG\n" + "EwJOTDELMAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGzAZBgNVBAMT\n" + "EkJvYiBUZXN0IFVudHJ1c3RlZDEmMCQGCSqGSIb3DQEJARYXaW5mb0Bpc3QuYWRs\n" + "aW5rdGVjaC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDB5vqh\n" + "uWnwhxXZqffPmfjzge7w91oX4ISlboIfBXp3sLj2mqLSsYhgBNJAn/Fl1OZeFw0d\n" + "4gVibBgx5Zdcjsi+ClvYK8H534iTJfNriMyhg4kSWxZF1Tixfw3FS7LqjKEY5ZNP\n" + "fp5a4P+8UveorYJusrnlv1DiF6aPhJQh8J62J6bhx62DNLO7dZbN0BUsnWtyDcfi\n" + "5DOjf2/r3lSRfecn3uBr1QYRaS5FrV+MSoGcjI3M75mei1TTUp7YT4ZWRR5rKUMq\n" + "l605xsmsd6sqJaKofYmw7wCuaVJ86pb/w8srdddKt21xUeQNMKn49H6raezMOE3U\n" + "5BUMtZ+P2OBLk/CPAgMBAAGjgckwgcYwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU\n" + "QpxLPHT5o/GQRwdBw2scINXnWlUwHwYDVR0jBBgwFoAUQpxLPHT5o/GQRwdBw2sc\n" + "INXnWlUwDwYDVR0PAQH/BAUDAwf/gDBlBgNVHSUBAf8EWzBZBggrBgEFBQcDAQYI\n" + "KwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwgGCCsGAQUFBwMJ\n" + "BggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggEB\n" + "ABcyab7F7OAsjUSW0YWkVRX1SUMkW25xLLs8koXhHrdnBqgnmOur0xO72/fmTTX9\n" + "KnCUmQj+dAOmmZrAaIZzqLtMyp4ibHZPfOBwmM0MFnyuwyEnCEYvjPN3FTB0HEgS\n" + "vCoFH1001LVi4oC1mEMxYaNW4/5Tgl+DTqGF+tctJe3hvbxh+Uu5M0320VAvASjt\n" + "cJ0me6Ug1FJJ60tgXgZ+M/8V6AXhrQGNgN6WkPMFbbLi5IyEld186QPeLdZ8vCtz\n" + "StjIV9HZGR1XLotlXarbjVtjxavZJjtwiySeYkAgG7Zjy7LalPSJiIdAD3R/ny+S\n" + "9kXDKiw/HgYxb8xiy9gdlSc=\n" + "-----END CERTIFICATE-----\n"; + +static const char *remote_identity_trusted_expired = + "-----BEGIN CERTIFICATE-----\n" + "MIIEKTCCAxGgAwIBAgIBBjANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL\n" + "MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50\n" + "aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu\n" + "Y29tMB4XDTE4MDMwMTAwMDAwMFoXDTE4MDQyMzIzNTk1OVowcjELMAkGA1UEBhMC\n" + "TkwxCzAJBgNVBAgTAk9WMRMwEQYDVQQKEwpBRExpbmsgSVNUMRkwFwYDVQQDExBC\n" + "b2IgVGVzdCBFeHBpcmVkMSYwJAYJKoZIhvcNAQkBFhdpbmZvQGlzdC5hZGxpbmt0\n" + "ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMHm+qG5afCH\n" + "Fdmp98+Z+POB7vD3WhfghKVugh8FenewuPaaotKxiGAE0kCf8WXU5l4XDR3iBWJs\n" + "GDHll1yOyL4KW9grwfnfiJMl82uIzKGDiRJbFkXVOLF/DcVLsuqMoRjlk09+nlrg\n" + "/7xS96itgm6yueW/UOIXpo+ElCHwnrYnpuHHrYM0s7t1ls3QFSyda3INx+LkM6N/\n" + "b+veVJF95yfe4GvVBhFpLkWtX4xKgZyMjczvmZ6LVNNSnthPhlZFHmspQyqXrTnG\n" + "yax3qyoloqh9ibDvAK5pUnzqlv/Dyyt110q3bXFR5A0wqfj0fqtp7Mw4TdTkFQy1\n" + "n4/Y4EuT8I8CAwEAAaOByTCBxjAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRCnEs8\n" + "dPmj8ZBHB0HDaxwg1edaVTAfBgNVHSMEGDAWgBRNVUJNFzhJPReYT4QSx6dK53CX\n" + "CTAPBgNVHQ8BAf8EBQMDB/+AMGUGA1UdJQEB/wRbMFkGCCsGAQUFBwMBBggrBgEF\n" + "BQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkGCCsG\n" + "AQUFBwMNBggrBgEFBQcDDgYHKwYBBQIDBTANBgkqhkiG9w0BAQsFAAOCAQEAdY5n\n" + "5ElOhpHq/YPWUs68t8HNIhqfokqjLZAgzNyU5QFppb9tPpmFCugerfjlScNwp5HB\n" + "X6/WjK4runDrgzXfmrBogR4Kscb1KJSm8KAmnzXVUNr1iyASlHxI7241kYdQvTH2\n" + "LL6b0kjsD5lKAnNh4id0SDHfy/CKg5d7dUxxO1mX48jUiIZtmFqgjej8tFLHy/w/\n" + "usI5ErlI0qzI6lkoRxPCEWLbXWeBDm3/smHeDbYa/+Lw4Bid8U1+ZSAuC1CT7a7F\n" + "O3gAjPUL0jzRztp5Yj3dYPV8YyJHLEKr75IXNedV9YKhT4f6kTS3UEjMTqYbYsix\n" + "MtqgY283RjsExzjNvw==\n" + "-----END CERTIFICATE-----\n"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_authentication *auth = NULL; +static DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_IdentityHandle remote_identity_handle1 = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_IdentityHandle remote_identity_handle2 = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_AuthRequestMessageToken g_local_auth_request_token = DDS_SECURITY_TOKEN_INIT; +static DDS_Security_AuthRequestMessageToken g_remote_auth_request_token = DDS_SECURITY_TOKEN_INIT; +static const DDS_Security_BinaryProperty_t *challenge1 = NULL; +static const DDS_Security_BinaryProperty_t *challenge2 = NULL; +static DDS_Security_OctetSeq serialized_participant_data = DDS_SECURITY_SEQUENCE_INIT; +static DDS_Security_ParticipantBuiltinTopicData *remote_participant_data1 = NULL; +static DDS_Security_ParticipantBuiltinTopicData *remote_participant_data2 = NULL; +static DDS_Security_ParticipantBuiltinTopicData *remote_participant_data3 = NULL; +static DDS_Security_GUID_t candidate_participant_guid; +static DDS_Security_GUID_t remote_participant_guid1; +static DDS_Security_GUID_t remote_participant_guid2; +static bool future_challenge_done = false; + + +#if OPENSSL_VERSION_NUMBER >= 0x1000200fL +#define AUTH_INCLUDE_EC +#include +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#define AUTH_INCLUDE_DH_ACCESSORS +#endif +#else +#error "version not found" +#endif + + +static const BIGNUM * +dh_get_public_key( + DH *dhkey) +{ +#ifdef AUTH_INCLUDE_DH_ACCESSORS + const BIGNUM *pubkey, *privkey; + DH_get0_key(dhkey, &pubkey, &privkey); + return pubkey; +#else + return dhkey->pub_key; +#endif +} + + +static void +serializer_participant_data( + DDS_Security_ParticipantBuiltinTopicData *pdata, + unsigned char **buffer, + size_t *size); + +static void +dds_security_property_init( + DDS_Security_PropertySeq *seq, + DDS_Security_unsigned_long size) +{ + seq->_length = size; + seq->_maximum = size; + seq->_buffer = ddsrt_malloc(size * sizeof(DDS_Security_Property_t)); + memset(seq->_buffer, 0, size * sizeof(DDS_Security_Property_t)); +} + +static void +dds_security_property_deinit( + DDS_Security_PropertySeq *seq) +{ + uint32_t i; + + for (i = 0; i < seq->_length; i++) { + ddsrt_free(seq->_buffer[i].name); + ddsrt_free(seq->_buffer[i].value); + } + ddsrt_free(seq->_buffer); +} + +static void +reset_exception( + DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static char * +get_openssl_error( + void) +{ + BIO *bio = BIO_new(BIO_s_mem()); + char *msg; + char *buf = NULL; + size_t len; + + if (bio) { + ERR_print_errors(bio); + len = (size_t) BIO_get_mem_data (bio, &buf); + msg = (char *) ddsrt_malloc(len + 1); + memset(msg, 0, len+1); + memcpy(msg, buf, len); + BIO_free(bio); + } else { + msg = ddsrt_strdup("BIO_new failed"); + } + + return msg; +} + +static void +initialize_identity_token( + DDS_Security_IdentityToken *token, + const char *certAlgo, + const char *caAlgo) +{ + memset(token, 0, sizeof(*token)); + + token->class_id = ddsrt_strdup(AUTH_PROTOCOL_CLASS_ID); + token->properties._maximum = 4; + token->properties._length = 4; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(4); + + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_CERT_SUBJECT_NAME); + token->properties._buffer[0].value = ddsrt_strdup(SUBJECT_NAME_IDENTITY_CERT); + token->properties._buffer[0].propagate = true; + + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_CERT_ALGORITHM); + token->properties._buffer[1].value = ddsrt_strdup(certAlgo); + token->properties._buffer[1].propagate = true; + + token->properties._buffer[2].name = ddsrt_strdup(PROPERTY_CA_SUBJECT_NAME); + token->properties._buffer[2].value = ddsrt_strdup(SUBJECT_NAME_IDENTITY_CA); + token->properties._buffer[2].propagate = true; + + token->properties._buffer[3].name = ddsrt_strdup(PROPERTY_CA_ALGORITHM); + token->properties._buffer[3].value = ddsrt_strdup(caAlgo); + token->properties._buffer[3].propagate = true; +} + +static void +initialize_permissions_token( + DDS_Security_PermissionsToken *token, + const char *caAlgo) +{ + token->class_id = ddsrt_strdup(PERM_ACCESS_CLASS_ID); + token->properties._length = 2; + token->properties._maximum = 2; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(4); + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_CERT_SUBJECT_NAME); + token->properties._buffer[0].value = ddsrt_strdup(SUBJECT_NAME_IDENTITY_CA); + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_PERM_CA_SUBJECT_NAME); + token->properties._buffer[1].value = ddsrt_strdup(caAlgo); +} + + + +static void +fill_auth_request_token( + DDS_Security_AuthRequestMessageToken *token) +{ + uint32_t i; + uint32_t len = 32; + unsigned char *challenge; + + challenge = ddsrt_malloc(len); + + for (i = 0; i < len; i++) { + challenge[i] = (unsigned char)(0xFF - i); + } + + memset(token, 0, sizeof(*token)); + + token->class_id = ddsrt_strdup(AUTH_REQUEST_TOKEN_CLASS_ID); + token->binary_properties._maximum = 1; + token->binary_properties._length = 1; + token->binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + token->binary_properties._buffer->name = ddsrt_strdup(AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + + token->binary_properties._buffer->value._maximum = len; + token->binary_properties._buffer->value._length = len; + token->binary_properties._buffer->value._buffer = challenge; +} + +static DDS_Security_BinaryProperty_t * +find_binary_property( + DDS_Security_DataHolder *token, + const char *name) +{ + DDS_Security_BinaryProperty_t *result = NULL; + uint32_t i; + + for (i = 0; i < token->binary_properties._length && !result; i++) { + if (token->binary_properties._buffer[i].name && (strcmp(token->binary_properties._buffer[i].name, name) == 0)) { + result = &token->binary_properties._buffer[i]; + } + } + + return result; +} + + +static void +deinitialize_identity_token( + DDS_Security_IdentityToken *token) +{ + DDS_Security_DataHolder_deinit(token); +} + +static int +validate_local_identity(const char* trusted_ca_dir) +{ + int res = 0; + DDS_Security_ValidationResult_t result; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GUID_t local_participant_guid; + DDS_Security_GuidPrefix_t prefix = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb}; + DDS_Security_EntityId_t entityId = {{0xb0,0xb1,0xb2},0x1}; + DDS_Security_ParticipantBuiltinTopicData *local_participant_data; + unsigned char *sdata; + size_t sz; + + memset(&local_participant_guid, 0, sizeof(local_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + memset(&participant_qos, 0, sizeof(participant_qos)); + if( trusted_ca_dir != NULL){ + char trusted_ca_dir_path[1024]; + dds_security_property_init(&participant_qos.property.value, 4); +#ifdef WIN32 + snprintf(trusted_ca_dir_path, 1024, "%s\\validate_begin_handshake_reply\\etc\\%s", CONFIG_ENV_TESTS_DIR,trusted_ca_dir); +#else + snprintf(trusted_ca_dir_path, 1024, "%s/validate_begin_handshake_reply/etc/%s", CONFIG_ENV_TESTS_DIR, trusted_ca_dir); +#endif + participant_qos.property.value._buffer[3].name = ddsrt_strdup(PROPERTY_TRUSTED_CA_DIR); + participant_qos.property.value._buffer[3].value = ddsrt_strdup(trusted_ca_dir_path); + } + else{ + dds_security_property_init(&participant_qos.property.value, 3); + } + participant_qos.property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + participant_qos.property.value._buffer[0].value = ddsrt_strdup(identity_certificate); + participant_qos.property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + participant_qos.property.value._buffer[1].value = ddsrt_strdup(identity_ca); + participant_qos.property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + participant_qos.property.value._buffer[2].value = ddsrt_strdup(private_key); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &local_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + res = -1; + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + local_participant_data = DDS_Security_ParticipantBuiltinTopicData_alloc(); + memcpy(&local_participant_data->key[0], &local_participant_guid, 12); + /* convert from big-endian format to native format */ + local_participant_data->key[0] = ddsrt_fromBE4u(local_participant_data->key[0]); + local_participant_data->key[1] = ddsrt_fromBE4u(local_participant_data->key[1]); + local_participant_data->key[2] = ddsrt_fromBE4u(local_participant_data->key[2]); + + initialize_identity_token(&local_participant_data->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + initialize_permissions_token(&local_participant_data->permissions_token, RSA_2048_ALGORITHM_NAME); + + local_participant_data->security_info.participant_security_attributes = 0x01; + local_participant_data->security_info.plugin_participant_security_attributes = 0x02; + + serializer_participant_data(local_participant_data, &sdata, &sz); + + serialized_participant_data._length = serialized_participant_data._maximum = (uint32_t) sz; + serialized_participant_data._buffer = sdata; + + DDS_Security_ParticipantBuiltinTopicData_free(local_participant_data); + + return res; +} + +static void +release_local_identity(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (local_identity_handle != DDS_SECURITY_HANDLE_NIL) { + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + local_identity_handle = DDS_SECURITY_HANDLE_NIL; + } + DDS_Security_OctetSeq_deinit(&serialized_participant_data); +} + + +static X509 * +load_certificate( + const char *data) +{ + X509 *cert = NULL; + BIO *bio; + + bio = BIO_new_mem_buf((void *) data, -1); + if (!bio) { + return NULL; + } + + cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); + + BIO_free(bio); + + return cert; +} + +static int +get_adjusted_participant_guid( + X509 *cert, + const DDS_Security_GUID_t *candidate, + DDS_Security_GUID_t *adjusted) +{ + int result = 0; + unsigned char high[SHA256_DIGEST_LENGTH], low[SHA256_DIGEST_LENGTH]; + unsigned char *subject; + DDS_Security_octet hb = 0x80; + X509_NAME *name; + unsigned char *tmp = NULL; + int i; + size_t sz; + + name = X509_get_subject_name(cert); + sz = (size_t) i2d_X509_NAME(name, &tmp); + if (sz > 0) { + subject = ddsrt_malloc( sz); + memcpy(subject, tmp, sz); + OPENSSL_free(tmp); + + SHA256(subject, sz, high); + SHA256(&candidate->prefix[0], sizeof(DDS_Security_GuidPrefix_t), low); + + adjusted->entityId = candidate->entityId; + for (i = 0; i < 6; i++) { + adjusted->prefix[i] = hb | high[i]>>1; + hb = (unsigned char) ( high[i]<<7 ); + } + for (i = 0; i < 6; i++) { + adjusted->prefix[i+6] = low[i]; + } + ddsrt_free(subject); + result = 1; + } + + return result; +} + +static int +set_dh_public_key( + const char *keystr, + unsigned char **pubkey, + size_t *size) +{ + int r = 0; + BIO *bio = NULL; + EVP_PKEY *pkey; + DH *dhkey; + unsigned char *buffer = NULL; + ASN1_INTEGER *asn1int; + + *pubkey = NULL; + + + /* load certificate in buffer */ + bio = BIO_new_mem_buf((void *) keystr, -1); + if (!bio) { + char *msg = get_openssl_error(); + r = -1; + printf("BIO_new_mem_buf failed: %s", msg); + ddsrt_free(msg); + goto fail_alloc_bio; + } + + pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); + if (!pkey) { + char *msg = get_openssl_error(); + r = -1; + printf("Failed to read public key: %s", msg); + ddsrt_free(msg); + goto fail_key_read; + } + + dhkey = EVP_PKEY_get1_DH(pkey); + if (!dhkey) { + char *msg = get_openssl_error(); + r = -1; + printf("Failed to get DH key from PKEY: %s", msg); + ddsrt_free(msg); + goto fail_get_dhkey; + } + + asn1int = BN_to_ASN1_INTEGER(dh_get_public_key(dhkey), NULL); + + if (!asn1int) { + char *msg = get_openssl_error(); + r = -1; + printf("Failed to convert DH key to ASN1 integer: %s", msg); + ddsrt_free(msg); + goto fail_get_pubkey; + } + + *size = (size_t)i2d_ASN1_INTEGER(asn1int, &buffer); + + *pubkey = ddsrt_malloc(*size); + memcpy(*pubkey, buffer, *size); + ddsrt_free(buffer); + + ASN1_INTEGER_free(asn1int); + +fail_get_pubkey: + DH_free(dhkey); +fail_get_dhkey: + EVP_PKEY_free(pkey); +fail_key_read: + BIO_free(bio); +fail_alloc_bio: + return r; +} + + +static int +set_dh_keys(void) +{ + int r; + + r = set_dh_public_key(diffie_hellman_pubkey, &dh_pubkey_modp_2048_value, &dh_pubkey_modp_2048_length); + if (r) { + invalid_dh_pubkey_modp_2048_value = ddsrt_malloc(dh_pubkey_modp_2048_length); + memcpy(invalid_dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length); + invalid_dh_pubkey_modp_2048_value[0] = 0x8; + } + return r; +} + + +static int +validate_remote_identities (const char *remote_id_certificate) +{ + int res = 0; + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityToken remote_identity_token; + static DDS_Security_AuthRequestMessageToken local_auth_request_token = DDS_SECURITY_TOKEN_INIT; + DDS_Security_GUID_t guid1; + DDS_Security_GUID_t guid2; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix1 = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab}; + DDS_Security_GuidPrefix_t prefix2 = {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb}; + DDS_Security_EntityId_t entityId = {{0xb0,0xb1,0xb2},0x1}; + X509 *cert; + + memcpy(&guid1.prefix, &prefix1, sizeof(prefix1)); + memcpy(&guid1.entityId, &entityId, sizeof(entityId)); + memcpy(&guid2.prefix, &prefix2, sizeof(prefix2)); + memcpy(&guid2.entityId, &entityId, sizeof(entityId)); + + if (local_identity_handle == DDS_SECURITY_HANDLE_NIL) { + return -1; + } + + cert = load_certificate(remote_id_certificate); + if (!cert) { + return -1; + } + + if (!get_adjusted_participant_guid(cert, &guid1, &remote_participant_guid1)) { + X509_free(cert); + return -1; + } + + if (!get_adjusted_participant_guid(cert, &guid2, &remote_participant_guid2)) { + X509_free(cert); + return -1; + } + + X509_free(cert); + + initialize_identity_token(&remote_identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle1, + &g_local_auth_request_token, + NULL, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid1, + &exception); + + if ((result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST) && + (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE)) { + res = -1; + printf("validate_remote_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + reset_exception(&exception); + + fill_auth_request_token(&g_remote_auth_request_token); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle2, + &local_auth_request_token, + &g_remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid2, + &exception); + + if ((result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST) && + (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE)) { + res = -1; + printf("validate_remote_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + reset_exception(&exception); + + deinitialize_identity_token(&remote_identity_token); + DDS_Security_DataHolder_deinit(&local_auth_request_token); + + remote_participant_data1 = DDS_Security_ParticipantBuiltinTopicData_alloc(); + memcpy(&remote_participant_data1->key[0], &remote_participant_guid1, 12); + remote_participant_data1->key[0] = ddsrt_fromBE4u(remote_participant_data1->key[0]); + remote_participant_data1->key[1] = ddsrt_fromBE4u(remote_participant_data1->key[1]); + remote_participant_data1->key[2] = ddsrt_fromBE4u(remote_participant_data1->key[2]); + + + initialize_identity_token(&remote_participant_data1->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + initialize_permissions_token(&remote_participant_data1->permissions_token, RSA_2048_ALGORITHM_NAME); + + remote_participant_data1->security_info.participant_security_attributes = 0x01; + remote_participant_data1->security_info.plugin_participant_security_attributes = 0x02; + + remote_participant_data2 = DDS_Security_ParticipantBuiltinTopicData_alloc(); + memcpy(&remote_participant_data2->key[0], &remote_participant_guid2, 12); + remote_participant_data2->key[0] = ddsrt_fromBE4u(remote_participant_data2->key[0]); + remote_participant_data2->key[1] = ddsrt_fromBE4u(remote_participant_data2->key[1]); + remote_participant_data2->key[2] = ddsrt_fromBE4u(remote_participant_data2->key[2]); + + initialize_identity_token(&remote_participant_data2->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + initialize_permissions_token(&remote_participant_data2->permissions_token, RSA_2048_ALGORITHM_NAME); + + remote_participant_data2->security_info.participant_security_attributes = 0x01; + remote_participant_data2->security_info.plugin_participant_security_attributes = 0x02; + + remote_participant_data3 = DDS_Security_ParticipantBuiltinTopicData_alloc(); + memcpy(&remote_participant_data3->key[0], &candidate_participant_guid, 12); + + initialize_identity_token(&remote_participant_data3->identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + initialize_permissions_token(&remote_participant_data3->permissions_token, RSA_2048_ALGORITHM_NAME); + + remote_participant_data2->security_info.participant_security_attributes = 0x01; + remote_participant_data2->security_info.plugin_participant_security_attributes = 0x02; + + challenge1 = find_binary_property(&g_local_auth_request_token, AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + challenge2 = find_binary_property(&g_remote_auth_request_token, AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + + return res; +} + +static void +release_remote_identities(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL) { + success = auth->return_identity_handle(auth, remote_identity_handle1, &exception); + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + remote_identity_handle1 = DDS_SECURITY_HANDLE_NIL; + } + if (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL) { + success = auth->return_identity_handle(auth, remote_identity_handle2, &exception); + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + remote_identity_handle2 = DDS_SECURITY_HANDLE_NIL; + } + + DDS_Security_DataHolder_deinit(&g_local_auth_request_token); + DDS_Security_DataHolder_deinit(&g_remote_auth_request_token); + + DDS_Security_ParticipantBuiltinTopicData_free(remote_participant_data1); + DDS_Security_ParticipantBuiltinTopicData_free(remote_participant_data2); + DDS_Security_ParticipantBuiltinTopicData_free(remote_participant_data3); + remote_participant_data1 = NULL; + remote_participant_data2 = NULL; + remote_participant_data3 = NULL; +} + +static void init_testcase(void) +{ + + int res = 0; + /* Only need the authentication plugin. */ + plugins = load_plugins(NULL /* Access Control */, + &auth /* Authentication */, + NULL /* Cryptograpy */); + + if (plugins) { + res = validate_local_identity( NULL ); + if (res == 0) { + res = validate_remote_identities( remote_identity_certificate ); + } + if (res == 0){ + res = set_dh_keys(); + } + } else { + res = -1; + } + + CU_ASSERT_FATAL( res == 0 ); +} + +static void fini_testcase(void) +{ + release_local_identity(); + release_remote_identities(); + unload_plugins(plugins); + ddsrt_free(invalid_dh_pubkey_modp_2048_value); + ddsrt_free(dh_pubkey_modp_2048_value); + +} + + + + +static bool +compare_octet_seq( + const DDS_Security_OctetSeq *seq1, + const DDS_Security_OctetSeq *seq2) +{ + int r; + if (seq1 && seq2) { + r = (int)(seq2->_length - seq1->_length); + if (r == 0) { + r = memcmp(seq1->_buffer, seq2->_buffer, seq1->_length); + } + } else if (seq1 == seq2) { + r = 0; + } else { + r = (seq2 > seq1) ? 1 : -1; + } + return r; +} + +static bool +valid_c_id_property( + const char *certificate, + const DDS_Security_OctetSeq *value) +{ + if (value->_length == 0) { + CU_FAIL("c.id has no value"); + return false; + } + if (strncmp(certificate, (const char *)value->_buffer, value->_length) != 0) { + return false; + } + return true; +} + +static bool +valid_string_value( + const char *expected, + const DDS_Security_OctetSeq *value) +{ + size_t len = strlen(expected) + 1; + + if (strncmp(expected, (const char *)value->_buffer, len) != 0) { + return false; + } + + return true; +} + +static void +serializer_participant_data( + DDS_Security_ParticipantBuiltinTopicData *pdata, + unsigned char **buffer, + size_t *size) +{ + DDS_Security_Serializer serializer; + serializer = DDS_Security_Serializer_new(1024, 1024); + + DDS_Security_Serialize_ParticipantBuiltinTopicData(serializer, pdata); + DDS_Security_Serializer_buffer(serializer, buffer, size); + DDS_Security_Serializer_free(serializer); +} + + +static void +set_binary_property_value( + DDS_Security_BinaryProperty_t *bp, + const char *name, + const unsigned char *data, + size_t length) +{ + assert(bp); + assert(name); + assert(data); + + bp->name = ddsrt_strdup(name); + bp->value._maximum = bp->value._length = (DDS_Security_unsigned_long) length; + if (length) { + bp->value._buffer = ddsrt_malloc(length); + memcpy(bp->value._buffer, data, length); + } else { + bp->value._buffer = NULL; + } +} + +static void +set_binary_property_string( + DDS_Security_BinaryProperty_t *bp, + const char *name, + const char *data) +{ + size_t length; + + assert(bp); + assert(name); + assert(data); + + length = strlen(data) + 1; + set_binary_property_value(bp, name, (const unsigned char *)data, length); +} + +static void +fill_handshake_message_token( + DDS_Security_HandshakeMessageToken *token, + DDS_Security_ParticipantBuiltinTopicData *pdata, + const char *certificate, + const char *dsign, + const char *kagree, + const unsigned char *diffie_hellman, + const size_t diffie_hellman_size, + const unsigned char *challengeData, + size_t challengeDataSize) +{ + DDS_Security_BinaryProperty_t *tokens; + DDS_Security_BinaryProperty_t *c_id; + DDS_Security_BinaryProperty_t *c_perm; + DDS_Security_BinaryProperty_t *c_pdata; + DDS_Security_BinaryProperty_t *c_dsign_algo; + DDS_Security_BinaryProperty_t *c_kagree_algo; + DDS_Security_BinaryProperty_t *hash_c1; + DDS_Security_BinaryProperty_t *dh1; + DDS_Security_BinaryProperty_t *challenge; + unsigned char *serialized_local_participant_data; + size_t serialized_local_participant_data_size; + unsigned char hash[32]; + + serializer_participant_data(pdata, &serialized_local_participant_data, &serialized_local_participant_data_size); + + tokens = DDS_Security_BinaryPropertySeq_allocbuf(8); + c_id = &tokens[0]; + c_perm = &tokens[1]; + c_pdata = &tokens[2]; + c_dsign_algo = &tokens[3]; + c_kagree_algo = &tokens[4]; + hash_c1 = &tokens[5]; + dh1 = &tokens[6]; + challenge = &tokens[7]; + + /* Store the Identity Certificate associated with the local identify in c.id property */ + if (certificate) { + set_binary_property_string(c_id, "c.id", certificate); + } else { + set_binary_property_string(c_id, "c.idx", "rubbish"); + } + + /* Store the permission document in the c.perm property */ + set_binary_property_string(c_perm, "c.perm", "permissions_document"); + + /* Store the provided local_participant_data in the c.pdata property */ + set_binary_property_value(c_pdata, "c.pdata", serialized_local_participant_data, serialized_local_participant_data_size); + + /* Set the used signing algorithm descriptor in c.dsign_algo */ + if (dsign) { + set_binary_property_string(c_dsign_algo, "c.dsign_algo", dsign); + } else { + set_binary_property_string(c_dsign_algo, "c.dsign_algox", "rubbish"); + } + + /* Set the used key algorithm descriptor in c.kagree_algo */ + if (kagree) { + set_binary_property_string(c_kagree_algo, "c.kagree_algo", kagree); + } else { + set_binary_property_string(c_kagree_algo, "c.kagree_algox", "rubbish"); + } + + /* Calculate the hash_c1 */ + { + DDS_Security_BinaryPropertySeq bseq; + DDS_Security_Serializer serializer; + unsigned char *buffer; + size_t size; + + bseq._length = bseq._maximum = 5; + bseq._buffer = tokens; + + serializer = DDS_Security_Serializer_new(1024, 1024); + + DDS_Security_Serialize_BinaryPropertySeq(serializer, &bseq); + DDS_Security_Serializer_buffer(serializer, &buffer, &size); + SHA256(buffer, size, (unsigned char *)&hash); + ddsrt_free(buffer); + DDS_Security_Serializer_free(serializer); + + set_binary_property_value(hash_c1, "hash_c1", (const unsigned char *) &hash, sizeof(hash)); + } + + /* Set the DH public key associated with the local participant in dh1 property */ + if (diffie_hellman) { + set_binary_property_value(dh1, "dh1", diffie_hellman, diffie_hellman_size); + } else { + set_binary_property_string(dh1, "dh1x", "rubbish"); + } + + /* Set the challenge in challenge1 property */ + if (challengeData) { + set_binary_property_value(challenge, "challenge1", challengeData, challengeDataSize); + } else { + set_binary_property_value(challenge, "challenge1x", challenge2->value._buffer, challenge2->value._length); + } + + token->class_id = ddsrt_strdup(AUTH_HANDSHAKE_REQUEST_TOKEN_CLASS_ID); + token->binary_properties._length = token->binary_properties._maximum = 8; + token->binary_properties._buffer = tokens; + + ddsrt_free(serialized_local_participant_data); +} + +static void +fill_handshake_message_token_default( + DDS_Security_HandshakeMessageToken *token, + DDS_Security_ParticipantBuiltinTopicData *pdata, + const unsigned char *challengeData, + unsigned int challengeDataSize) +{ + fill_handshake_message_token( + token, pdata, remote_identity_certificate, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length, challengeData, challengeDataSize); +} + +static void +handshake_message_deinit( + DDS_Security_HandshakeMessageToken *token) +{ + DDS_Security_DataHolder_deinit(token); +} + +static bool +validate_handshake_token( + DDS_Security_HandshakeMessageToken *token, + const DDS_Security_OctetSeq *challenge_1, + const DDS_Security_OctetSeq *challenge_2) +{ + const DDS_Security_BinaryProperty_t *property; + + if (!token->class_id || strcmp(token->class_id, AUTH_HANDSHAKE_REPLY_TOKEN_CLASS_ID) != 0) { + CU_FAIL("HandshakeMessageToken incorrect class_id"); + } else if ((property = find_binary_property(token, "c.id")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'c.id' not found"); + } else if (!valid_c_id_property(&identity_certificate[6], &property->value)) { + CU_FAIL("HandshakeMessageToken incorrect property 'c.id' value is invalid"); + } else if ((property = find_binary_property(token, "c.pdata")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'c.pdata' not found"); + } else if ((property = find_binary_property(token, "c.dsign_algo")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'c.dsign_algo' not found"); + } else if (!valid_string_value(AUTH_DSIGN_ALGO_RSA_NAME, &property->value)) { + CU_FAIL("HandshakeMessageToken incorrect property 'c.dsign_algo' incorrect value"); + } else if ((property = find_binary_property(token, "c.kagree_algo")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'c.kagree_algo' not found"); + } else if (!valid_string_value(AUTH_KAGREE_ALGO_RSA_NAME, &property->value)) { + CU_FAIL("HandshakeMessageToken incorrect property 'c.kagree_algo' incorrect value"); + } else if ((property = find_binary_property(token, "hash_c2")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'hash_c2' not found"); + } else if ((property = find_binary_property(token, "dh2")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'dh2' not found"); + } else if ((property = find_binary_property(token, "hash_c1")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'hash_c1' not found"); + } else if ((property = find_binary_property(token, "dh1")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'dh1' not found"); + } else if ((property = find_binary_property(token, "challenge1")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'challenge1' not found"); + } else if (challenge_1 && compare_octet_seq(challenge_1, &property->value) != 0) { + CU_FAIL("HandshakeMessageToken incorrect property 'challenge1' incorrect value"); + } else if ((property = find_binary_property(token, "challenge2")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'challenge2' not found"); + } else if (challenge_2 && compare_octet_seq(challenge_2, &property->value) != 0) { + CU_FAIL("HandshakeMessageToken incorrect property 'challenge2' incorrect value"); + } else { + return true; + } + + return false; +} + +CU_Test(ddssec_builtin_validate_begin_handshake_reply, happy_day, .init = init_testcase, .fini = fini_testcase) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + + fill_handshake_message_token_default(&handshake_token_in, remote_participant_data1, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + CU_ASSERT(handshake_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT(validate_handshake_token(&handshake_token_out, &challenge2->value, NULL)); + + reset_exception(&exception); + + success= auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_handshake_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); +} + +CU_Test(ddssec_builtin_validate_begin_handshake_reply,future_challenge, .init = init_testcase, .fini = fini_testcase) + +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + fill_handshake_message_token_default(&handshake_token_in, remote_participant_data2, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle1, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + CU_ASSERT(handshake_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT(validate_handshake_token(&handshake_token_out, &challenge2->value, &challenge1->value)); + + reset_exception(&exception); + + success= auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_handshake_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + + future_challenge_done = true; +} + + +CU_Test(ddssec_builtin_validate_begin_handshake_reply,invalid_arguments, .init = init_testcase, .fini = fini_testcase) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq serdata = DDS_SECURITY_SEQUENCE_INIT; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + fill_handshake_message_token_default(&handshake_token_in, remote_participant_data1, challenge1->value._buffer, challenge1->value._length); + + result = auth->begin_handshake_reply( + auth, + NULL, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle1, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + NULL, + &handshake_token_in, + remote_identity_handle1, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + NULL, + remote_identity_handle1, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + 0, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle1, + 0, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle1, + local_identity_handle, + NULL, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle1, + local_identity_handle, + &serdata, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); +} + + +CU_Test(ddssec_builtin_validate_begin_handshake_reply,invalid_certificate, .init = init_testcase, .fini = fini_testcase) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + fill_handshake_message_token( + &handshake_token_in, remote_participant_data1, unrelated_identity, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result == DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + handshake_message_deinit(&handshake_token_in); + + fill_handshake_message_token( + &handshake_token_in, remote_participant_data1, NULL, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result == DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); +} + +CU_Test(ddssec_builtin_validate_begin_handshake_reply,invalid_participant_data , .init = init_testcase, .fini = fini_testcase) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_BinaryProperty_t *property; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + fill_handshake_message_token( + &handshake_token_in, remote_participant_data3, remote_identity_certificate, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result == DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); + + fill_handshake_message_token( + &handshake_token_in, remote_participant_data1, remote_identity_certificate, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length, challenge2->value._buffer, challenge2->value._length); + + property = find_binary_property(&handshake_token_in, "c.pdata"); + CU_ASSERT_FATAL(property != NULL); + assert(property != NULL); // for Clang's static analyzer + + ddsrt_free(property->name); + property->name = ddsrt_strdup("c.pdatax"); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result == DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); +} + + +CU_Test(ddssec_builtin_validate_begin_handshake_reply,invalid_dsign_algo , .init = init_testcase, .fini = fini_testcase) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + fill_handshake_message_token( + &handshake_token_in, remote_participant_data1, remote_identity_certificate, + "RSASSA-PSS-SHA128", AUTH_KAGREE_ALGO_RSA_NAME, + dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result == DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); + + fill_handshake_message_token( + &handshake_token_in, remote_participant_data1, remote_identity_certificate, + NULL, AUTH_KAGREE_ALGO_RSA_NAME, + dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result == DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); +} + +CU_Test(ddssec_builtin_validate_begin_handshake_reply,invalid_kagree_algo , .init = init_testcase, .fini = fini_testcase) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + fill_handshake_message_token( + &handshake_token_in, remote_participant_data1, remote_identity_certificate, + AUTH_DSIGN_ALGO_RSA_NAME, "DH+MODP-2048-128", + dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result == DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); + + fill_handshake_message_token( + &handshake_token_in, remote_participant_data1, remote_identity_certificate, + AUTH_DSIGN_ALGO_RSA_NAME, NULL, + dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result == DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); +} + +CU_Test(ddssec_builtin_validate_begin_handshake_reply,invalid_diffie_hellman , .init = init_testcase, .fini = fini_testcase) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + fill_handshake_message_token( + &handshake_token_in, remote_participant_data1, remote_identity_certificate, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + invalid_dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result == DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); + + fill_handshake_message_token( + &handshake_token_in, remote_participant_data1, remote_identity_certificate, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + NULL, 0, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result == DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); +} + +CU_Test(ddssec_builtin_validate_begin_handshake_reply,invalid_challenge , .init = init_testcase, .fini = fini_testcase) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + fill_handshake_message_token_default(&handshake_token_in, remote_participant_data2, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle1, + local_identity_handle, + &serialized_participant_data, + &exception); + CU_ASSERT_FATAL (result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + + + fill_handshake_message_token( + &handshake_token_in, remote_participant_data1, remote_identity_certificate, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length, challenge1->value._buffer, challenge1->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle1, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result == DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); + + fill_handshake_message_token( + &handshake_token_in, remote_participant_data1, remote_identity_certificate, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length, NULL, 0); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle1, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result == DDS_SECURITY_VALIDATION_OK) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); +} + + +CU_Test(ddssec_builtin_validate_begin_handshake_reply,return_handle, .init = init_testcase, .fini = fini_testcase) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + fill_handshake_message_token_default(&handshake_token_in, remote_participant_data1, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle1, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL (result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + CU_ASSERT (handshake_handle != DDS_SECURITY_HANDLE_NIL); + + reset_exception(&exception); + + success = auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_handshake_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + success = auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT ( success == false ); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + if (!success) { + printf("return_handshake_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + +} + +CU_Test(validate_begin_handshake_reply,extended_certificate_check, .init = init_testcase, .fini = fini_testcase ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token_in = DDS_SECURITY_TOKEN_INIT; + DDS_Security_HandshakeMessageToken handshake_token_out = DDS_SECURITY_TOKEN_INIT; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + release_local_identity(); + release_remote_identities(); + + CU_ASSERT_FATAL( !validate_local_identity("trusted_ca_dir") ); + CU_ASSERT_FATAL( !validate_remote_identities( remote_identity_trusted ) ); + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + + fill_handshake_message_token( + &handshake_token_in, remote_participant_data1, remote_identity_trusted, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_reply failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + CU_ASSERT(handshake_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT(validate_handshake_token(&handshake_token_out, &challenge2->value, NULL)); + + reset_exception(&exception); + + success= auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_handshake_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + + release_local_identity(); + release_remote_identities(); + + CU_ASSERT_FATAL( !validate_local_identity("trusted_ca_dir") ); + CU_ASSERT_FATAL( !validate_remote_identities( remote_identity_untrusted ) ); + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + + fill_handshake_message_token( + &handshake_token_in, remote_participant_data1, remote_identity_untrusted, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT_FATAL( exception.code != 0 ); + + reset_exception(&exception); + + auth->return_handshake_handle(auth, handshake_handle, &exception); + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + reset_exception(&exception); + + + release_local_identity(); + release_remote_identities(); + + CU_ASSERT_FATAL( !validate_local_identity("trusted_ca_dir") ); + CU_ASSERT_FATAL( !validate_remote_identities( remote_identity_trusted_expired ) ); + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_reply != NULL); + + + fill_handshake_message_token( + &handshake_token_in, remote_participant_data1, remote_identity_trusted_expired, + AUTH_DSIGN_ALGO_RSA_NAME, AUTH_KAGREE_ALGO_RSA_NAME, + dh_pubkey_modp_2048_value, dh_pubkey_modp_2048_length, challenge2->value._buffer, challenge2->value._length); + + result = auth->begin_handshake_reply( + auth, + &handshake_handle, + &handshake_token_out, + &handshake_token_in, + remote_identity_handle2, + local_identity_handle, + &serialized_participant_data, + &exception); + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT_FATAL( exception.code != 0 ); + + reset_exception(&exception); + + + auth->return_handshake_handle(auth, handshake_handle, &exception); + handshake_message_deinit(&handshake_token_in); + handshake_message_deinit(&handshake_token_out); + reset_exception(&exception); +} diff --git a/src/security/builtin_plugins/tests/validate_begin_handshake_request/src/validate_begin_handshake_request_utests.c b/src/security/builtin_plugins/tests/validate_begin_handshake_request/src/validate_begin_handshake_request_utests.c new file mode 100644 index 0000000..0c1b198 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_begin_handshake_request/src/validate_begin_handshake_request_utests.c @@ -0,0 +1,832 @@ + + + + +/* CUnit includes. */ +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/dds_security_api.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include +#include +#include "dds/ddsrt/environ.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "assert.h" + + +/* Test helper includes. */ +#include "common/src/loader.h" + +/* Private header include */ + +#ifdef _WIN32 +/* supposedly WinSock2 must be included before openssl 1.0.2 headers otherwise winsock will be used */ +#include +#endif +#include + +static const char * AUTH_PROTOCOL_CLASS_ID = "DDS:Auth:PKI-DH:1.0"; + +static const char * PROPERTY_IDENTITY_CA = "dds.sec.auth.identity_ca"; +static const char * PROPERTY_PRIVATE_KEY = "dds.sec.auth.private_key"; +static const char * PROPERTY_IDENTITY_CERT = "dds.sec.auth.identity_certificate"; + +static const char * PROPERTY_CERT_SUBJECT_NAME = "dds.cert.sn"; +static const char * PROPERTY_CERT_ALGORITHM = "dds.cert.algo"; +static const char * PROPERTY_CA_SUBJECT_NAME = "dds.ca.sn"; +static const char * PROPERTY_CA_ALGORITHM = "dds.ca.aglo"; + +static const char * SUBJECT_NAME_IDENTITY_CERT = "CN=CHAM-574 client,O=Some Company,ST=Some-State,C=NL"; +static const char * SUBJECT_NAME_IDENTITY_CA = "CN=CHAM-574 authority,O=Some Company,ST=Some-State,C=NL"; + +static const char * RSA_2048_ALGORITHM_NAME = "RSA-2048"; + +static const char * AUTH_REQUEST_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+AuthReq"; +static const char * AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME = "future_challenge"; + +static const char * AUTH_HANDSHAKE_REQUEST_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+Req"; + +static const char * AUTH_DSIGN_ALGO_RSA_NAME = "RSASSA-PSS-SHA256"; +static const char * AUTH_KAGREE_ALGO_ECDH_NAME = "ECDH+prime256v1-CEUM"; +/* static const char * AUTH_KAGREE_ALGO_RSA_NAME = "DH+MODP-2048-256"; */ + + + +static const char *identity_certificate = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEQTCCAymgAwIBAgIINpuaAAnrQZIwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE3MDIy\n" + "MjIyMjIwMFoYDzIyMjIwMjIyMjIyMjAwWjBcMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRUwEwYDVQQDEwxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n" + "ggEKAoIBAQDCpVhivH/wBIyu74rvQncnSZqKyspN6CvD1pmV9wft5PHhVt9jV79v\n" + "gSub5LADoRHAgFdv9duYgBr17Ob6uRrIY4B18CcrCjhQcC4gjx8y2jl9PeYm+qYD\n" + "3o44FYBrBq0QCnrQgKsb/qX9Z+Mw/VUiw65x68W876LEHQQoEgT4kxSuagwBoVRk\n" + "ePD6fYAKmT4XS3x+O0v+rHESTcsKF6yMadgp7h3eH1b8kJTzSx8JV9Zzq++mxjox\n" + "qhbBVP5nDze2hhSIeCkCvSrx7efkgKS4AQXa5/Z44GiAu1TfXXUqdic9rxwD0edn\n" + "ajNElnZe7sjok/0yuqvH+2hSqpNva/zpAgMBAAGjggEAMIH9MAwGA1UdDwQFAwMH\n" + "/4AwgewGA1UdJQSB5DCB4QYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYI\n" + "KwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3AgEVBgorBgEEAYI3AgEWBgorBgEE\n" + "AYI3CgMBBgorBgEEAYI3CgMDBgorBgEEAYI3CgMEBglghkgBhvhCBAEGCysGAQQB\n" + "gjcKAwQBBggrBgEFBQcDBQYIKwYBBQUHAwYGCCsGAQUFBwMHBggrBgEFBQgCAgYK\n" + "KwYBBAGCNxQCAgYIKwYBBQUHAwkGCCsGAQUFBwMNBggrBgEFBQcDDgYHKwYBBQID\n" + "BTANBgkqhkiG9w0BAQsFAAOCAQEAawdHy0Xw7nTK2ltp91Ion6fJ7hqYuj///zr7\n" + "Adt6uonpDh/xl3esuwcFimIJrJrHujnGkL0nLddRCikmnzuBMNDWS6yq0/Ckl/YG\n" + "yjNr44dlX24wo+MVAgkj3/8CyWDZ3a8kBg9QT3bs2SqbjmhTrXN1DRyf9S5vJysE\n" + "I7V1gTN66BeKL64hOrAlRVrEu8Ds6TWL6Q/YH+61ViZkoLTeSaPjH4nknaFr4C35\n" + "iji0JhkyfRHRRVPHFnaj25AkxOrSV64qVKoTMjDl5fji5iMGtjm6iJ7q05ml/qDl\n" + "nLotHXemZNvYhbwUmRzbt4Dls9EMH4VRbP85I94nM5TAvtHVNA==\n" + "-----END CERTIFICATE-----\n"; + + +static const char *identity_ca = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEmTCCA4GgAwIBAgIIZ5gEIUFhO5wwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDIx\n" + "MjE1MDUwMFoYDzIyMjIwMjIyMjIyMjAwWjBfMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRgwFgYDVQQDEw9DSEFNNTAwIHJvb3QgY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" + "DwAwggEKAoIBAQC6Fa3TheL+UrdZCp9GhU/2WbneP2t/avUa3muwDttPxeI2XU9k\n" + "ZjBR95mAXme4SPXHk5+YDN319AqIje3oKhzky/ngvKH2GkoJKYxWnuDBfMEHdViz\n" + "2Q9/xso2ZvH50ukwWa0pfx2/EVV1wRxeQcRd/UVfq3KTJizG0M88mOYvGEAw3LFf\n" + "zef7k1aCuOofQmBvLukUudcYpMzfyHFp7lQqU4CcrrR5RtmfiUfrWfdGLea2iPDB\n" + "pJgN8ESOMwEHtOTEBDclYnH9L4t7CHQz+fXXS5IWFsDK9fCMQjnxDsDVeNrNzTYL\n" + "FaZrMg9S6IUQCEsQWsnq5weS8omOpVLUm9klAgMBAAGjggFVMIIBUTAMBgNVHRME\n" + "BTADAQH/MB0GA1UdDgQWBBQg2FZB/j8uWDVnJhjwXkX278znSTAfBgNVHSMEGDAW\n" + "gBQg2FZB/j8uWDVnJhjwXkX278znSTAPBgNVHQ8BAf8EBQMDB/+AMIHvBgNVHSUB\n" + "Af8EgeQwgeEGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwME\n" + "BggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK\n" + "KwYBBAGCNwoDAwYKKwYBBAGCNwoDBAYJYIZIAYb4QgQBBgsrBgEEAYI3CgMEAQYI\n" + "KwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUIAgIGCisGAQQBgjcU\n" + "AgIGCCsGAQUFBwMJBggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZI\n" + "hvcNAQELBQADggEBAKHmwejWRwGE1wf1k2rG8SNRV/neGsZ6Qfqf6co3TpR/Wi1s\n" + "iZDvSeT/rbqNBS7z34xnG88NIUwu00y78e8Mfon31ZZbK4Uo7fla9/D3ukdJqPQC\n" + "LKdbKJjR2kH+KCukY/1rghjJ8/X+t2egBit0LCOdsFCl07Sfksb9kpGUIZSFcYYm\n" + "geqhjhoNwxazzHiw+QWHC5HG9248JIizBmy1aymNWuMnPudhjHAnPcsIlqMVNq3t\n" + "Rv9ap7S8JeCxHVRPJvJeCwXWvW3dW/v3xH52Yn/fqRblN1w9Fxz5NhopKx0gj/Jd\n" + "sw2N4Fk4gaOWEolFpa0bwNw8nAx7moehZpowzfw=\n" + "-----END CERTIFICATE-----\n"; + + +static const char *private_key = + "data:,-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEogIBAAKCAQEAwqVYYrx/8ASMru+K70J3J0maisrKTegrw9aZlfcH7eTx4Vbf\n" + "Y1e/b4Erm+SwA6ERwIBXb/XbmIAa9ezm+rkayGOAdfAnKwo4UHAuII8fMto5fT3m\n" + "JvqmA96OOBWAawatEAp60ICrG/6l/WfjMP1VIsOucevFvO+ixB0EKBIE+JMUrmoM\n" + "AaFUZHjw+n2ACpk+F0t8fjtL/qxxEk3LChesjGnYKe4d3h9W/JCU80sfCVfWc6vv\n" + "psY6MaoWwVT+Zw83toYUiHgpAr0q8e3n5ICkuAEF2uf2eOBogLtU3111KnYnPa8c\n" + "A9HnZ2ozRJZ2Xu7I6JP9Mrqrx/toUqqTb2v86QIDAQABAoIBAC1q32DKkx+yMBFx\n" + "m32QiLUGG6VfBC2BixS7MkMnzRXZYgcuehl4FBc0kLRjfB6cqsO8LqrVN1QyMBhK\n" + "GutN3c38SbE7RChqzhEW2+yE+Mao3Nk4ZEecHLiyaYT0n25ZtHAVwep823BAzwJ+\n" + "BykbM45VEpNKbG1VjSktjBa9faNyZiZAEJEjVyla+6R8N4kHV52LbZcLjvJv3IQ2\n" + "iPYRrmMyI5C23qTni0vy7yJbAXBo3CqgSlwie9FARBWT7Puu7F4mF1O1c/SnTysw\n" + "Tm3e5FzgfHipQbnRVn0w4rDprPMKmPxMnvf/Wkw0zVgNadp1Tc1I6Yj525DEQ07i\n" + "2gIn/gECgYEA4jNnY1u2Eu7x3pAQF3dRO0x35boVtuq9iwQk7q+uaZaK4RJRr+0Y\n" + "T68S3bPnfer6SHvcxtST89Bvs/j/Ky4SOaX037UYjFh6T7OIzPl+MzO1yb+VOBT6\n" + "D6FVGEJGp8ZAITU1OfJPeTYViUeEC8tHFGoKUCk50FbB6jOf1oKtv/ECgYEA3EnB\n" + "Y7kSbJJaUuj9ciFUL/pAno86Cim3VjegK1wKgEiyDb610bhoMErovPwfVJbtcttG\n" + "eKJNuwizkRcVbj+vpjDvqqaP5eMxLl6/Nd4haPMJYzGo88Z8NJpwFRNF2KEWjOpQ\n" + "2NEvoCeRtVulCJyka2Tpljzw8cOXkxhPOe2UhHkCgYBo3entj0QO7QXm56T+LAvV\n" + "0PK45xdQEO3EuCwjGAFk5C0IgUSrqeCeeIzniZMltj1IQ1wsNbtNynEu3530t8wt\n" + "O7oVyFBUKGSz9IjUdkpClJOPr6kPMfJoMqRPtdIpz+hFPPSrI6IikKdVWHloOlp+\n" + "pVaYqTQrWT1XRY2xli3VEQKBgGySmZN6Cx+h/oywswIGdUT0VdcQhq2to+QFpJba\n" + "VX6m1cM6hMip2Ag9U3qZ1SNPBBdBBfm9HQybHE3dj713/C2wHuAAGhpXIM1W+20k\n" + "X1knuC/AsSH9aQhQOf/ZMOq1crTfZBuI9q0782/sjGmzMsKPySU4QhUWruVb7OiD\n" + "NVkZAoGAEvihW7G+8/iOE40vGHyBqUeopAAWLciTAUIEwM/Oi3BYfNWNTWF/FWNc\n" + "nMvCZPYigY8C1vO+1iT2Frtd3CIU+f01Q3fJNJoRLlEiKLNZUJRF48OKUqjKSmsi\n" + "w6pucFO40z05YW7utApj4L82rZnOS0pd1tUI1yexqvj0i4ThJfk=\n" + "-----END RSA PRIVATE KEY-----\n"; + + + +static struct plugins_hdl *plugins = NULL; +static dds_security_authentication *auth = NULL; +static DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_IdentityHandle remote_identity_handle1 = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_IdentityHandle remote_identity_handle2 = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_AuthRequestMessageToken g_local_auth_request_token = DDS_SECURITY_TOKEN_INIT; +static DDS_Security_AuthRequestMessageToken g_remote_auth_request_token = DDS_SECURITY_TOKEN_INIT; +static const DDS_Security_BinaryProperty_t *challenge1 = NULL; +static const DDS_Security_BinaryProperty_t *challenge2 = NULL; + + +static void +dds_security_property_init( + DDS_Security_PropertySeq *seq, + DDS_Security_unsigned_long size) +{ + seq->_length = size; + seq->_maximum = size; + seq->_buffer = ddsrt_malloc(size * sizeof(DDS_Security_Property_t)); + memset(seq->_buffer, 0, size * sizeof(DDS_Security_Property_t)); +} + +static void +dds_security_property_deinit( + DDS_Security_PropertySeq *seq) +{ + uint32_t i; + + for (i = 0; i < seq->_length; i++) { + ddsrt_free(seq->_buffer[i].name); + ddsrt_free(seq->_buffer[i].value); + } + ddsrt_free(seq->_buffer); +} + +static void +reset_exception( + DDS_Security_SecurityException *ex) +{ + ex->minor_code = 0; + ex->code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void +initialize_identity_token( + DDS_Security_IdentityToken *token, + const char *certAlgo, + const char *caAlgo) +{ + memset(token, 0, sizeof(*token)); + + token->class_id = ddsrt_strdup(AUTH_PROTOCOL_CLASS_ID); + token->properties._maximum = 4; + token->properties._length = 4; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(4); + + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_CERT_SUBJECT_NAME); + token->properties._buffer[0].value = ddsrt_strdup(SUBJECT_NAME_IDENTITY_CERT); + token->properties._buffer[0].propagate = true; + + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_CERT_ALGORITHM); + token->properties._buffer[1].value = ddsrt_strdup(certAlgo); + token->properties._buffer[1].propagate = true; + + token->properties._buffer[2].name = ddsrt_strdup(PROPERTY_CA_SUBJECT_NAME); + token->properties._buffer[2].value = ddsrt_strdup(SUBJECT_NAME_IDENTITY_CA); + token->properties._buffer[2].propagate = true; + + token->properties._buffer[3].name = ddsrt_strdup(PROPERTY_CA_ALGORITHM); + token->properties._buffer[3].value = ddsrt_strdup(caAlgo); + token->properties._buffer[3].propagate = true; +} + +static void +fill_auth_request_token( + DDS_Security_AuthRequestMessageToken *token) +{ + uint32_t i; + uint32_t len = 32; + unsigned char *challenge; + + challenge = ddsrt_malloc(len); + + for (i = 0; i < len; i++) { + challenge[i] = (unsigned char)(0xFF - i); + } + + memset(token, 0, sizeof(*token)); + + token->class_id = ddsrt_strdup(AUTH_REQUEST_TOKEN_CLASS_ID); + token->binary_properties._maximum = 1; + token->binary_properties._length = 1; + token->binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + token->binary_properties._buffer->name = ddsrt_strdup(AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + + token->binary_properties._buffer->value._maximum = len; + token->binary_properties._buffer->value._length = len; + token->binary_properties._buffer->value._buffer = challenge; +} + +static const DDS_Security_BinaryProperty_t * +find_binary_property( + DDS_Security_DataHolder *token, + const char *name) +{ + const DDS_Security_BinaryProperty_t *result = NULL; + uint32_t i; + + for (i = 0; i < token->binary_properties._length && !result; i++) { + if (token->binary_properties._buffer[i].name && (strcmp(token->binary_properties._buffer[i].name, name) == 0)) { + result = &token->binary_properties._buffer[i]; + } + } + + return result; +} + + +static void +deinitialize_identity_token( + DDS_Security_IdentityToken *token) +{ + DDS_Security_DataHolder_deinit(token); +} + +static int +validate_local_identity(void) +{ + int res = 0; + DDS_Security_ValidationResult_t result; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GUID_t local_participant_guid; + DDS_Security_GuidPrefix_t prefix = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb}; + DDS_Security_EntityId_t entityId = {{0xb0,0xb1,0xb2},0x1}; + + memset(&local_participant_guid, 0, sizeof(local_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + memset(&participant_qos, 0, sizeof(participant_qos)); + dds_security_property_init(&participant_qos.property.value, 3); + participant_qos.property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + participant_qos.property.value._buffer[0].value = ddsrt_strdup(identity_certificate); + participant_qos.property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + participant_qos.property.value._buffer[1].value = ddsrt_strdup(identity_ca); + participant_qos.property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + participant_qos.property.value._buffer[2].value = ddsrt_strdup(private_key); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &local_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + res = -1; + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + return res; +} + +static void +release_local_identity(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (local_identity_handle != DDS_SECURITY_HANDLE_NIL) { + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } +} + +static int +validate_remote_identities (void) +{ + int res = 0; + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityToken remote_identity_token; + static DDS_Security_AuthRequestMessageToken local_auth_request_token = DDS_SECURITY_TOKEN_INIT; + DDS_Security_GUID_t remote_participant_guid1; + DDS_Security_GUID_t remote_participant_guid2; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix1 = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab}; + DDS_Security_GuidPrefix_t prefix2 = {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb}; + DDS_Security_EntityId_t entityId = {{0xb0,0xb1,0xb2},0x1}; + + memcpy(&remote_participant_guid1.prefix, &prefix1, sizeof(prefix1)); + memcpy(&remote_participant_guid1.entityId, &entityId, sizeof(entityId)); + memcpy(&remote_participant_guid2.prefix, &prefix2, sizeof(prefix2)); + memcpy(&remote_participant_guid2.entityId, &entityId, sizeof(entityId)); + + if (local_identity_handle == DDS_SECURITY_HANDLE_NIL) { + return -1; + } + + initialize_identity_token(&remote_identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle1, + &g_local_auth_request_token, + NULL, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid1, + &exception); + + if ((result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST) && + (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE)) { + printf("validate_remote_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + reset_exception(&exception); + + fill_auth_request_token(&g_remote_auth_request_token); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle2, + &local_auth_request_token, + &g_remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid2, + &exception); + + if ((result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST) && + (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE)) { + printf("validate_remote_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + reset_exception(&exception); + + deinitialize_identity_token(&remote_identity_token); + DDS_Security_DataHolder_deinit(&local_auth_request_token); + + challenge1 = find_binary_property(&g_local_auth_request_token, AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + challenge2 = find_binary_property(&g_remote_auth_request_token, AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + + return res; +} + +static void +release_remote_identities(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL) { + success = auth->return_identity_handle(auth, remote_identity_handle1, &exception); + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } + if (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL) { + success = auth->return_identity_handle(auth, remote_identity_handle2, &exception); + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } + + DDS_Security_DataHolder_deinit(&g_local_auth_request_token); + DDS_Security_DataHolder_deinit(&g_remote_auth_request_token); +} + +static void +fill_local_participant_data( + DDS_Security_OctetSeq *pdata, + uint32_t length) +{ + uint32_t i; + + pdata->_length = pdata->_maximum = length; + pdata->_buffer = ddsrt_malloc(length); + + for (i = 0; i < length; i++) { + pdata->_buffer[i] = (unsigned char)(i % 256); + } +} + +static void +release_local_participant_data( + DDS_Security_OctetSeq *pdata) +{ + if (pdata) { + ddsrt_free(pdata->_buffer); + } +} + +CU_Init(ddssec_builtin_validate_begin_handshake_request) +{ + int res = 0; + + /* Only need the authentication plugin. */ + plugins = load_plugins(NULL /* Access Control */, + &auth /* Authentication */, + NULL /* Cryptograpy */); + if (plugins) { + res = validate_local_identity(); + if (res >= 0) { + res = validate_remote_identities(); + } + } else { + res = -1; + } + + return res; +} + +CU_Clean(ddssec_builtin_validate_begin_handshake_request) +{ + release_local_identity(); + release_remote_identities(); + unload_plugins(plugins); + return 0; +} + +static bool +compare_octet_seq( + const DDS_Security_OctetSeq *seq1, + const DDS_Security_OctetSeq *seq2) +{ + int r; + if (seq1 && seq2) { + r = (int)(seq2->_length - seq1->_length); + if (r == 0) { + r = memcmp(seq1->_buffer, seq2->_buffer, seq1->_length); + } + } else if (seq1 == seq2) { + r = 0; + } else { + r = (seq2 > seq1) ? 1 : -1; + } + return r; +} + +static bool +valid_c_id_property( + const char *certificate, + const DDS_Security_OctetSeq *value) +{ + if (value->_length == 0) { + CU_FAIL("c.id has no value"); + return false; + } + if (strncmp(certificate, (const char *)value->_buffer, value->_length) != 0) { + return false; + } + return true; +} + +static bool +valid_string_value( + const char *expected, + const DDS_Security_OctetSeq *value) +{ + size_t len = strlen(expected) + 1; + + if (strncmp(expected, (const char *)value->_buffer, len) != 0) { + return false; + } + + return true; +} + + + +static bool +validate_handshake_token( + DDS_Security_HandshakeMessageToken *token, + const DDS_Security_OctetSeq *challenge) +{ + const DDS_Security_BinaryProperty_t *property; + + if (!token->class_id || strcmp(token->class_id, AUTH_HANDSHAKE_REQUEST_TOKEN_CLASS_ID) != 0) { + CU_FAIL("HandshakeMessageToken incorrect class_id"); + } else if ((property = find_binary_property(token, "c.id")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'c.id' not found"); + } else if (!valid_c_id_property(&identity_certificate[6], &property->value)) { + CU_FAIL("HandshakeMessageToken incorrect property 'c.id' value is invalid"); + } else if ((property = find_binary_property(token, "c.pdata")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'c.pdata' not found"); + } else if ((property = find_binary_property(token, "c.dsign_algo")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'c.dsign_algo' not found"); + } else if (!valid_string_value(AUTH_DSIGN_ALGO_RSA_NAME, &property->value)) { + CU_FAIL("HandshakeMessageToken incorrect property 'c.dsign_algo' incorrect value"); + } else if ((property = find_binary_property(token, "c.kagree_algo")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'c.kagree_algo' not found"); + } else if (!valid_string_value(AUTH_KAGREE_ALGO_ECDH_NAME, &property->value)) { + CU_FAIL("HandshakeMessageToken incorrect property 'c.kagree_algo' incorrect value"); + } else if ((property = find_binary_property(token, "hash_c1")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'hash_c1' not found"); + } else if ((property = find_binary_property(token, "dh1")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'dh1' not found"); + } else if ((property = find_binary_property(token, "challenge1")) == NULL) { + CU_FAIL("HandshakeMessageToken incorrect property 'challenge1' not found"); + } else if (challenge && compare_octet_seq(challenge, &property->value) != 0) { + CU_FAIL("HandshakeMessageToken incorrect property 'challenge1' incorrect value"); + } else { + return true; + } + + return false; +} + + + +CU_Test(ddssec_builtin_validate_begin_handshake_request,happy_day_challenge) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq local_participant_data; + DDS_Security_boolean success; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_request != NULL); + + fill_local_participant_data(&local_participant_data, 82); + + result = auth->begin_handshake_request( + auth, + &handshake_handle, + &handshake_token, + local_identity_handle, + remote_identity_handle2, + &local_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_request failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + CU_ASSERT(handshake_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT(validate_handshake_token(&handshake_token, NULL)); + + reset_exception(&exception); + + release_local_participant_data(&local_participant_data); + + success= auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_handshake_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + DDS_Security_DataHolder_deinit(&handshake_token); +} + +CU_Test(ddssec_builtin_validate_begin_handshake_request,happy_day_future_challenge) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq local_participant_data; + DDS_Security_boolean success; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_request != NULL); + + fill_local_participant_data(&local_participant_data, 82); + + result = auth->begin_handshake_request( + auth, + &handshake_handle, + &handshake_token, + local_identity_handle, + remote_identity_handle1, + &local_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_request failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL(result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + CU_ASSERT(handshake_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT(validate_handshake_token(&handshake_token, &challenge1->value)); + + reset_exception(&exception); + + release_local_participant_data(&local_participant_data); + + success = auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_handshake_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + DDS_Security_DataHolder_deinit(&handshake_token); +} + + +CU_Test(ddssec_builtin_validate_begin_handshake_request,invalid_arguments) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq local_participant_data; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_request != NULL); + + fill_local_participant_data(&local_participant_data, 82); + + result = auth->begin_handshake_request( + auth, + NULL, + &handshake_token, + local_identity_handle, + remote_identity_handle1, + &local_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->begin_handshake_request( + auth, + &handshake_handle, + NULL, + local_identity_handle, + remote_identity_handle1, + &local_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->begin_handshake_request( + auth, + &handshake_handle, + &handshake_token, + 0x1234598, + remote_identity_handle1, + &local_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->begin_handshake_request( + auth, + &handshake_handle, + &handshake_token, + local_identity_handle, + 0x1234598, + &local_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->begin_handshake_request( + auth, + &handshake_handle, + &handshake_token, + local_identity_handle, + remote_identity_handle1, + NULL, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + release_local_participant_data(&local_participant_data); +} + +CU_Test(ddssec_builtin_validate_begin_handshake_request,return_handle) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_HandshakeHandle handshake_handle; + DDS_Security_HandshakeMessageToken handshake_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_OctetSeq local_participant_data; + DDS_Security_boolean success; + + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle1 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (remote_identity_handle2 != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->begin_handshake_request != NULL); + + fill_local_participant_data(&local_participant_data, 82); + + result = auth->begin_handshake_request( + auth, + &handshake_handle, + &handshake_token, + local_identity_handle, + remote_identity_handle2, + &local_participant_data, + &exception); + + if (result != DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) { + printf("begin_handshake_request failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL (result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + CU_ASSERT (handshake_handle != DDS_SECURITY_HANDLE_NIL); + + reset_exception(&exception); + + release_local_participant_data(&local_participant_data); + + success = auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_handshake_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + success = auth->return_handshake_handle(auth, handshake_handle, &exception); + CU_ASSERT_FALSE (success); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + if (!success) { + printf("return_handshake_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + DDS_Security_DataHolder_deinit(&handshake_token); +} diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/Alice_Test_2.crt b/src/security/builtin_plugins/tests/validate_local_identity/etc/Alice_Test_2.crt new file mode 100644 index 0000000..f5f77eb --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/Alice_Test_2.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEJTCCAw2gAwIBAgIBFzANBgkqhkiG9w0BAQsFADBzMQswCQYDVQQGEwJOTDEL +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGjAYBgNVBAMTEUlkZW50 +aXR5IENBIFRlc3QyMSYwJAYJKoZIhvcNAQkBFhdpbmZvQGlzdC5hZGxpbmt0ZWNo +LmNvbTAeFw0xODA3MjAwMDAwMDBaFw0yNzA3MTkyMzU5NTlaMG0xCzAJBgNVBAYT +Ak5MMQswCQYDVQQIEwJPVjETMBEGA1UEChMKQURMaW5rIElTVDEUMBIGA1UEAxML +QWxpY2UgVGVzdDIxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu +Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Fb60RkFrDsRAIRf +LMf2fsiRnw9Agp7yEbUsA4Zg4X+hRhBkk78fFtagLisWo4LbT4DqKzqQXCvVnOn9 +a6uT0KsVejk2iaLoBy0fotQznudio3rzDpTfzP9eRDFVj8RJnl3JJ8P1DULxH7N0 +TyDBuKZ1ibBfuKjPffqeCEzYKgAc8NG2FB4m6mXzHhXuKw6W2v0IbHz6KYldsavf +04rq7ztw0t67bexSQ4gLSVJEwiohAregm0dLvQnap5xd2qn0yETteTL8Y+Ujym1D +WAnwDdwA6+0j2a0wkyzOzYQpZMt95NyZ8kcoqEqO8KAN2HclqfjHlg9iDscbof5x +45SQwwIDAQABo4HJMIHGMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFL66FT0vnlFE ++PKrtV+KhJoLsCOWMB8GA1UdIwQYMBaAFIFGyWkPWvNkBD2SCYj9H+NfnlOLMA8G +A1UdDwEB/wQFAwMH/4AwZQYDVR0lAQH/BFswWQYIKwYBBQUHAwEGCCsGAQUFBwMC +BggrBgEFBQcDAwYIKwYBBQUHAwQGCCsGAQUFBwMIBggrBgEFBQcDCQYIKwYBBQUH +Aw0GCCsGAQUFBwMOBgcrBgEFAgMFMA0GCSqGSIb3DQEBCwUAA4IBAQCsBINpBXSp +Xe3f5MMObeUXE2VhWZWIjMdDQRFDDjq6u1YR7rbffsCReiCX5zviU2dtVV8VN3MQ +k7wp8qEDKwP1ToMIwZGwT4Hfwei1eueJ1vuotgiGe0Gm3otXlGsb0C5otnsu63MM +OeFgkpZde3VpIqK9EmhgjWOD8TXc8Me7zBlYSEIaXkkwP0jAKRf5vFgz0WfE5ITx +SDKUO0OrcN789flO/OKLAHZ4cqNcxNPkMz7h9VBSgRRRk115HEa8Fe46nl1YpwRG +0urHlyAKoUV+J+I3Qy4+SwIDwix978hgGN3bKVyv9q0yAQRzpZ54EJOj4C7lNEpB +roGVpY4yYP/B +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/Bob_Chain_Test.crt b/src/security/builtin_plugins/tests/validate_local_identity/etc/Bob_Chain_Test.crt new file mode 100644 index 0000000..e980af3 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/Bob_Chain_Test.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEJDCCAwygAwIBAgIBAzANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJOTDEL +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxJDAiBgNVBAMTG0lkZW50 +aXR5IENBIFRlc3QgV2l0aCBDaGFpbjEmMCQGCSqGSIb3DQEJARYXaW5mb0Bpc3Qu +YWRsaW5rdGVjaC5jb20wHhcNMTgwNjEzMDAwMDAwWhcNMjcwNjEwMjM1OTU5WjBw +MQswCQYDVQQGEwJOTDELMAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1Qx +FzAVBgNVBAMTDkJvYiBDaGFpbiBUZXN0MSYwJAYJKoZIhvcNAQkBFhdpbmZvQGlz +dC5hZGxpbmt0ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AMHm+qG5afCHFdmp98+Z+POB7vD3WhfghKVugh8FenewuPaaotKxiGAE0kCf8WXU +5l4XDR3iBWJsGDHll1yOyL4KW9grwfnfiJMl82uIzKGDiRJbFkXVOLF/DcVLsuqM +oRjlk09+nlrg/7xS96itgm6yueW/UOIXpo+ElCHwnrYnpuHHrYM0s7t1ls3QFSyd +a3INx+LkM6N/b+veVJF95yfe4GvVBhFpLkWtX4xKgZyMjczvmZ6LVNNSnthPhlZF +HmspQyqXrTnGyax3qyoloqh9ibDvAK5pUnzqlv/Dyyt110q3bXFR5A0wqfj0fqtp +7Mw4TdTkFQy1n4/Y4EuT8I8CAwEAAaOBuzCBuDAdBgNVHQ4EFgQUQpxLPHT5o/GQ +RwdBw2scINXnWlUwHwYDVR0jBBgwFoAUTVVCTRc4ST0XmE+EEsenSudwlwkwDwYD +VR0PAQH/BAUDAwf/gDBlBgNVHSUBAf8EWzBZBggrBgEFBQcDAQYIKwYBBQUHAwIG +CCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwgGCCsGAQUFBwMJBggrBgEFBQcD +DQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggEBAJwd60WigqbB +/6CT0ekvXZdvIV5IaIKiy6KYU0/0ebPVXn0YKp9LQTE6lYCr6hZUcEjBfkFBZhAy +KJJOb2sUXAnYqnX/mIipiNb7oHsCHxVCKAwEcmxsS3tGl2CXgpKL8EQQFKJgSrC/ +uzhf2QESQ0T5Mgni1jXXGf6SAwFAjk+mAM9bMdrtLOX39e5aKrgpZOHmdFke+m/K +upxP/M0/omTNNQaSfWDmfDvpdsRD9+mFG12Kzgpue2jut1qeICvSmcQsu2OBYG/Q +ZXMx8e8azoX0KB+njf826UcVgDkDmfwN9taOU2lFsmZAvYhpIslNwtH/Htu3zJWO +vQxyIh+kxFQ= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/Identity_CA_Test2.crt b/src/security/builtin_plugins/tests/validate_local_identity/etc/Identity_CA_Test2.crt new file mode 100644 index 0000000..592eea3 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/Identity_CA_Test2.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIBFjANBgkqhkiG9w0BAQsFADBzMQswCQYDVQQGEwJOTDEL +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGjAYBgNVBAMTEUlkZW50 +aXR5IENBIFRlc3QyMSYwJAYJKoZIhvcNAQkBFhdpbmZvQGlzdC5hZGxpbmt0ZWNo +LmNvbTAeFw0xODA3MjAwMDAwMDBaFw0yNzA3MTkyMzU5NTlaMHMxCzAJBgNVBAYT +Ak5MMQswCQYDVQQIEwJPVjETMBEGA1UEChMKQURMaW5rIElTVDEaMBgGA1UEAxMR +SWRlbnRpdHkgQ0EgVGVzdDIxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlu +a3RlY2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyIweDOdB +xotexcDiUdbIdDLu9A6/KSpkxUJnYb2iRhBonmCNFvErEokso/Dga6QT3rg83UCg +GMJBSJSZhq/j+eZweHoXS8Ccet/aF2iNj5A5Uhn476M3zMg+rCoos2yKlpZLOz1x +QjrRJfeOoBHvkHkxBeupnnQPx4oAro7zoXMIO83NKLwCROC/kGq1ktW8fbKa5THQ +z0QfZG3zAeD93N+dTAqA+jkCfzbrQepF243Tu4cLaGwVALZ/8cZ7sky8+OOmKnBU +P9r+U/4L62DVJYnYkTGnYEwqXcM1b8/JHasmKEaHXgAu/UI5i/SZfRPZUyC1ERSv +tX6k7sBxZZSPLQIDAQABo4HJMIHGMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFIFG +yWkPWvNkBD2SCYj9H+NfnlOLMB8GA1UdIwQYMBaAFIFGyWkPWvNkBD2SCYj9H+Nf +nlOLMA8GA1UdDwEB/wQFAwMH/4AwZQYDVR0lAQH/BFswWQYIKwYBBQUHAwEGCCsG +AQUFBwMCBggrBgEFBQcDAwYIKwYBBQUHAwQGCCsGAQUFBwMIBggrBgEFBQcDCQYI +KwYBBQUHAw0GCCsGAQUFBwMOBgcrBgEFAgMFMA0GCSqGSIb3DQEBCwUAA4IBAQCK +SkemYQIvsslkMc8PNHSk2om4xk7hUXkatAZPN9dvRravu3PJqMWxpQ0TWbddrkBL +he7/ARC2G9vVUwQl2b8K1Rjt/nZ3j+NPvhCDzcPyxjornyN8IG1NJQVH18fTxR23 +6PvDBE0H2trA3WJgKo6Wlxo6CHWts8ulFWWXBE1nNQw30hU49FDsFn3nz6Gry4ti +/ouAvbz+UXSsT9R+zkci3A394sEsOCZSStgAnXsejU45pCt6OtCGaLfDvEPp21az +OEjuIaj6Kbd+MHeLyPoe+d1Bkl39OnAUEJ8q2HdwvIg2ZqP6h0agm5gpZo/ALDWn +9P3owIGVsHFGkYqhHc+K +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/Identity_CA_Test_With_Chain.crt b/src/security/builtin_plugins/tests/validate_local_identity/etc/Identity_CA_Test_With_Chain.crt new file mode 100644 index 0000000..35506b8 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/Identity_CA_Test_With_Chain.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIENDCCAxygAwIBAgIBAjANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50 +aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu +Y29tMB4XDTE4MDYxMzAwMDAwMFoXDTI3MDYxMDIzNTk1OVowfTELMAkGA1UEBhMC +TkwxCzAJBgNVBAgTAk9WMRMwEQYDVQQKEwpBRExpbmsgSVNUMSQwIgYDVQQDExtJ +ZGVudGl0eSBDQSBUZXN0IFdpdGggQ2hhaW4xJjAkBgkqhkiG9w0BCQEWF2luZm9A +aXN0LmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA1r8Q0V8ZVeBs8tPMF0N+JlBynl1Zn/89vwSsU4m7y6ixUcW/y3r12CMeA0cH +g6yOaOdHsZ8pRlPRwy9YmeOwLsMOUHAURP2uPiTjSf3pttUIf0jv602GyirNzoS7 +7mHiyTtV80ZMzZlLIJ3gaJJlG4DjitFuFcjv8sOmviFjkn1kOjkAz1nKgsCiHvvg +fcJlYPrtLfle9SzvZ3MTq4ob+/EFu9nt5bYYs7p7Br1TGWctUw98l2mSn/FhfDBw +9bb7ZhcKB7W6PGy2Os5AnkdTJKHoOQT+RmnHzPBhab0BoKuy8IhfW2GyqC8rL5Tm +/UVLUvnx4Zzqz//3IyA2FTb1HQIDAQABo4HJMIHGMAwGA1UdEwQFMAMBAf8wHQYD +VR0OBBYEFE1VQk0XOEk9F5hPhBLHp0rncJcJMB8GA1UdIwQYMBaAFER4R6N3MQ1W +l7gn+R8wwHloDCVZMA8GA1UdDwEB/wQFAwMH/4AwZQYDVR0lAQH/BFswWQYIKwYB +BQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYIKwYBBQUHAwQGCCsGAQUFBwMIBggr +BgEFBQcDCQYIKwYBBQUHAw0GCCsGAQUFBwMOBgcrBgEFAgMFMA0GCSqGSIb3DQEB +CwUAA4IBAQCbl7ed4p66G6WquxO7ceZFvYKn3kDErjCfXHcqHxBnA2xTpoZCGj95 +Qpirqo6N4UcLX5sn3CmgyVk0dYvlti/53FJgZ9XQDNxBuEYWPkY7vO+Uo0WdYpGz +ZDNIUQpiPMA7bHvwKldTIs77xxtnw9kbBU2k0xQyb2tdZNfD5YqSI1MeUtpEpNFW +sbC8+mQ3clzWpjF8eHH1fFSAmlJ+z1Uqmtt2FK0vRz+MQcpydwvpMnfqGdcwhGPQ +X4HZreLObjBA8KUEkUB3+rZXuELBgkk/c8/jRZl7QF5jJDLQCCLg7KoYBKN2GuTt +/dzeSnP7VZm/nTL8wpCvKgSOwOGgklf2 +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/alice.pem b/src/security/builtin_plugins/tests/validate_local_identity/etc/alice.pem new file mode 100644 index 0000000..07a5977 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/alice.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA0Fb60RkFrDsRAIRfLMf2fsiRnw9Agp7yEbUsA4Zg4X+hRhBk +k78fFtagLisWo4LbT4DqKzqQXCvVnOn9a6uT0KsVejk2iaLoBy0fotQznudio3rz +DpTfzP9eRDFVj8RJnl3JJ8P1DULxH7N0TyDBuKZ1ibBfuKjPffqeCEzYKgAc8NG2 +FB4m6mXzHhXuKw6W2v0IbHz6KYldsavf04rq7ztw0t67bexSQ4gLSVJEwiohAreg +m0dLvQnap5xd2qn0yETteTL8Y+Ujym1DWAnwDdwA6+0j2a0wkyzOzYQpZMt95NyZ +8kcoqEqO8KAN2HclqfjHlg9iDscbof5x45SQwwIDAQABAoIBAG0dYPeqd0IhHWJ7 +8azufbchLMN1pX/D51xG2uptssfnpHuhkkufSZUYi4QipRS2ME6PYhWJ8pmTi6lH +E6cUkbI0KGd/F4U2gPdhNrR9Fxwea5bbifkVF7Gx/ZkRjZJiZ3w9+mCNTQbJDKhh +wITAzzT6WYznhvqbzzBX1fTa6kv0GAQtX7aHKM+XIwkhX2gzU5TU80bvH8aMrT05 +tAMGQqkUeRnpo0yucBl4VmTZzd/+X/d2UyXR0my15jE5iH5o+p+E6qTRE9D+MGUd +MQ6Ftj0Untqy1lcog1ZLL6zPlnwcD4jgY5VCYDgvabnrSwymOJapPLsAEdWdq+U5 +ec44BMECgYEA/+3qPUrd4XxA517qO3fCGBvf2Gkr7w5ZDeATOTHGuD8QZeK0nxPl +CWhRjdgkqo0fyf1cjczL5XgYayo+YxkO1Z4RUU+8lJAHlVx9izOQo+MTQfkwH4BK +LYlHxMoHJwAOXXoE+dmBaDh5xT0mDUGU750r763L6EFovE4qRBn9hxkCgYEA0GWz +rpOPNxb419WxG9npoQYdCZ5IbmEOGDH3ReggVzWHmW8sqtkqTZm5srcyDpqAc1Gu +paUveMblEBbU+NFJjLWOfwB5PCp8jsrqRgCQSxolShiVkc3Vu3oyzMus9PDge1eo +9mwVGO7ojQKWRu/WVAakENPaAjeyyhv4dqSNnjsCgYEAlwe8yszqoY1k8+U0T0G+ +HeIdOCXgkmOiNCj+zyrLvaEhuS6PLq1b5TBVqGJcSPWdQ+MrglbQIKu9pUg5ptt7 +wJ5WU+i9PeK9Ruxc/g/BFKYFkFJQjtZzb+nqm3wpul8zGwDN/O/ZiTqCyd3rHbmM +/dZ/viKPCZHIEBAEq0m3LskCgYBndzcAo+5k8ZjWwBfQth5SfhCIp/daJgGzbYtR +P/BenAsY2KOap3tjT8Fsw5usuHSxzIojX6H0Gvu7Qzq11mLn43Q+BeQrRQTWeFRc +MQdy4iZFZXNNEp7dF8yE9VKHwdgSJPGUdxD6chMvf2tRCN6mlS171VLV6wVvZvez +H/vX5QKBgD2Dq/NHpjCpAsECP9awmNF5Akn5WJbRGmegwXIih2mOtgtYYDeuQyxY +ZCrdJFfIUjUVPagshEmUklKhkYMYpzy2PQDVtaVcm6UNFroxT5h+J+KDs1LN1H8G +LsASrzyAg8EpRulwXEfLrWKiu9DKv8bMEgO4Ovgz8zTKJZIFhcac +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/bob.pem b/src/security/builtin_plugins/tests/validate_local_identity/etc/bob.pem new file mode 100644 index 0000000..cf62cc3 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/bob.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAweb6oblp8IcV2an3z5n484Hu8PdaF+CEpW6CHwV6d7C49pqi +0rGIYATSQJ/xZdTmXhcNHeIFYmwYMeWXXI7Ivgpb2CvB+d+IkyXza4jMoYOJElsW +RdU4sX8NxUuy6oyhGOWTT36eWuD/vFL3qK2CbrK55b9Q4hemj4SUIfCetiem4cet +gzSzu3WWzdAVLJ1rcg3H4uQzo39v695UkX3nJ97ga9UGEWkuRa1fjEqBnIyNzO+Z +notU01Ke2E+GVkUeaylDKpetOcbJrHerKiWiqH2JsO8ArmlSfOqW/8PLK3XXSrdt +cVHkDTCp+PR+q2nszDhN1OQVDLWfj9jgS5PwjwIDAQABAoIBAHfgWhED9VgL29le +uGMzmPLK4LM+6Qcb+kXghTeyhl1a928WeRVzRpG+SVJEz9QaBHYlICnaY2PO2kJ2 +49YIPFkpRFDn9JuLs/7tFonj4Eb2cBbWE3YG9W7e0t+oBiv1117yB9m8uSAMPG7s +iEpTQvE3M7CzT8kHwCS4XXCCN0z7LqKyZ1heScjdfhV3D2TnFFjdtQ/9KfQa3hIc +6ftbpi4EKbfasspyqfrJ/cqjHzse9iEXLOZJhs+atBAKe/uJ4Hc3LRPbX4MPniAp +JJrldXFK9p+HILlbXvu+5n+DSGbZmT1x9a/E9suGyoJiASDH2Ax4yCVTi+v8C1R2 +aKdU1LkCgYEA/3dFuM6zIHwiJ0GKT0gtJL6J3m+i51SNcRIm8deXt6HULMpUNajj +vZ1bgQm/h+uRBlPV3swkaVxvPTIabOTY4gmCBSzvVCSIAKHVc/+5Nkl9KruwSq4G +tctmXZ7ymMDi+6QGCJTJkAx6jptXyrzC00HOjXOwyQ+iDipqgr3A8FsCgYEAwk7B +2/hi569EIHFRT6nz/JMqQVPZ/MJDKoKhffTbnjQ5OAzpiVN6cyThMM1iVJEBFNhx +OEacy60Qj0TtR1oYrQSRSLm58TTxiuB4Pohbmg3iU+kSM/eTq/ups/Ul1oCs2eAb +POfweD3c4d4i7sN8bUNQXehiE4MOlK9TYQy39t0CgYAJht0mwy6S644qgJsz0bE9 +SY3Cqc8daV3M9axWIIAb7QEImpMBXUcA7zlWWpK18ub5oW68XEiPVU8grRmnLfGY +nFoo70ANlz8rJt3a8ZJqn9r3GQC+CDdf2DH9E8xgPfE5CSjgcQwDPzPi1ZA0k02A +q1eUltfk55xXguVt8r2bOQKBgQC7+kldr1yv20VDRZ1uPnMGRLE6Zg6bkqw78gid +vEbDNK6uZP+BlTr/LgyVk/yu52Fucz6FPPrvqEw+7mXHA4ifya1r+BHFIn0S57os +dOp5jTkKCI9NqxQ3683vhRjH/dA7L63qLFDdYqvP74FID+LOKbMURn6rdbyjZ0J4 +vz8yGQKBgHIzcKlQosRxf+KptOPMGRs30L9PnH+sNmTo2SmEzAGkBkt1msGRh/2l +uT3hOEhUXL9knRyXwQSXgrIwr9QwI5rGS5FAgX26TgBtPBDs2NuyyhhS5yxsiEPT +BR+EjQFW9dzRkpRJgvsG4DcNAhFn7fQqFNcWXgFWuBXmGNkdtEGR +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_identity_ca b/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_identity_ca new file mode 100644 index 0000000..cfd24b6 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_identity_ca @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICEDCCAbegAwIBAgIJAPOifu8ejrRRMAoGCCqGSM49BAMCMGUxCzAJBgNVBAYT +Ak5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQKDBZBRExJTksgVGVjaG5v +bG9neSBCLlYuMSAwHgYDVQQDDBdDSEFNXzU3MCBDQSBjZXJ0aWZpY2F0ZTAeFw0x +OTAyMTgxMDQwMTZaFw00NjA3MDYxMDQwMTZaMGUxCzAJBgNVBAYTAk5MMRMwEQYD +VQQIDApTb21lLVN0YXRlMR8wHQYDVQQKDBZBRExJTksgVGVjaG5vbG9neSBCLlYu +MSAwHgYDVQQDDBdDSEFNXzU3MCBDQSBjZXJ0aWZpY2F0ZTBZMBMGByqGSM49AgEG +CCqGSM49AwEHA0IABMXCYXBHEryADoYXMEE0Jw9aHlA7p3KVFzuypxuez0n7rKoX +k9kanNtrw5o2X4WSWKM7zkH4I6AU7xSAQgJN+8GjUDBOMB0GA1UdDgQWBBR1Llq9 +zrRrTJLSvUJykksncZ+HsDAfBgNVHSMEGDAWgBR1Llq9zrRrTJLSvUJykksncZ+H +sDAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0cAMEQCIHKRM3VeB2F7z3nJT752 +gY5mNdj91ulmNX84TXA7UHNKAiA2ytpsV4OKURHkjyn1gnW48JDKtHGZF6/tMNvX +VrDITA== +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_identity_certificate b/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_identity_certificate new file mode 100644 index 0000000..5c29b6e --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_identity_certificate @@ -0,0 +1,50 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4096 (0x1000) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: C=NL, ST=Some-State, O=ADLINK Technology B.V., CN=CHAM_570 CA certificate + Validity + Not Before: Feb 18 10:52:41 2019 GMT + Not After : Jul 6 10:52:41 2046 GMT + Subject: C=NL, ST=Some-State, O=ADLINK Technology B.V., CN=CHAM_570 Identity certificate + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:9d:b5:7b:f5:fe:63:da:24:e4:0c:26:c5:32:55: + 55:b3:7f:7a:60:ea:0d:56:2c:0a:85:e0:5b:85:5a: + 01:1b:69:fc:23:79:98:33:d6:60:d5:d9:ab:1e:1d: + 7a:1e:c2:5f:ad:30:9b:73:45:40:39:d9:07:f7:59: + 8d:44:f6:6b:e3 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Basic Constraints: + CA:false + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + C6:68:7E:D7:20:B3:51:4B:D4:50:54:26:12:86:BE:9B:EA:55:A1:EA + X509v3 Authority Key Identifier: + keyid:75:2E:5A:BD:CE:B4:6B:4C:92:D2:BD:42:72:92:4B:27:71:9F:87:B0 + + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:21:00:b2:a7:be:fb:0b:d4:e2:87:b0:2c:c9:b8:fa: + 10:b0:18:4b:dc:6a:bc:58:55:e8:22:46:93:d8:b1:5b:50:17: + 77:02:20:2a:cf:42:10:fc:7e:02:39:37:44:4a:cf:9b:a3:9a: + 55:cb:15:2d:12:86:06:7e:d4:b8:24:7a:57:13:48:b5:69 +-----BEGIN CERTIFICATE----- +MIICOzCCAeGgAwIBAgICEAAwCgYIKoZIzj0EAwIwZTELMAkGA1UEBhMCTkwxEzAR +BgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2d5IEIu +Vi4xIDAeBgNVBAMMF0NIQU1fNTcwIENBIGNlcnRpZmljYXRlMB4XDTE5MDIxODEw +NTI0MVoXDTQ2MDcwNjEwNTI0MVowazELMAkGA1UEBhMCTkwxEzARBgNVBAgMClNv +bWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2d5IEIuVi4xJjAkBgNV +BAMMHUNIQU1fNTcwIElkZW50aXR5IGNlcnRpZmljYXRlMFkwEwYHKoZIzj0CAQYI +KoZIzj0DAQcDQgAEnbV79f5j2iTkDCbFMlVVs396YOoNViwKheBbhVoBG2n8I3mY +M9Zg1dmrHh16HsJfrTCbc0VAOdkH91mNRPZr46N7MHkwCQYDVR0TBAIwADAsBglg +hkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O +BBYEFMZoftcgs1FL1FBUJhKGvpvqVaHqMB8GA1UdIwQYMBaAFHUuWr3OtGtMktK9 +QnKSSydxn4ewMAoGCCqGSM49BAMCA0gAMEUCIQCyp777C9Tih7Asybj6ELAYS9xq +vFhV6CJGk9ixW1AXdwIgKs9CEPx+Ajk3RErPm6OaVcsVLRKGBn7UuCR6VxNItWk= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_identity_certificate_unsupported b/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_identity_certificate_unsupported new file mode 100644 index 0000000..220abcf --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_identity_certificate_unsupported @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICFTCCAbygAwIBAgICEAEwCgYIKoZIzj0EAwIwWjELMAkGA1UEBhMCTkwxEzAR +BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5 +IEx0ZDETMBEGA1UEAwwKQ0hBTTUwMF9DQTAeFw0xODAyMTkxMDMyMjRaFw0xOTAy +MTkxMDMyMjRaMGExCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxGjAYBgNVBAMMEUNIQU01 +NjkgdW5zdXAga2V5MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQIDMgAEKt3HYPnDlEOS +zYqTzT2patyreLHN2Jty22KXwjaNAjgrwujdPr+MW38DsyBF5Yn9o3sweTAJBgNV +HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp +Y2F0ZTAdBgNVHQ4EFgQUG9MuQz3W/AKA98AyOKhI2af9I+0wHwYDVR0jBBgwFoAU +ACsYsaEsZfjfRVrj0IBmcsncVyMwCgYIKoZIzj0EAwIDRwAwRAIgfhisahVmgghI +GaaQavdKHpM/OTVODZPzYjky6Am+z08CIBidnuuznXrZtr78oy/tAES/7Lz8P5Iw +Q1y5Vo8CdXQQ +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_private_key b/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_private_key new file mode 100644 index 0000000..214e2dd --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_private_key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgP3SnBXzcCc0uUEiG +0CPNdcV0hBewOnVoh4d9q9E5U5ihRANCAASdtXv1/mPaJOQMJsUyVVWzf3pg6g1W +LAqF4FuFWgEbafwjeZgz1mDV2aseHXoewl+tMJtzRUA52Qf3WY1E9mvj +-----END PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_private_key_unsupported b/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_private_key_unsupported new file mode 100644 index 0000000..421d9a3 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_private_key_unsupported @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MG8CAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQIEVTBTAgEBBBh8p6kwBS7jT86ctN33 +Vs4vosHh7upPZBWhNAMyAAQq3cdg+cOUQ5LNipPNPalq3Kt4sc3Ym3LbYpfCNo0C +OCvC6N0+v4xbfwOzIEXlif0= +-----END PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_private_key_w_password b/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_private_key_w_password new file mode 100644 index 0000000..f1f6e13 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/ec_private_key_w_password @@ -0,0 +1,8 @@ +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,11055B75D406068EB1FF850646228EA9 + +GUnwN8e2gvUkopN3ak+2dK1dSTSKSJguers3h5C+qQDq57By933ijCCjUTu2LY/F +ERH6m8UD6H5ij/QDsXLx6tH/dFQ7An+Zao3eD2N2zquGED/OfTQJFv3gBKs4RUtg +66dfuv9mNSXt7Rnu9uBNtodm5JGifczdmIPHn0mNY2g= +-----END EC PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/identity_ca b/src/security/builtin_plugins/tests/validate_local_identity/etc/identity_ca new file mode 100644 index 0000000..7e2675c --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/identity_ca @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEmTCCA4GgAwIBAgIIZ5gEIUFhO5wwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE +BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp +ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDIx +MjE1MDUwMFoYDzIyMjIwMjIyMjIyMjAwWjBfMQswCQYDVQQGEwJOTDETMBEGA1UE +CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk +MRgwFgYDVQQDEw9DSEFNNTAwIHJvb3QgY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQC6Fa3TheL+UrdZCp9GhU/2WbneP2t/avUa3muwDttPxeI2XU9k +ZjBR95mAXme4SPXHk5+YDN319AqIje3oKhzky/ngvKH2GkoJKYxWnuDBfMEHdViz +2Q9/xso2ZvH50ukwWa0pfx2/EVV1wRxeQcRd/UVfq3KTJizG0M88mOYvGEAw3LFf +zef7k1aCuOofQmBvLukUudcYpMzfyHFp7lQqU4CcrrR5RtmfiUfrWfdGLea2iPDB +pJgN8ESOMwEHtOTEBDclYnH9L4t7CHQz+fXXS5IWFsDK9fCMQjnxDsDVeNrNzTYL +FaZrMg9S6IUQCEsQWsnq5weS8omOpVLUm9klAgMBAAGjggFVMIIBUTAMBgNVHRME +BTADAQH/MB0GA1UdDgQWBBQg2FZB/j8uWDVnJhjwXkX278znSTAfBgNVHSMEGDAW +gBQg2FZB/j8uWDVnJhjwXkX278znSTAPBgNVHQ8BAf8EBQMDB/+AMIHvBgNVHSUB +Af8EgeQwgeEGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwME +BggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK +KwYBBAGCNwoDAwYKKwYBBAGCNwoDBAYJYIZIAYb4QgQBBgsrBgEEAYI3CgMEAQYI +KwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUIAgIGCisGAQQBgjcU +AgIGCCsGAQUFBwMJBggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZI +hvcNAQELBQADggEBAKHmwejWRwGE1wf1k2rG8SNRV/neGsZ6Qfqf6co3TpR/Wi1s +iZDvSeT/rbqNBS7z34xnG88NIUwu00y78e8Mfon31ZZbK4Uo7fla9/D3ukdJqPQC +LKdbKJjR2kH+KCukY/1rghjJ8/X+t2egBit0LCOdsFCl07Sfksb9kpGUIZSFcYYm +geqhjhoNwxazzHiw+QWHC5HG9248JIizBmy1aymNWuMnPudhjHAnPcsIlqMVNq3t +Rv9ap7S8JeCxHVRPJvJeCwXWvW3dW/v3xH52Yn/fqRblN1w9Fxz5NhopKx0gj/Jd +sw2N4Fk4gaOWEolFpa0bwNw8nAx7moehZpowzfw= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/identity_ca_private_key b/src/security/builtin_plugins/tests/validate_local_identity/etc/identity_ca_private_key new file mode 100644 index 0000000..eb4f6fc --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/identity_ca_private_key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAuhWt04Xi/lK3WQqfRoVP9lm53j9rf2r1Gt5rsA7bT8XiNl1P +ZGYwUfeZgF5nuEj1x5OfmAzd9fQKiI3t6Coc5Mv54Lyh9hpKCSmMVp7gwXzBB3VY +s9kPf8bKNmbx+dLpMFmtKX8dvxFVdcEcXkHEXf1FX6tykyYsxtDPPJjmLxhAMNyx +X83n+5NWgrjqH0Jgby7pFLnXGKTM38hxae5UKlOAnK60eUbZn4lH61n3Ri3mtojw +waSYDfBEjjMBB7TkxAQ3JWJx/S+Lewh0M/n110uSFhbAyvXwjEI58Q7A1Xjazc02 +CxWmazIPUuiFEAhLEFrJ6ucHkvKJjqVS1JvZJQIDAQABAoIBAFktMHtw60J0A3fB +dmkGVDa78y4F+I88g6/XrYXW6NUHAQyKlRSJQFjXrpFtLImNNXPqVA47BFftFusw +ETY0kFo5QkuoOnnFSXuwlJeiVhWDosHfQ54UxK+4ZYnCte3CXIwWPbzoNSoutWTU +IbMuE1vzlz5s3GCWZ9jzkoz4vT8NrkucEQ2sxvAVWk2//SoQljN+b4BLDdsWl3Bq +l+9JR2EzROXrPH5voYUZV17LbnCOmU+6ucxlGu704oqLJBxtNyYKsSEh4KMo4lX4 +bOZVSct3LXifj5BQmF9vbi5FiJqFGtoY4iBw0IUq05CJ4nsQuW1ZLucXaw1tBRKn +S1l/C0ECgYEA9zWVLQtWGrOZ7we7dTbF5ghZ541NjR9NmBFET5lNRU5yDG0poRdh +WD2qioGJigV6ZaEoXny0jFqqqqPM5S/sDRtoicK+XlFuhURw0CZCAsisjVhCDGXU ++FJRbR+As7NFvb/9itvNE+PD4p39UXObePzM9JnlHSP7Ml0KdJqcQHUCgYEAwLOp +Sp9k0CbFy/lQCSBbBiiu6ol/OxSzOBuZsFIbV8ILcn8v5NWdrcArssJBMdLTIaHN +nrTxKOOAzFnPW6DeRmWM/NnwizB/a6uo34q6ywmXmgFSQPX86XTVZCdD96nNik0C +KaEY2SqJxrnYstVApWRJAwy7T2jxJEj0aEZBH/ECgYEAmYyTuyXWdsFl9N2lp1m9 +NHOtfDD9oZF2/eSDvLlpEIp4NpW7jM7b7RZojp2FU9CxRN0EGSR2dNOAPHt/sj/A +7CdBGIh4/FayQl7Pf8qzp80DuMvAQrkhvphK8W/m3jeVMxZEovKCAD+yFVmy1dvs +DwtfNvM8J4yI47B85Q5/zV0CgYArxGKN/VfjYvsH0e9Ys02ZP4JC6MnJ/HCcLMCi +aHOnYf5BmhuhqNbwULZcGny+OTkU6XAPPN+NPubRAxDyqb3yVTxJbaKRqok2Rj3L +z/GPDfWt1+D7uiMgTxXscnKgfKOfZtA37kv7fwrd5PYP4BmXtwhSNgERDy+94wgH +6vT9sQKBgBqsTsdDmBmKLQM/JzQC2AeQo0/ZFZIXdsiCShMbo2XALlaxZDYDu1it +M/zkpmWmHncrBnnW3h6ME1ZZj2HGTowDuJvQqR7cZW5jWY3uLpOnEAGeOoKPhfOP +IW2pVPZXq3Zl1yn86oG7C7poPRq0PRu+q2HtHP6/M0NgtGBx8F9M +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/identity_certificate b/src/security/builtin_plugins/tests/validate_local_identity/etc/identity_certificate new file mode 100644 index 0000000..6d3379d --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/identity_certificate @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEQTCCAymgAwIBAgIINpuaAAnrQZIwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE +BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp +ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE3MDIy +MjIyMjIwMFoYDzIyMjIwMjIyMjIyMjAwWjBcMQswCQYDVQQGEwJOTDETMBEGA1UE +CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk +MRUwEwYDVQQDEwxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDCpVhivH/wBIyu74rvQncnSZqKyspN6CvD1pmV9wft5PHhVt9jV79v +gSub5LADoRHAgFdv9duYgBr17Ob6uRrIY4B18CcrCjhQcC4gjx8y2jl9PeYm+qYD +3o44FYBrBq0QCnrQgKsb/qX9Z+Mw/VUiw65x68W876LEHQQoEgT4kxSuagwBoVRk +ePD6fYAKmT4XS3x+O0v+rHESTcsKF6yMadgp7h3eH1b8kJTzSx8JV9Zzq++mxjox +qhbBVP5nDze2hhSIeCkCvSrx7efkgKS4AQXa5/Z44GiAu1TfXXUqdic9rxwD0edn +ajNElnZe7sjok/0yuqvH+2hSqpNva/zpAgMBAAGjggEAMIH9MAwGA1UdDwQFAwMH +/4AwgewGA1UdJQSB5DCB4QYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYI +KwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3AgEVBgorBgEEAYI3AgEWBgorBgEE +AYI3CgMBBgorBgEEAYI3CgMDBgorBgEEAYI3CgMEBglghkgBhvhCBAEGCysGAQQB +gjcKAwQBBggrBgEFBQcDBQYIKwYBBQUHAwYGCCsGAQUFBwMHBggrBgEFBQgCAgYK +KwYBBAGCNxQCAgYIKwYBBQUHAwkGCCsGAQUFBwMNBggrBgEFBQcDDgYHKwYBBQID +BTANBgkqhkiG9w0BAQsFAAOCAQEAawdHy0Xw7nTK2ltp91Ion6fJ7hqYuj///zr7 +Adt6uonpDh/xl3esuwcFimIJrJrHujnGkL0nLddRCikmnzuBMNDWS6yq0/Ckl/YG +yjNr44dlX24wo+MVAgkj3/8CyWDZ3a8kBg9QT3bs2SqbjmhTrXN1DRyf9S5vJysE +I7V1gTN66BeKL64hOrAlRVrEu8Ds6TWL6Q/YH+61ViZkoLTeSaPjH4nknaFr4C35 +iji0JhkyfRHRRVPHFnaj25AkxOrSV64qVKoTMjDl5fji5iMGtjm6iJ7q05ml/qDl +nLotHXemZNvYhbwUmRzbt4Dls9EMH4VRbP85I94nM5TAvtHVNA== +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/identity_certificate_1024key b/src/security/builtin_plugins/tests/validate_local_identity/etc/identity_certificate_1024key new file mode 100644 index 0000000..9384833 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/identity_certificate_1024key @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICrjCCAZYCCQDn8i4K9c4ErjANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJO +TDETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMRgwFgYDVQQDDA9DSEFNNTAwIHJvb3QgY2EwHhcNMTgwMjE2MTAy +MzM2WhcNMjMwODA5MTAyMzM2WjBXMQswCQYDVQQGEwJOTDETMBEGA1UECAwKU29t +ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRAwDgYD +VQQDDAdDSEFNNTY5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDS5w0h8L70 +hkreKchVbTzfz4CrBLY4iADNSqPx9uW7DxjeHyLbKT2eRViY/xPuPXQmfRim01QM +sZWKvFr6k9WMsJ6ItNtCyKS/beONqvXOddIu+4IhNzEGs5v4pTJAOzraoZcVmXnf +Mr9G/baMYfMG47JR5HaSHDI5esa2STHt4wIDAQABMA0GCSqGSIb3DQEBCwUAA4IB +AQBdZ2ijHYH8TkOGBqzsNwnNwPaDb/NA0vAO9T5kSOm8HA8vKHnNza+DeUJN+5P/ +P4fLK7UZqpQN32MpvXL0068g99RLjAzAsEVn+0FTyc08r9p/KO/dxxdMKeET7Cpv +rMpu3W0A/EJptCQsTEZI0iqts7T2qQVXzoDlnUwEt3xdmKYJ9jbEq1UUCeexD3nP +LB+JtUtfGevVzIoBjHv0qA3ePA24jDUlx5bxFeoIDC4tEewvUG5ZekftsRdNe3fk +3LkwyK+4NN1ZCa2+S5SOAfjZA2o6qXiq/le0vWRgl7AHEgDr6w7xoRsw4K5dQ+0R +eKtsBC4XO1GqrNYdKuJb1MhI +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/invalid_identity_ca b/src/security/builtin_plugins/tests/validate_local_identity/etc/invalid_identity_ca new file mode 100644 index 0000000..b7b7678 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/invalid_identity_ca @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UEBhMCTkwx +EzARBgNVBAgMCk92ZXJpanNzZWwxEDAOBgNVBAcMB0hlbmdlbG8xDzANBgNVBAoM +BkFETElOSzEYMBYGA1UEAwwPQ0hBTTUwMCBSb290IENBMB4XDTE4MDIwOTE2Mjky +MVoXDTI4MDIwNzE2MjkyMVowVTELMAkGA1UEBhMCTkwxEzARBgNVBAgMCk92ZXJp +anNzZWwxDzANBgNVBAoMBkFETElOSzEgMB4GA1UEAwwXQ0hBTTUwMCBJbnRlcm1l +ZGlhdGUgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwucuU/L6N +iYxYJ7tyzcdzwXwYbr4GynZE4u2Sd7hcXrQGxTotm9BEhOZWscSGvH+UJSp0Vrb4 +3zDppiJ76ys6PeSBw1PpxdO97fO+eAE5DoXRj0a9lmnjbsV6waZ2GxgYQNVmKqbI +uPDfW+jsmRcTO94s05GWQshHeiqxuEUAv3/Qe2vOhulrg4YDcXrIDWK93cr1EmRX +Eq3Ck+Fjwtk5wAk3TANv2XQkVfS80jYAurL8J+XC2kyYB7e8KO92zqlfVXXMC3NI +YDcq86bAI4NNMjVE2zIVheMLoOEXaV7KUTYfEQABZl76aWLDxjED9kf371tcrZzJ +6xZ1M/rPGNblAgMBAAGjZjBkMB0GA1UdDgQWBBQngrlZqhQptCR4p04zqHamYUx7 +RTAfBgNVHSMEGDAWgBQrLYI+RHJtx1Pze8MSZbhaOful1DASBgNVHRMBAf8ECDAG +AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAfMmiQ0tv +o3K3xwSS621tsfkijUTx920hAe1XYY2XKrG7a/MJBhStex5A3AfqPOY9UMihkBl9 +3hgxOaddX9SAf2eLk2JLhqxZi1U/GVzT5h10AKLA5WUXIK4UGz3JRqhEm7V39t/N +G0LCdpWOZueezkfO6eGcAvOKthdd32a3zbn+rzzDHdsjzxhEEv8d8x1Xf4xH2dgk +HlpmpvXMfG/1aCzIpWGEPdkB7WR694GiCmh7hnFBiY+h1GFj2l5dThd51QqAlncM +u+NmlPCrFZL0ulwRFeo80KOwDpxkqgavDlP9irdWqM9VHybjGu0xFHCeElz9M6od +ym/MCh4ax7jDxg== +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/invalid_identity_certificate b/src/security/builtin_plugins/tests/validate_local_identity/etc/invalid_identity_certificate new file mode 100644 index 0000000..453f1fd --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/invalid_identity_certificate @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDNzCCAh8CCQDn8i4K9c4ErDANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJO +TDETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMRgwFgYDVTQDDA9DSEFNNTAwIHJvb3QgY2EwHhcNMTgwMjEyMTUw +NjUxWhcNMTkwNjI3MTUwNjUxWjBcMQswCQYDVQQGEwJOTDETMBEGA1UECAwKU29t +ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRUwEwYD +VQQDDAxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDRnnNnV3PZrbZwjxk+dkQcO3pK3wMvoDNAHPPiTfXRV2KjLHxsuK7wV+GPHmXo +97bot6vBxNQN7hfxoDLL+KBO9s3V+8OX6lOrF7hQ6+6/p9EgRoyNGo21eIzGwc2M +aJAKjImNMbM7FDTvhk3u+VTTJtlnKvJM1tgncbEZwRLri/2MEC5XS/O5FQT4AXPr +A6bRcGMqCVYtQ0ci6wd18PegA/rSmGSRf/TOd4jZXkxfHD+YOkHcxxz9sX4KnyOg +XZm8jDdBc7rxiDep8kIjL06VszJeoQrxjuf8cNZtbol/7ECS5aM2YOx7t0Dc/629 +V2Q5waRVBV5xVCJ0BzUh8rIFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGlkxYLr +ZI/XNjDC6RFfSFRoDc+Xpcg+GsJKKbw2+btZvAD8z7ofL01yGru9oi6u2Yy/ZDKT +liZ+gtsD8uVyRkS2skq7BvPzvoYErLmSqwlrcCbeX8uHiN7C76ll9PFtSjnwPD// +UaNyZM5dJB2eBh4/prclix+RR/FWQzkPqEVLwMcFBmnPZ0mvR2tncjpZq476Qyl9 +3jcmfms9qBfBPPjCdXqGEDgsTd2PpYRD2WDj/Ctl4rV7B2jnByullLUYIWGu0rYt +988waU5i8ie4t/TorBBLqQo/NO9jSXfEqcAnILPnv1QZanKzAAxSg7+FgFrsn359 +ihiEkx9zFUnPrdA= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/invalid_private_key b/src/security/builtin_plugins/tests/validate_local_identity/etc/invalid_private_key new file mode 100644 index 0000000..2672622 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/invalid_private_key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA0Z5zZ1dz2a22cI8ZPnZEHDt6St8DL6AzQBzz4k310Vdioyx8 +bLiu8Ffhjx5l6Pe26LerwcTUDe4X8aAyy/igTvbN1fvDl+pTqxe4UOvuv6fRIEaM +jRqNtXiMxsHNjGiQCoyJjTGzOxQ074ZN7vlU0ybZZyryTNbYJ3GxGcES64v9jBAu +V0vzuRUE+AFz6wOm0XBjKglWLUNHIusHdfD3oAP60phkkX/0zneI2V5MXxw/mDpB +3Mcc/bF+Cp8joF2ZvIw3QXO68Yg3qfJCIy9OlbMyXqEK8Y7n/HDWbW6Jf+xAkuWj +NmDse7dA3P+tvVdkOcGkVQVecVQidAc1IfKyBQIDAQABAoIBAEddUpzUQTTS11Hq +5gVF7lpORYxH8KW+PLSPJtjdAduLjKAQ++tn1OcuhDRdfQSbkUIZhfgqMqerb6tr +ht+6fZlknR9E34pQ1LtjD/U83cOSNrhuTFudtrEZoZPpVzl+P8vXnNzdFs/+SSdi +6hV5/U8F4u4kyOkwG9cR9eF2wiI+oQ/RBKCXUo3OVs9K27A/OkKsb7coL7yBsgBj +lzorS9a/DyHT2eiMKjwCZFyG4A66EkLi6t9JLJ8oTkI2WskXYeVEAbEXE57RWm44 +2OgTgfsgYgf2ftXq93KD17FN1m77dqp7EPAhjGnRHNq7+0Ykr1EO1nbDfqHG4gS+4o +lfP8iwECgYEA58da0R34l93yQnK0mAtoobwvsOjADnBVhBg9L4s2eDs8liUjf0zt +7hcMdUJaa7iMuNf3qGtnZtRURc3kSOE429Or7fCAYUr/AaA7+2ekPG1vjMb50tVv +se5rwb1hvgMYe2L5ktJJAg+RcmqpY+ncJ+hP/vWwZRxUKvXba50qqEkCgYEA54ZE +mJfSueGM/63xlhP71CM4OWtTqkQGp2OmgTOsBI5q/GUXr8vMR8sCEMHAc6HyXzmL +x/RnAoa/vTX58rXBk0QjfO9esIHa452697EIaJu5w8skCLDv2e/f+Jg7o/IDyUZs +5lqhiEuH9Qc3sx2nhnSYXMZWqwh8OchI7dCSE90CgYEAzrJ1JhpxUJYI7wM2VIWQ +GPQnH8BhTj8VtEidgCHJQK2rGUcjgepMIVECtiunUXtyW4GWBedKfmSKhvnXRLs9 +pqT9JaOeCaYFBiEsfMZvqUY4e/YSYtge1PIHvO40FWzTT23zneDUZPcXQY8nYsfy +otBFTt0yIumBkhJRTIYLvakCgYA+CcttvBj6OAcJJ/n5RgeP05QoRqsXj7zcs6YV +LtxkKClg0lHjiE+H2U0HYnOISJfijk/3V3UWxzavo7wDHlLtfC+qNZYA4/rcTRKh +dm2TYk8HuPJB5e+PTWiNe3VXu+zpzRY3L4fjNqIKtVFmjIasT6fYDEmC8PYgoZtx +JhdOfQKBgCD/bDkc+VI6lwQtoQQKiSfQjKGe+6Cw9K/obzWO0uJwBvZrGLXF8tTc +MOPIv9OILt7DYxpMXAiHv8HtzH5CFVrZ/nj63Soka/j2yvUdBDrGhyIbsc4pDu+ +lCFa0ZiT/u5vRAiOkM6GuStH4HxnW9LtwBtiYXtfU7IPExJiAlsq +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/new/CHAM-577.crt b/src/security/builtin_plugins/tests/validate_local_identity/etc/new/CHAM-577.crt new file mode 100644 index 0000000..3b30c97 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/new/CHAM-577.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEPTCCAyWgAwIBAgIIRmtzSKaI+rowDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE +BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp +ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDMy +MzEyMDEwMFoYDzIyMjIwMjIyMjIyMjAwWjBYMQswCQYDVQQGEwJOTDETMBEGA1UE +CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk +MREwDwYDVQQDEwhDSEFNLTU3NzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAMKlWGK8f/AEjK7viu9CdydJmorKyk3oK8PWmZX3B+3k8eFW32NXv2+BK5vk +sAOhEcCAV2/125iAGvXs5vq5GshjgHXwJysKOFBwLiCPHzLaOX095ib6pgPejjgV +gGsGrRAKetCAqxv+pf1n4zD9VSLDrnHrxbzvosQdBCgSBPiTFK5qDAGhVGR48Pp9 +gAqZPhdLfH47S/6scRJNywoXrIxp2CnuHd4fVvyQlPNLHwlX1nOr76bGOjGqFsFU +/mcPN7aGFIh4KQK9KvHt5+SApLgBBdrn9njgaIC7VN9ddSp2Jz2vHAPR52dqM0SW +dl7uyOiT/TK6q8f7aFKqk29r/OkCAwEAAaOCAQAwgf0wDAYDVR0PBAUDAwf/gDCB +7AYDVR0lBIHkMIHhBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEF +BQcDBAYIKwYBBQUHAwgGCisGAQQBgjcCARUGCisGAQQBgjcCARYGCisGAQQBgjcK +AwEGCisGAQQBgjcKAwMGCisGAQQBgjcKAwQGCWCGSAGG+EIEAQYLKwYBBAGCNwoD +BAEGCCsGAQUFBwMFBggrBgEFBQcDBgYIKwYBBQUHAwcGCCsGAQUFCAICBgorBgEE +AYI3FAICBggrBgEFBQcDCQYIKwYBBQUHAw0GCCsGAQUFBwMOBgcrBgEFAgMFMA0G +CSqGSIb3DQEBCwUAA4IBAQAniERWU9f/ijm9t8xuyOujEKDJl0Ded4El9mM5UYPR +ZSnabPNKQjABBS4sVISIYVwfQxGkPgK0MeMBKqs/kWsZ4rp8h5hlZvxFX8H148mo +3apNgdc/VylDBW5Ltbrypn/dZh9hFZE8Y/Uvo9HPksVEkjYuFN5v7e8/mwxTcrZ1 +BAZrTlDTiCR046NN1lUs/7oUaNCruFV7AU6RbGYnSzM6plPJHMRa9nzNeO0uPaHK +kNPe+/UGpMi7cpF9w0M5Z1wW+Nq45bBRejFLQkHSjOEeGL2zi7T1HFAHZQydd6Wo +zYffGTmyHqIjNArbOWEMYN6s1nqsQS+ifolr0MtfeHad +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/new/identity_ca b/src/security/builtin_plugins/tests/validate_local_identity/etc/new/identity_ca new file mode 100644 index 0000000..7e2675c --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/new/identity_ca @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEmTCCA4GgAwIBAgIIZ5gEIUFhO5wwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE +BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp +ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDIx +MjE1MDUwMFoYDzIyMjIwMjIyMjIyMjAwWjBfMQswCQYDVQQGEwJOTDETMBEGA1UE +CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk +MRgwFgYDVQQDEw9DSEFNNTAwIHJvb3QgY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQC6Fa3TheL+UrdZCp9GhU/2WbneP2t/avUa3muwDttPxeI2XU9k +ZjBR95mAXme4SPXHk5+YDN319AqIje3oKhzky/ngvKH2GkoJKYxWnuDBfMEHdViz +2Q9/xso2ZvH50ukwWa0pfx2/EVV1wRxeQcRd/UVfq3KTJizG0M88mOYvGEAw3LFf +zef7k1aCuOofQmBvLukUudcYpMzfyHFp7lQqU4CcrrR5RtmfiUfrWfdGLea2iPDB +pJgN8ESOMwEHtOTEBDclYnH9L4t7CHQz+fXXS5IWFsDK9fCMQjnxDsDVeNrNzTYL +FaZrMg9S6IUQCEsQWsnq5weS8omOpVLUm9klAgMBAAGjggFVMIIBUTAMBgNVHRME +BTADAQH/MB0GA1UdDgQWBBQg2FZB/j8uWDVnJhjwXkX278znSTAfBgNVHSMEGDAW +gBQg2FZB/j8uWDVnJhjwXkX278znSTAPBgNVHQ8BAf8EBQMDB/+AMIHvBgNVHSUB +Af8EgeQwgeEGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwME +BggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK +KwYBBAGCNwoDAwYKKwYBBAGCNwoDBAYJYIZIAYb4QgQBBgsrBgEEAYI3CgMEAQYI +KwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUIAgIGCisGAQQBgjcU +AgIGCCsGAQUFBwMJBggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZI +hvcNAQELBQADggEBAKHmwejWRwGE1wf1k2rG8SNRV/neGsZ6Qfqf6co3TpR/Wi1s +iZDvSeT/rbqNBS7z34xnG88NIUwu00y78e8Mfon31ZZbK4Uo7fla9/D3ukdJqPQC +LKdbKJjR2kH+KCukY/1rghjJ8/X+t2egBit0LCOdsFCl07Sfksb9kpGUIZSFcYYm +geqhjhoNwxazzHiw+QWHC5HG9248JIizBmy1aymNWuMnPudhjHAnPcsIlqMVNq3t +Rv9ap7S8JeCxHVRPJvJeCwXWvW3dW/v3xH52Yn/fqRblN1w9Fxz5NhopKx0gj/Jd +sw2N4Fk4gaOWEolFpa0bwNw8nAx7moehZpowzfw= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/new/identity_ca_private_key b/src/security/builtin_plugins/tests/validate_local_identity/etc/new/identity_ca_private_key new file mode 100644 index 0000000..eb4f6fc --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/new/identity_ca_private_key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAuhWt04Xi/lK3WQqfRoVP9lm53j9rf2r1Gt5rsA7bT8XiNl1P +ZGYwUfeZgF5nuEj1x5OfmAzd9fQKiI3t6Coc5Mv54Lyh9hpKCSmMVp7gwXzBB3VY +s9kPf8bKNmbx+dLpMFmtKX8dvxFVdcEcXkHEXf1FX6tykyYsxtDPPJjmLxhAMNyx +X83n+5NWgrjqH0Jgby7pFLnXGKTM38hxae5UKlOAnK60eUbZn4lH61n3Ri3mtojw +waSYDfBEjjMBB7TkxAQ3JWJx/S+Lewh0M/n110uSFhbAyvXwjEI58Q7A1Xjazc02 +CxWmazIPUuiFEAhLEFrJ6ucHkvKJjqVS1JvZJQIDAQABAoIBAFktMHtw60J0A3fB +dmkGVDa78y4F+I88g6/XrYXW6NUHAQyKlRSJQFjXrpFtLImNNXPqVA47BFftFusw +ETY0kFo5QkuoOnnFSXuwlJeiVhWDosHfQ54UxK+4ZYnCte3CXIwWPbzoNSoutWTU +IbMuE1vzlz5s3GCWZ9jzkoz4vT8NrkucEQ2sxvAVWk2//SoQljN+b4BLDdsWl3Bq +l+9JR2EzROXrPH5voYUZV17LbnCOmU+6ucxlGu704oqLJBxtNyYKsSEh4KMo4lX4 +bOZVSct3LXifj5BQmF9vbi5FiJqFGtoY4iBw0IUq05CJ4nsQuW1ZLucXaw1tBRKn +S1l/C0ECgYEA9zWVLQtWGrOZ7we7dTbF5ghZ541NjR9NmBFET5lNRU5yDG0poRdh +WD2qioGJigV6ZaEoXny0jFqqqqPM5S/sDRtoicK+XlFuhURw0CZCAsisjVhCDGXU ++FJRbR+As7NFvb/9itvNE+PD4p39UXObePzM9JnlHSP7Ml0KdJqcQHUCgYEAwLOp +Sp9k0CbFy/lQCSBbBiiu6ol/OxSzOBuZsFIbV8ILcn8v5NWdrcArssJBMdLTIaHN +nrTxKOOAzFnPW6DeRmWM/NnwizB/a6uo34q6ywmXmgFSQPX86XTVZCdD96nNik0C +KaEY2SqJxrnYstVApWRJAwy7T2jxJEj0aEZBH/ECgYEAmYyTuyXWdsFl9N2lp1m9 +NHOtfDD9oZF2/eSDvLlpEIp4NpW7jM7b7RZojp2FU9CxRN0EGSR2dNOAPHt/sj/A +7CdBGIh4/FayQl7Pf8qzp80DuMvAQrkhvphK8W/m3jeVMxZEovKCAD+yFVmy1dvs +DwtfNvM8J4yI47B85Q5/zV0CgYArxGKN/VfjYvsH0e9Ys02ZP4JC6MnJ/HCcLMCi +aHOnYf5BmhuhqNbwULZcGny+OTkU6XAPPN+NPubRAxDyqb3yVTxJbaKRqok2Rj3L +z/GPDfWt1+D7uiMgTxXscnKgfKOfZtA37kv7fwrd5PYP4BmXtwhSNgERDy+94wgH +6vT9sQKBgBqsTsdDmBmKLQM/JzQC2AeQo0/ZFZIXdsiCShMbo2XALlaxZDYDu1it +M/zkpmWmHncrBnnW3h6ME1ZZj2HGTowDuJvQqR7cZW5jWY3uLpOnEAGeOoKPhfOP +IW2pVPZXq3Zl1yn86oG7C7poPRq0PRu+q2HtHP6/M0NgtGBx8F9M +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/new/identity_certificate b/src/security/builtin_plugins/tests/validate_local_identity/etc/new/identity_certificate new file mode 100644 index 0000000..6d3379d --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/new/identity_certificate @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEQTCCAymgAwIBAgIINpuaAAnrQZIwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE +BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp +ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE3MDIy +MjIyMjIwMFoYDzIyMjIwMjIyMjIyMjAwWjBcMQswCQYDVQQGEwJOTDETMBEGA1UE +CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk +MRUwEwYDVQQDEwxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDCpVhivH/wBIyu74rvQncnSZqKyspN6CvD1pmV9wft5PHhVt9jV79v +gSub5LADoRHAgFdv9duYgBr17Ob6uRrIY4B18CcrCjhQcC4gjx8y2jl9PeYm+qYD +3o44FYBrBq0QCnrQgKsb/qX9Z+Mw/VUiw65x68W876LEHQQoEgT4kxSuagwBoVRk +ePD6fYAKmT4XS3x+O0v+rHESTcsKF6yMadgp7h3eH1b8kJTzSx8JV9Zzq++mxjox +qhbBVP5nDze2hhSIeCkCvSrx7efkgKS4AQXa5/Z44GiAu1TfXXUqdic9rxwD0edn +ajNElnZe7sjok/0yuqvH+2hSqpNva/zpAgMBAAGjggEAMIH9MAwGA1UdDwQFAwMH +/4AwgewGA1UdJQSB5DCB4QYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYI +KwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3AgEVBgorBgEEAYI3AgEWBgorBgEE +AYI3CgMBBgorBgEEAYI3CgMDBgorBgEEAYI3CgMEBglghkgBhvhCBAEGCysGAQQB +gjcKAwQBBggrBgEFBQcDBQYIKwYBBQUHAwYGCCsGAQUFBwMHBggrBgEFBQgCAgYK +KwYBBAGCNxQCAgYIKwYBBQUHAwkGCCsGAQUFBwMNBggrBgEFBQcDDgYHKwYBBQID +BTANBgkqhkiG9w0BAQsFAAOCAQEAawdHy0Xw7nTK2ltp91Ion6fJ7hqYuj///zr7 +Adt6uonpDh/xl3esuwcFimIJrJrHujnGkL0nLddRCikmnzuBMNDWS6yq0/Ckl/YG +yjNr44dlX24wo+MVAgkj3/8CyWDZ3a8kBg9QT3bs2SqbjmhTrXN1DRyf9S5vJysE +I7V1gTN66BeKL64hOrAlRVrEu8Ds6TWL6Q/YH+61ViZkoLTeSaPjH4nknaFr4C35 +iji0JhkyfRHRRVPHFnaj25AkxOrSV64qVKoTMjDl5fji5iMGtjm6iJ7q05ml/qDl +nLotHXemZNvYhbwUmRzbt4Dls9EMH4VRbP85I94nM5TAvtHVNA== +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/new/private_key b/src/security/builtin_plugins/tests/validate_local_identity/etc/new/private_key new file mode 100644 index 0000000..06f57d1 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/new/private_key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAwqVYYrx/8ASMru+K70J3J0maisrKTegrw9aZlfcH7eTx4Vbf +Y1e/b4Erm+SwA6ERwIBXb/XbmIAa9ezm+rkayGOAdfAnKwo4UHAuII8fMto5fT3m +JvqmA96OOBWAawatEAp60ICrG/6l/WfjMP1VIsOucevFvO+ixB0EKBIE+JMUrmoM +AaFUZHjw+n2ACpk+F0t8fjtL/qxxEk3LChesjGnYKe4d3h9W/JCU80sfCVfWc6vv +psY6MaoWwVT+Zw83toYUiHgpAr0q8e3n5ICkuAEF2uf2eOBogLtU3111KnYnPa8c +A9HnZ2ozRJZ2Xu7I6JP9Mrqrx/toUqqTb2v86QIDAQABAoIBAC1q32DKkx+yMBFx +m32QiLUGG6VfBC2BixS7MkMnzRXZYgcuehl4FBc0kLRjfB6cqsO8LqrVN1QyMBhK +GutN3c38SbE7RChqzhEW2+yE+Mao3Nk4ZEecHLiyaYT0n25ZtHAVwep823BAzwJ+ +BykbM45VEpNKbG1VjSktjBa9faNyZiZAEJEjVyla+6R8N4kHV52LbZcLjvJv3IQ2 +iPYRrmMyI5C23qTni0vy7yJbAXBo3CqgSlwie9FARBWT7Puu7F4mF1O1c/SnTysw +Tm3e5FzgfHipQbnRVn0w4rDprPMKmPxMnvf/Wkw0zVgNadp1Tc1I6Yj525DEQ07i +2gIn/gECgYEA4jNnY1u2Eu7x3pAQF3dRO0x35boVtuq9iwQk7q+uaZaK4RJRr+0Y +T68S3bPnfer6SHvcxtST89Bvs/j/Ky4SOaX037UYjFh6T7OIzPl+MzO1yb+VOBT6 +D6FVGEJGp8ZAITU1OfJPeTYViUeEC8tHFGoKUCk50FbB6jOf1oKtv/ECgYEA3EnB +Y7kSbJJaUuj9ciFUL/pAno86Cim3VjegK1wKgEiyDb610bhoMErovPwfVJbtcttG +eKJNuwizkRcVbj+vpjDvqqaP5eMxLl6/Nd4haPMJYzGo88Z8NJpwFRNF2KEWjOpQ +2NEvoCeRtVulCJyka2Tpljzw8cOXkxhPOe2UhHkCgYBo3entj0QO7QXm56T+LAvV +0PK45xdQEO3EuCwjGAFk5C0IgUSrqeCeeIzniZMltj1IQ1wsNbtNynEu3530t8wt +O7oVyFBUKGSz9IjUdkpClJOPr6kPMfJoMqRPtdIpz+hFPPSrI6IikKdVWHloOlp+ +pVaYqTQrWT1XRY2xli3VEQKBgGySmZN6Cx+h/oywswIGdUT0VdcQhq2to+QFpJba +VX6m1cM6hMip2Ag9U3qZ1SNPBBdBBfm9HQybHE3dj713/C2wHuAAGhpXIM1W+20k +X1knuC/AsSH9aQhQOf/ZMOq1crTfZBuI9q0782/sjGmzMsKPySU4QhUWruVb7OiD +NVkZAoGAEvihW7G+8/iOE40vGHyBqUeopAAWLciTAUIEwM/Oi3BYfNWNTWF/FWNc +nMvCZPYigY8C1vO+1iT2Frtd3CIU+f01Q3fJNJoRLlEiKLNZUJRF48OKUqjKSmsi +w6pucFO40z05YW7utApj4L82rZnOS0pd1tUI1yexqvj0i4ThJfk= +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/Alice_Test_2.crt b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/Alice_Test_2.crt new file mode 100644 index 0000000..f5f77eb --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/Alice_Test_2.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEJTCCAw2gAwIBAgIBFzANBgkqhkiG9w0BAQsFADBzMQswCQYDVQQGEwJOTDEL +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGjAYBgNVBAMTEUlkZW50 +aXR5IENBIFRlc3QyMSYwJAYJKoZIhvcNAQkBFhdpbmZvQGlzdC5hZGxpbmt0ZWNo +LmNvbTAeFw0xODA3MjAwMDAwMDBaFw0yNzA3MTkyMzU5NTlaMG0xCzAJBgNVBAYT +Ak5MMQswCQYDVQQIEwJPVjETMBEGA1UEChMKQURMaW5rIElTVDEUMBIGA1UEAxML +QWxpY2UgVGVzdDIxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu +Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Fb60RkFrDsRAIRf +LMf2fsiRnw9Agp7yEbUsA4Zg4X+hRhBkk78fFtagLisWo4LbT4DqKzqQXCvVnOn9 +a6uT0KsVejk2iaLoBy0fotQznudio3rzDpTfzP9eRDFVj8RJnl3JJ8P1DULxH7N0 +TyDBuKZ1ibBfuKjPffqeCEzYKgAc8NG2FB4m6mXzHhXuKw6W2v0IbHz6KYldsavf +04rq7ztw0t67bexSQ4gLSVJEwiohAregm0dLvQnap5xd2qn0yETteTL8Y+Ujym1D +WAnwDdwA6+0j2a0wkyzOzYQpZMt95NyZ8kcoqEqO8KAN2HclqfjHlg9iDscbof5x +45SQwwIDAQABo4HJMIHGMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFL66FT0vnlFE ++PKrtV+KhJoLsCOWMB8GA1UdIwQYMBaAFIFGyWkPWvNkBD2SCYj9H+NfnlOLMA8G +A1UdDwEB/wQFAwMH/4AwZQYDVR0lAQH/BFswWQYIKwYBBQUHAwEGCCsGAQUFBwMC +BggrBgEFBQcDAwYIKwYBBQUHAwQGCCsGAQUFBwMIBggrBgEFBQcDCQYIKwYBBQUH +Aw0GCCsGAQUFBwMOBgcrBgEFAgMFMA0GCSqGSIb3DQEBCwUAA4IBAQCsBINpBXSp +Xe3f5MMObeUXE2VhWZWIjMdDQRFDDjq6u1YR7rbffsCReiCX5zviU2dtVV8VN3MQ +k7wp8qEDKwP1ToMIwZGwT4Hfwei1eueJ1vuotgiGe0Gm3otXlGsb0C5otnsu63MM +OeFgkpZde3VpIqK9EmhgjWOD8TXc8Me7zBlYSEIaXkkwP0jAKRf5vFgz0WfE5ITx +SDKUO0OrcN789flO/OKLAHZ4cqNcxNPkMz7h9VBSgRRRk115HEa8Fe46nl1YpwRG +0urHlyAKoUV+J+I3Qy4+SwIDwix978hgGN3bKVyv9q0yAQRzpZ54EJOj4C7lNEpB +roGVpY4yYP/B +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/Bob_Chain_Test.crt b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/Bob_Chain_Test.crt new file mode 100644 index 0000000..e980af3 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/Bob_Chain_Test.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEJDCCAwygAwIBAgIBAzANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJOTDEL +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxJDAiBgNVBAMTG0lkZW50 +aXR5IENBIFRlc3QgV2l0aCBDaGFpbjEmMCQGCSqGSIb3DQEJARYXaW5mb0Bpc3Qu +YWRsaW5rdGVjaC5jb20wHhcNMTgwNjEzMDAwMDAwWhcNMjcwNjEwMjM1OTU5WjBw +MQswCQYDVQQGEwJOTDELMAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1Qx +FzAVBgNVBAMTDkJvYiBDaGFpbiBUZXN0MSYwJAYJKoZIhvcNAQkBFhdpbmZvQGlz +dC5hZGxpbmt0ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AMHm+qG5afCHFdmp98+Z+POB7vD3WhfghKVugh8FenewuPaaotKxiGAE0kCf8WXU +5l4XDR3iBWJsGDHll1yOyL4KW9grwfnfiJMl82uIzKGDiRJbFkXVOLF/DcVLsuqM +oRjlk09+nlrg/7xS96itgm6yueW/UOIXpo+ElCHwnrYnpuHHrYM0s7t1ls3QFSyd +a3INx+LkM6N/b+veVJF95yfe4GvVBhFpLkWtX4xKgZyMjczvmZ6LVNNSnthPhlZF +HmspQyqXrTnGyax3qyoloqh9ibDvAK5pUnzqlv/Dyyt110q3bXFR5A0wqfj0fqtp +7Mw4TdTkFQy1n4/Y4EuT8I8CAwEAAaOBuzCBuDAdBgNVHQ4EFgQUQpxLPHT5o/GQ +RwdBw2scINXnWlUwHwYDVR0jBBgwFoAUTVVCTRc4ST0XmE+EEsenSudwlwkwDwYD +VR0PAQH/BAUDAwf/gDBlBgNVHSUBAf8EWzBZBggrBgEFBQcDAQYIKwYBBQUHAwIG +CCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwgGCCsGAQUFBwMJBggrBgEFBQcD +DQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggEBAJwd60WigqbB +/6CT0ekvXZdvIV5IaIKiy6KYU0/0ebPVXn0YKp9LQTE6lYCr6hZUcEjBfkFBZhAy +KJJOb2sUXAnYqnX/mIipiNb7oHsCHxVCKAwEcmxsS3tGl2CXgpKL8EQQFKJgSrC/ +uzhf2QESQ0T5Mgni1jXXGf6SAwFAjk+mAM9bMdrtLOX39e5aKrgpZOHmdFke+m/K +upxP/M0/omTNNQaSfWDmfDvpdsRD9+mFG12Kzgpue2jut1qeICvSmcQsu2OBYG/Q +ZXMx8e8azoX0KB+njf826UcVgDkDmfwN9taOU2lFsmZAvYhpIslNwtH/Htu3zJWO +vQxyIh+kxFQ= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/Identity_CA_Test2.crt b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/Identity_CA_Test2.crt new file mode 100644 index 0000000..592eea3 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/Identity_CA_Test2.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIBFjANBgkqhkiG9w0BAQsFADBzMQswCQYDVQQGEwJOTDEL +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGjAYBgNVBAMTEUlkZW50 +aXR5IENBIFRlc3QyMSYwJAYJKoZIhvcNAQkBFhdpbmZvQGlzdC5hZGxpbmt0ZWNo +LmNvbTAeFw0xODA3MjAwMDAwMDBaFw0yNzA3MTkyMzU5NTlaMHMxCzAJBgNVBAYT +Ak5MMQswCQYDVQQIEwJPVjETMBEGA1UEChMKQURMaW5rIElTVDEaMBgGA1UEAxMR +SWRlbnRpdHkgQ0EgVGVzdDIxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlu +a3RlY2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyIweDOdB +xotexcDiUdbIdDLu9A6/KSpkxUJnYb2iRhBonmCNFvErEokso/Dga6QT3rg83UCg +GMJBSJSZhq/j+eZweHoXS8Ccet/aF2iNj5A5Uhn476M3zMg+rCoos2yKlpZLOz1x +QjrRJfeOoBHvkHkxBeupnnQPx4oAro7zoXMIO83NKLwCROC/kGq1ktW8fbKa5THQ +z0QfZG3zAeD93N+dTAqA+jkCfzbrQepF243Tu4cLaGwVALZ/8cZ7sky8+OOmKnBU +P9r+U/4L62DVJYnYkTGnYEwqXcM1b8/JHasmKEaHXgAu/UI5i/SZfRPZUyC1ERSv +tX6k7sBxZZSPLQIDAQABo4HJMIHGMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFIFG +yWkPWvNkBD2SCYj9H+NfnlOLMB8GA1UdIwQYMBaAFIFGyWkPWvNkBD2SCYj9H+Nf +nlOLMA8GA1UdDwEB/wQFAwMH/4AwZQYDVR0lAQH/BFswWQYIKwYBBQUHAwEGCCsG +AQUFBwMCBggrBgEFBQcDAwYIKwYBBQUHAwQGCCsGAQUFBwMIBggrBgEFBQcDCQYI +KwYBBQUHAw0GCCsGAQUFBwMOBgcrBgEFAgMFMA0GCSqGSIb3DQEBCwUAA4IBAQCK +SkemYQIvsslkMc8PNHSk2om4xk7hUXkatAZPN9dvRravu3PJqMWxpQ0TWbddrkBL +he7/ARC2G9vVUwQl2b8K1Rjt/nZ3j+NPvhCDzcPyxjornyN8IG1NJQVH18fTxR23 +6PvDBE0H2trA3WJgKo6Wlxo6CHWts8ulFWWXBE1nNQw30hU49FDsFn3nz6Gry4ti +/ouAvbz+UXSsT9R+zkci3A394sEsOCZSStgAnXsejU45pCt6OtCGaLfDvEPp21az +OEjuIaj6Kbd+MHeLyPoe+d1Bkl39OnAUEJ8q2HdwvIg2ZqP6h0agm5gpZo/ALDWn +9P3owIGVsHFGkYqhHc+K +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/Identity_CA_Test_With_Chain.crt b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/Identity_CA_Test_With_Chain.crt new file mode 100644 index 0000000..35506b8 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/Identity_CA_Test_With_Chain.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIENDCCAxygAwIBAgIBAjANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50 +aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu +Y29tMB4XDTE4MDYxMzAwMDAwMFoXDTI3MDYxMDIzNTk1OVowfTELMAkGA1UEBhMC +TkwxCzAJBgNVBAgTAk9WMRMwEQYDVQQKEwpBRExpbmsgSVNUMSQwIgYDVQQDExtJ +ZGVudGl0eSBDQSBUZXN0IFdpdGggQ2hhaW4xJjAkBgkqhkiG9w0BCQEWF2luZm9A +aXN0LmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA1r8Q0V8ZVeBs8tPMF0N+JlBynl1Zn/89vwSsU4m7y6ixUcW/y3r12CMeA0cH +g6yOaOdHsZ8pRlPRwy9YmeOwLsMOUHAURP2uPiTjSf3pttUIf0jv602GyirNzoS7 +7mHiyTtV80ZMzZlLIJ3gaJJlG4DjitFuFcjv8sOmviFjkn1kOjkAz1nKgsCiHvvg +fcJlYPrtLfle9SzvZ3MTq4ob+/EFu9nt5bYYs7p7Br1TGWctUw98l2mSn/FhfDBw +9bb7ZhcKB7W6PGy2Os5AnkdTJKHoOQT+RmnHzPBhab0BoKuy8IhfW2GyqC8rL5Tm +/UVLUvnx4Zzqz//3IyA2FTb1HQIDAQABo4HJMIHGMAwGA1UdEwQFMAMBAf8wHQYD +VR0OBBYEFE1VQk0XOEk9F5hPhBLHp0rncJcJMB8GA1UdIwQYMBaAFER4R6N3MQ1W +l7gn+R8wwHloDCVZMA8GA1UdDwEB/wQFAwMH/4AwZQYDVR0lAQH/BFswWQYIKwYB +BQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYIKwYBBQUHAwQGCCsGAQUFBwMIBggr +BgEFBQcDCQYIKwYBBQUHAw0GCCsGAQUFBwMOBgcrBgEFAgMFMA0GCSqGSIb3DQEB +CwUAA4IBAQCbl7ed4p66G6WquxO7ceZFvYKn3kDErjCfXHcqHxBnA2xTpoZCGj95 +Qpirqo6N4UcLX5sn3CmgyVk0dYvlti/53FJgZ9XQDNxBuEYWPkY7vO+Uo0WdYpGz +ZDNIUQpiPMA7bHvwKldTIs77xxtnw9kbBU2k0xQyb2tdZNfD5YqSI1MeUtpEpNFW +sbC8+mQ3clzWpjF8eHH1fFSAmlJ+z1Uqmtt2FK0vRz+MQcpydwvpMnfqGdcwhGPQ +X4HZreLObjBA8KUEkUB3+rZXuELBgkk/c8/jRZl7QF5jJDLQCCLg7KoYBKN2GuTt +/dzeSnP7VZm/nTL8wpCvKgSOwOGgklf2 +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/alice.pem b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/alice.pem new file mode 100644 index 0000000..07a5977 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/alice.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA0Fb60RkFrDsRAIRfLMf2fsiRnw9Agp7yEbUsA4Zg4X+hRhBk +k78fFtagLisWo4LbT4DqKzqQXCvVnOn9a6uT0KsVejk2iaLoBy0fotQznudio3rz +DpTfzP9eRDFVj8RJnl3JJ8P1DULxH7N0TyDBuKZ1ibBfuKjPffqeCEzYKgAc8NG2 +FB4m6mXzHhXuKw6W2v0IbHz6KYldsavf04rq7ztw0t67bexSQ4gLSVJEwiohAreg +m0dLvQnap5xd2qn0yETteTL8Y+Ujym1DWAnwDdwA6+0j2a0wkyzOzYQpZMt95NyZ +8kcoqEqO8KAN2HclqfjHlg9iDscbof5x45SQwwIDAQABAoIBAG0dYPeqd0IhHWJ7 +8azufbchLMN1pX/D51xG2uptssfnpHuhkkufSZUYi4QipRS2ME6PYhWJ8pmTi6lH +E6cUkbI0KGd/F4U2gPdhNrR9Fxwea5bbifkVF7Gx/ZkRjZJiZ3w9+mCNTQbJDKhh +wITAzzT6WYznhvqbzzBX1fTa6kv0GAQtX7aHKM+XIwkhX2gzU5TU80bvH8aMrT05 +tAMGQqkUeRnpo0yucBl4VmTZzd/+X/d2UyXR0my15jE5iH5o+p+E6qTRE9D+MGUd +MQ6Ftj0Untqy1lcog1ZLL6zPlnwcD4jgY5VCYDgvabnrSwymOJapPLsAEdWdq+U5 +ec44BMECgYEA/+3qPUrd4XxA517qO3fCGBvf2Gkr7w5ZDeATOTHGuD8QZeK0nxPl +CWhRjdgkqo0fyf1cjczL5XgYayo+YxkO1Z4RUU+8lJAHlVx9izOQo+MTQfkwH4BK +LYlHxMoHJwAOXXoE+dmBaDh5xT0mDUGU750r763L6EFovE4qRBn9hxkCgYEA0GWz +rpOPNxb419WxG9npoQYdCZ5IbmEOGDH3ReggVzWHmW8sqtkqTZm5srcyDpqAc1Gu +paUveMblEBbU+NFJjLWOfwB5PCp8jsrqRgCQSxolShiVkc3Vu3oyzMus9PDge1eo +9mwVGO7ojQKWRu/WVAakENPaAjeyyhv4dqSNnjsCgYEAlwe8yszqoY1k8+U0T0G+ +HeIdOCXgkmOiNCj+zyrLvaEhuS6PLq1b5TBVqGJcSPWdQ+MrglbQIKu9pUg5ptt7 +wJ5WU+i9PeK9Ruxc/g/BFKYFkFJQjtZzb+nqm3wpul8zGwDN/O/ZiTqCyd3rHbmM +/dZ/viKPCZHIEBAEq0m3LskCgYBndzcAo+5k8ZjWwBfQth5SfhCIp/daJgGzbYtR +P/BenAsY2KOap3tjT8Fsw5usuHSxzIojX6H0Gvu7Qzq11mLn43Q+BeQrRQTWeFRc +MQdy4iZFZXNNEp7dF8yE9VKHwdgSJPGUdxD6chMvf2tRCN6mlS171VLV6wVvZvez +H/vX5QKBgD2Dq/NHpjCpAsECP9awmNF5Akn5WJbRGmegwXIih2mOtgtYYDeuQyxY +ZCrdJFfIUjUVPagshEmUklKhkYMYpzy2PQDVtaVcm6UNFroxT5h+J+KDs1LN1H8G +LsASrzyAg8EpRulwXEfLrWKiu9DKv8bMEgO4Ovgz8zTKJZIFhcac +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/bob.pem b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/bob.pem new file mode 100644 index 0000000..cf62cc3 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/bob.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAweb6oblp8IcV2an3z5n484Hu8PdaF+CEpW6CHwV6d7C49pqi +0rGIYATSQJ/xZdTmXhcNHeIFYmwYMeWXXI7Ivgpb2CvB+d+IkyXza4jMoYOJElsW +RdU4sX8NxUuy6oyhGOWTT36eWuD/vFL3qK2CbrK55b9Q4hemj4SUIfCetiem4cet +gzSzu3WWzdAVLJ1rcg3H4uQzo39v695UkX3nJ97ga9UGEWkuRa1fjEqBnIyNzO+Z +notU01Ke2E+GVkUeaylDKpetOcbJrHerKiWiqH2JsO8ArmlSfOqW/8PLK3XXSrdt +cVHkDTCp+PR+q2nszDhN1OQVDLWfj9jgS5PwjwIDAQABAoIBAHfgWhED9VgL29le +uGMzmPLK4LM+6Qcb+kXghTeyhl1a928WeRVzRpG+SVJEz9QaBHYlICnaY2PO2kJ2 +49YIPFkpRFDn9JuLs/7tFonj4Eb2cBbWE3YG9W7e0t+oBiv1117yB9m8uSAMPG7s +iEpTQvE3M7CzT8kHwCS4XXCCN0z7LqKyZ1heScjdfhV3D2TnFFjdtQ/9KfQa3hIc +6ftbpi4EKbfasspyqfrJ/cqjHzse9iEXLOZJhs+atBAKe/uJ4Hc3LRPbX4MPniAp +JJrldXFK9p+HILlbXvu+5n+DSGbZmT1x9a/E9suGyoJiASDH2Ax4yCVTi+v8C1R2 +aKdU1LkCgYEA/3dFuM6zIHwiJ0GKT0gtJL6J3m+i51SNcRIm8deXt6HULMpUNajj +vZ1bgQm/h+uRBlPV3swkaVxvPTIabOTY4gmCBSzvVCSIAKHVc/+5Nkl9KruwSq4G +tctmXZ7ymMDi+6QGCJTJkAx6jptXyrzC00HOjXOwyQ+iDipqgr3A8FsCgYEAwk7B +2/hi569EIHFRT6nz/JMqQVPZ/MJDKoKhffTbnjQ5OAzpiVN6cyThMM1iVJEBFNhx +OEacy60Qj0TtR1oYrQSRSLm58TTxiuB4Pohbmg3iU+kSM/eTq/ups/Ul1oCs2eAb +POfweD3c4d4i7sN8bUNQXehiE4MOlK9TYQy39t0CgYAJht0mwy6S644qgJsz0bE9 +SY3Cqc8daV3M9axWIIAb7QEImpMBXUcA7zlWWpK18ub5oW68XEiPVU8grRmnLfGY +nFoo70ANlz8rJt3a8ZJqn9r3GQC+CDdf2DH9E8xgPfE5CSjgcQwDPzPi1ZA0k02A +q1eUltfk55xXguVt8r2bOQKBgQC7+kldr1yv20VDRZ1uPnMGRLE6Zg6bkqw78gid +vEbDNK6uZP+BlTr/LgyVk/yu52Fucz6FPPrvqEw+7mXHA4ifya1r+BHFIn0S57os +dOp5jTkKCI9NqxQ3683vhRjH/dA7L63qLFDdYqvP74FID+LOKbMURn6rdbyjZ0J4 +vz8yGQKBgHIzcKlQosRxf+KptOPMGRs30L9PnH+sNmTo2SmEzAGkBkt1msGRh/2l +uT3hOEhUXL9knRyXwQSXgrIwr9QwI5rGS5FAgX26TgBtPBDs2NuyyhhS5yxsiEPT +BR+EjQFW9dzRkpRJgvsG4DcNAhFn7fQqFNcWXgFWuBXmGNkdtEGR +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_identity_ca b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_identity_ca new file mode 100644 index 0000000..cfd24b6 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_identity_ca @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICEDCCAbegAwIBAgIJAPOifu8ejrRRMAoGCCqGSM49BAMCMGUxCzAJBgNVBAYT +Ak5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQKDBZBRExJTksgVGVjaG5v +bG9neSBCLlYuMSAwHgYDVQQDDBdDSEFNXzU3MCBDQSBjZXJ0aWZpY2F0ZTAeFw0x +OTAyMTgxMDQwMTZaFw00NjA3MDYxMDQwMTZaMGUxCzAJBgNVBAYTAk5MMRMwEQYD +VQQIDApTb21lLVN0YXRlMR8wHQYDVQQKDBZBRExJTksgVGVjaG5vbG9neSBCLlYu +MSAwHgYDVQQDDBdDSEFNXzU3MCBDQSBjZXJ0aWZpY2F0ZTBZMBMGByqGSM49AgEG +CCqGSM49AwEHA0IABMXCYXBHEryADoYXMEE0Jw9aHlA7p3KVFzuypxuez0n7rKoX +k9kanNtrw5o2X4WSWKM7zkH4I6AU7xSAQgJN+8GjUDBOMB0GA1UdDgQWBBR1Llq9 +zrRrTJLSvUJykksncZ+HsDAfBgNVHSMEGDAWgBR1Llq9zrRrTJLSvUJykksncZ+H +sDAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0cAMEQCIHKRM3VeB2F7z3nJT752 +gY5mNdj91ulmNX84TXA7UHNKAiA2ytpsV4OKURHkjyn1gnW48JDKtHGZF6/tMNvX +VrDITA== +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_identity_certificate b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_identity_certificate new file mode 100644 index 0000000..5c29b6e --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_identity_certificate @@ -0,0 +1,50 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 4096 (0x1000) + Signature Algorithm: ecdsa-with-SHA256 + Issuer: C=NL, ST=Some-State, O=ADLINK Technology B.V., CN=CHAM_570 CA certificate + Validity + Not Before: Feb 18 10:52:41 2019 GMT + Not After : Jul 6 10:52:41 2046 GMT + Subject: C=NL, ST=Some-State, O=ADLINK Technology B.V., CN=CHAM_570 Identity certificate + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:9d:b5:7b:f5:fe:63:da:24:e4:0c:26:c5:32:55: + 55:b3:7f:7a:60:ea:0d:56:2c:0a:85:e0:5b:85:5a: + 01:1b:69:fc:23:79:98:33:d6:60:d5:d9:ab:1e:1d: + 7a:1e:c2:5f:ad:30:9b:73:45:40:39:d9:07:f7:59: + 8d:44:f6:6b:e3 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + X509v3 extensions: + X509v3 Basic Constraints: + CA:false + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + C6:68:7E:D7:20:B3:51:4B:D4:50:54:26:12:86:BE:9B:EA:55:A1:EA + X509v3 Authority Key Identifier: + keyid:75:2E:5A:BD:CE:B4:6B:4C:92:D2:BD:42:72:92:4B:27:71:9F:87:B0 + + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:21:00:b2:a7:be:fb:0b:d4:e2:87:b0:2c:c9:b8:fa: + 10:b0:18:4b:dc:6a:bc:58:55:e8:22:46:93:d8:b1:5b:50:17: + 77:02:20:2a:cf:42:10:fc:7e:02:39:37:44:4a:cf:9b:a3:9a: + 55:cb:15:2d:12:86:06:7e:d4:b8:24:7a:57:13:48:b5:69 +-----BEGIN CERTIFICATE----- +MIICOzCCAeGgAwIBAgICEAAwCgYIKoZIzj0EAwIwZTELMAkGA1UEBhMCTkwxEzAR +BgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2d5IEIu +Vi4xIDAeBgNVBAMMF0NIQU1fNTcwIENBIGNlcnRpZmljYXRlMB4XDTE5MDIxODEw +NTI0MVoXDTQ2MDcwNjEwNTI0MVowazELMAkGA1UEBhMCTkwxEzARBgNVBAgMClNv +bWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2d5IEIuVi4xJjAkBgNV +BAMMHUNIQU1fNTcwIElkZW50aXR5IGNlcnRpZmljYXRlMFkwEwYHKoZIzj0CAQYI +KoZIzj0DAQcDQgAEnbV79f5j2iTkDCbFMlVVs396YOoNViwKheBbhVoBG2n8I3mY +M9Zg1dmrHh16HsJfrTCbc0VAOdkH91mNRPZr46N7MHkwCQYDVR0TBAIwADAsBglg +hkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O +BBYEFMZoftcgs1FL1FBUJhKGvpvqVaHqMB8GA1UdIwQYMBaAFHUuWr3OtGtMktK9 +QnKSSydxn4ewMAoGCCqGSM49BAMCA0gAMEUCIQCyp777C9Tih7Asybj6ELAYS9xq +vFhV6CJGk9ixW1AXdwIgKs9CEPx+Ajk3RErPm6OaVcsVLRKGBn7UuCR6VxNItWk= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_identity_certificate_unsupported b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_identity_certificate_unsupported new file mode 100644 index 0000000..220abcf --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_identity_certificate_unsupported @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICFTCCAbygAwIBAgICEAEwCgYIKoZIzj0EAwIwWjELMAkGA1UEBhMCTkwxEzAR +BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5 +IEx0ZDETMBEGA1UEAwwKQ0hBTTUwMF9DQTAeFw0xODAyMTkxMDMyMjRaFw0xOTAy +MTkxMDMyMjRaMGExCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxGjAYBgNVBAMMEUNIQU01 +NjkgdW5zdXAga2V5MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQIDMgAEKt3HYPnDlEOS +zYqTzT2patyreLHN2Jty22KXwjaNAjgrwujdPr+MW38DsyBF5Yn9o3sweTAJBgNV +HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp +Y2F0ZTAdBgNVHQ4EFgQUG9MuQz3W/AKA98AyOKhI2af9I+0wHwYDVR0jBBgwFoAU +ACsYsaEsZfjfRVrj0IBmcsncVyMwCgYIKoZIzj0EAwIDRwAwRAIgfhisahVmgghI +GaaQavdKHpM/OTVODZPzYjky6Am+z08CIBidnuuznXrZtr78oy/tAES/7Lz8P5Iw +Q1y5Vo8CdXQQ +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_private_key b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_private_key new file mode 100644 index 0000000..214e2dd --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_private_key @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgP3SnBXzcCc0uUEiG +0CPNdcV0hBewOnVoh4d9q9E5U5ihRANCAASdtXv1/mPaJOQMJsUyVVWzf3pg6g1W +LAqF4FuFWgEbafwjeZgz1mDV2aseHXoewl+tMJtzRUA52Qf3WY1E9mvj +-----END PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_private_key_unsupported b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_private_key_unsupported new file mode 100644 index 0000000..421d9a3 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_private_key_unsupported @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MG8CAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQIEVTBTAgEBBBh8p6kwBS7jT86ctN33 +Vs4vosHh7upPZBWhNAMyAAQq3cdg+cOUQ5LNipPNPalq3Kt4sc3Ym3LbYpfCNo0C +OCvC6N0+v4xbfwOzIEXlif0= +-----END PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_private_key_w_password b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_private_key_w_password new file mode 100644 index 0000000..f1f6e13 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/ec_private_key_w_password @@ -0,0 +1,8 @@ +-----BEGIN EC PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,11055B75D406068EB1FF850646228EA9 + +GUnwN8e2gvUkopN3ak+2dK1dSTSKSJguers3h5C+qQDq57By933ijCCjUTu2LY/F +ERH6m8UD6H5ij/QDsXLx6tH/dFQ7An+Zao3eD2N2zquGED/OfTQJFv3gBKs4RUtg +66dfuv9mNSXt7Rnu9uBNtodm5JGifczdmIPHn0mNY2g= +-----END EC PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/identity_ca b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/identity_ca new file mode 100644 index 0000000..f003d92 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/identity_ca @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkTCCAnmgAwIBAgIJAJvGJOEKNct1MA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV +BAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxGDAWBgNVBAMMD0NIQU01MDAgcm9vdCBjYTAeFw0xODAy +MTIxNTA1MDVaFw0yMDEyMDIxNTA1MDVaMF8xCzAJBgNVBAYTAk5MMRMwEQYDVQQI +DApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQx +GDAWBgNVBAMMD0NIQU01MDAgcm9vdCBjYTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAM/dCO4QAcCduw0NMqShDpTvGT6DClTFAJE8ZfuPCHKqNkicRbyj +sVXfF35Sdo6K92Ksz4G7i1RqJU2n8c7hg2EFUza0lIGgmTHV/DvFBcbAa0PpvdKS +XoPtSNDh65/GO1R7oeSFRzapqsLMPUwOWi46dYvRnPabxs21xHxn56JeuG74bad5 +PMTBvA2SiiTYPBlHGJS78GPo3BPMjL0MzPoMmumO8NSVYI+MEDY1lC4KkyZVKqtV +nIfaO/7adcM19xOAfAHkwhLGBC/bVAEqelev+GH/42xjNv532nM4/JVtBns+msR5 +DAYdtr6i82b7zhU1+lOOihv4lmQHoSnTya8CAwEAAaNQME4wHQYDVR0OBBYEFFYr +0CpiwxgFcZnW6IQEhxGv/vwiMB8GA1UdIwQYMBaAFFYr0CpiwxgFcZnW6IQEhxGv +/vwiMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKbBt0ht72fdtxwm +Kr0pOsKyDW0Rd5Ca5aDK4qAhDL0AD5+O6ShGYCnFNDGk3J5Yzawp8VoKrhDZZyUt +z2b0jNucVapAvPMA4066QxeIfvFmWcS73l7vjjeUoKWmNNGWprTg3RLsacTorKuY +ZRL7wsThfrhvg4B/OOIWKp5MEwIrUfnQzUca8getF2eyTt6QcMtE29AW5+01QTzj +fxZgzkmJFYBE2K/TLMDBDd+bz/8XnmPrJ01VUntXiXenTGTcIbJerB6GYQojjvhy +ZrOeuHTON1ndFiQkpeZA67ByZjkKVoJG3I8fwBjzcLE7u/QAQptVPjJXXcSpL7fA +a1tOvqw= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/identity_certificate b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/identity_certificate new file mode 100644 index 0000000..7c03aae --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/identity_certificate @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDNzCCAh8CCQDn8i4K9c4ErDANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJO +TDETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMRgwFgYDVQQDDA9DSEFNNTAwIHJvb3QgY2EwHhcNMTgwMjEyMTUw +NjUxWhcNMTkwNjI3MTUwNjUxWjBcMQswCQYDVQQGEwJOTDETMBEGA1UECAwKU29t +ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRUwEwYD +VQQDDAxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDRnnNnV3PZrbZwjxk+dkQcO3pK3wMvoDNAHPPiTfXRV2KjLHxsuK7wV+GPHmXo +97bot6vBxNQN7hfxoDLL+KBO9s3V+8OX6lOrF7hQ6+6/p9EgRoyNGo21eIzGwc2M +aJAKjImNMbM7FDTvhk3u+VTTJtlnKvJM1tgncbEZwRLri/2MEC5XS/O5FQT4AXPr +A6bRcGMqCVYtQ0ci6wd18PegA/rSmGSRf/TOd4jZXkxfHD+YOkHcxxz9sX4KnyOg +XZm8jDdBc7rxiDep8kIjL06VszJeoQrxjuf8cNZtbol/7ECS5aM2YOx7t0Dc/629 +V2Q5waRVBV5xVCJ0BzUh8rIFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGlkxYLr +ZI/XNjDC6RFfSFRoDc+Xpcg+GsJKKbw2+btZvAD8z7ofL01yGru9oi6u2Yy/ZDKT +liZ+gtsD8uVyRkS2skq7BvPzvoYErLmSqwlrcCbeX8uHiN7C76ll9PFtSjnwPD// +UaNyZM5dJB2eBh4/prclix+RR/FWQzkPqEVLwMcFBmnPZ0mvR2tncjpZq476Qyl9 +3jcmfms9qBfBPPjCdXqGEDgsTd2PpYRD2WDj/Ctl4rV7B2jnByullLUYIWGu0rYt +988waU5i8ie4t/TorBBLqQo/NO9jSXfEqcAnILPnv1QZanKzAAxSg7+FgFrsn359 +ihiEkx9zFUnPrdA= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/identity_certificate_1024key b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/identity_certificate_1024key new file mode 100644 index 0000000..9384833 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/identity_certificate_1024key @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICrjCCAZYCCQDn8i4K9c4ErjANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJO +TDETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMRgwFgYDVQQDDA9DSEFNNTAwIHJvb3QgY2EwHhcNMTgwMjE2MTAy +MzM2WhcNMjMwODA5MTAyMzM2WjBXMQswCQYDVQQGEwJOTDETMBEGA1UECAwKU29t +ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRAwDgYD +VQQDDAdDSEFNNTY5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDS5w0h8L70 +hkreKchVbTzfz4CrBLY4iADNSqPx9uW7DxjeHyLbKT2eRViY/xPuPXQmfRim01QM +sZWKvFr6k9WMsJ6ItNtCyKS/beONqvXOddIu+4IhNzEGs5v4pTJAOzraoZcVmXnf +Mr9G/baMYfMG47JR5HaSHDI5esa2STHt4wIDAQABMA0GCSqGSIb3DQEBCwUAA4IB +AQBdZ2ijHYH8TkOGBqzsNwnNwPaDb/NA0vAO9T5kSOm8HA8vKHnNza+DeUJN+5P/ +P4fLK7UZqpQN32MpvXL0068g99RLjAzAsEVn+0FTyc08r9p/KO/dxxdMKeET7Cpv +rMpu3W0A/EJptCQsTEZI0iqts7T2qQVXzoDlnUwEt3xdmKYJ9jbEq1UUCeexD3nP +LB+JtUtfGevVzIoBjHv0qA3ePA24jDUlx5bxFeoIDC4tEewvUG5ZekftsRdNe3fk +3LkwyK+4NN1ZCa2+S5SOAfjZA2o6qXiq/le0vWRgl7AHEgDr6w7xoRsw4K5dQ+0R +eKtsBC4XO1GqrNYdKuJb1MhI +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/invalid_identity_ca b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/invalid_identity_ca new file mode 100644 index 0000000..b7b7678 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/invalid_identity_ca @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UEBhMCTkwx +EzARBgNVBAgMCk92ZXJpanNzZWwxEDAOBgNVBAcMB0hlbmdlbG8xDzANBgNVBAoM +BkFETElOSzEYMBYGA1UEAwwPQ0hBTTUwMCBSb290IENBMB4XDTE4MDIwOTE2Mjky +MVoXDTI4MDIwNzE2MjkyMVowVTELMAkGA1UEBhMCTkwxEzARBgNVBAgMCk92ZXJp +anNzZWwxDzANBgNVBAoMBkFETElOSzEgMB4GA1UEAwwXQ0hBTTUwMCBJbnRlcm1l +ZGlhdGUgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwucuU/L6N +iYxYJ7tyzcdzwXwYbr4GynZE4u2Sd7hcXrQGxTotm9BEhOZWscSGvH+UJSp0Vrb4 +3zDppiJ76ys6PeSBw1PpxdO97fO+eAE5DoXRj0a9lmnjbsV6waZ2GxgYQNVmKqbI +uPDfW+jsmRcTO94s05GWQshHeiqxuEUAv3/Qe2vOhulrg4YDcXrIDWK93cr1EmRX +Eq3Ck+Fjwtk5wAk3TANv2XQkVfS80jYAurL8J+XC2kyYB7e8KO92zqlfVXXMC3NI +YDcq86bAI4NNMjVE2zIVheMLoOEXaV7KUTYfEQABZl76aWLDxjED9kf371tcrZzJ +6xZ1M/rPGNblAgMBAAGjZjBkMB0GA1UdDgQWBBQngrlZqhQptCR4p04zqHamYUx7 +RTAfBgNVHSMEGDAWgBQrLYI+RHJtx1Pze8MSZbhaOful1DASBgNVHRMBAf8ECDAG +AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAfMmiQ0tv +o3K3xwSS621tsfkijUTx920hAe1XYY2XKrG7a/MJBhStex5A3AfqPOY9UMihkBl9 +3hgxOaddX9SAf2eLk2JLhqxZi1U/GVzT5h10AKLA5WUXIK4UGz3JRqhEm7V39t/N +G0LCdpWOZueezkfO6eGcAvOKthdd32a3zbn+rzzDHdsjzxhEEv8d8x1Xf4xH2dgk +HlpmpvXMfG/1aCzIpWGEPdkB7WR694GiCmh7hnFBiY+h1GFj2l5dThd51QqAlncM +u+NmlPCrFZL0ulwRFeo80KOwDpxkqgavDlP9irdWqM9VHybjGu0xFHCeElz9M6od +ym/MCh4ax7jDxg== +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/invalid_identity_certificate b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/invalid_identity_certificate new file mode 100644 index 0000000..453f1fd --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/invalid_identity_certificate @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDNzCCAh8CCQDn8i4K9c4ErDANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJO +TDETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMRgwFgYDVTQDDA9DSEFNNTAwIHJvb3QgY2EwHhcNMTgwMjEyMTUw +NjUxWhcNMTkwNjI3MTUwNjUxWjBcMQswCQYDVQQGEwJOTDETMBEGA1UECAwKU29t +ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRUwEwYD +VQQDDAxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDRnnNnV3PZrbZwjxk+dkQcO3pK3wMvoDNAHPPiTfXRV2KjLHxsuK7wV+GPHmXo +97bot6vBxNQN7hfxoDLL+KBO9s3V+8OX6lOrF7hQ6+6/p9EgRoyNGo21eIzGwc2M +aJAKjImNMbM7FDTvhk3u+VTTJtlnKvJM1tgncbEZwRLri/2MEC5XS/O5FQT4AXPr +A6bRcGMqCVYtQ0ci6wd18PegA/rSmGSRf/TOd4jZXkxfHD+YOkHcxxz9sX4KnyOg +XZm8jDdBc7rxiDep8kIjL06VszJeoQrxjuf8cNZtbol/7ECS5aM2YOx7t0Dc/629 +V2Q5waRVBV5xVCJ0BzUh8rIFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGlkxYLr +ZI/XNjDC6RFfSFRoDc+Xpcg+GsJKKbw2+btZvAD8z7ofL01yGru9oi6u2Yy/ZDKT +liZ+gtsD8uVyRkS2skq7BvPzvoYErLmSqwlrcCbeX8uHiN7C76ll9PFtSjnwPD// +UaNyZM5dJB2eBh4/prclix+RR/FWQzkPqEVLwMcFBmnPZ0mvR2tncjpZq476Qyl9 +3jcmfms9qBfBPPjCdXqGEDgsTd2PpYRD2WDj/Ctl4rV7B2jnByullLUYIWGu0rYt +988waU5i8ie4t/TorBBLqQo/NO9jSXfEqcAnILPnv1QZanKzAAxSg7+FgFrsn359 +ihiEkx9zFUnPrdA= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/invalid_private_key b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/invalid_private_key new file mode 100644 index 0000000..2672622 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/invalid_private_key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA0Z5zZ1dz2a22cI8ZPnZEHDt6St8DL6AzQBzz4k310Vdioyx8 +bLiu8Ffhjx5l6Pe26LerwcTUDe4X8aAyy/igTvbN1fvDl+pTqxe4UOvuv6fRIEaM +jRqNtXiMxsHNjGiQCoyJjTGzOxQ074ZN7vlU0ybZZyryTNbYJ3GxGcES64v9jBAu +V0vzuRUE+AFz6wOm0XBjKglWLUNHIusHdfD3oAP60phkkX/0zneI2V5MXxw/mDpB +3Mcc/bF+Cp8joF2ZvIw3QXO68Yg3qfJCIy9OlbMyXqEK8Y7n/HDWbW6Jf+xAkuWj +NmDse7dA3P+tvVdkOcGkVQVecVQidAc1IfKyBQIDAQABAoIBAEddUpzUQTTS11Hq +5gVF7lpORYxH8KW+PLSPJtjdAduLjKAQ++tn1OcuhDRdfQSbkUIZhfgqMqerb6tr +ht+6fZlknR9E34pQ1LtjD/U83cOSNrhuTFudtrEZoZPpVzl+P8vXnNzdFs/+SSdi +6hV5/U8F4u4kyOkwG9cR9eF2wiI+oQ/RBKCXUo3OVs9K27A/OkKsb7coL7yBsgBj +lzorS9a/DyHT2eiMKjwCZFyG4A66EkLi6t9JLJ8oTkI2WskXYeVEAbEXE57RWm44 +2OgTgfsgYgf2ftXq93KD17FN1m77dqp7EPAhjGnRHNq7+0Ykr1EO1nbDfqHG4gS+4o +lfP8iwECgYEA58da0R34l93yQnK0mAtoobwvsOjADnBVhBg9L4s2eDs8liUjf0zt +7hcMdUJaa7iMuNf3qGtnZtRURc3kSOE429Or7fCAYUr/AaA7+2ekPG1vjMb50tVv +se5rwb1hvgMYe2L5ktJJAg+RcmqpY+ncJ+hP/vWwZRxUKvXba50qqEkCgYEA54ZE +mJfSueGM/63xlhP71CM4OWtTqkQGp2OmgTOsBI5q/GUXr8vMR8sCEMHAc6HyXzmL +x/RnAoa/vTX58rXBk0QjfO9esIHa452697EIaJu5w8skCLDv2e/f+Jg7o/IDyUZs +5lqhiEuH9Qc3sx2nhnSYXMZWqwh8OchI7dCSE90CgYEAzrJ1JhpxUJYI7wM2VIWQ +GPQnH8BhTj8VtEidgCHJQK2rGUcjgepMIVECtiunUXtyW4GWBedKfmSKhvnXRLs9 +pqT9JaOeCaYFBiEsfMZvqUY4e/YSYtge1PIHvO40FWzTT23zneDUZPcXQY8nYsfy +otBFTt0yIumBkhJRTIYLvakCgYA+CcttvBj6OAcJJ/n5RgeP05QoRqsXj7zcs6YV +LtxkKClg0lHjiE+H2U0HYnOISJfijk/3V3UWxzavo7wDHlLtfC+qNZYA4/rcTRKh +dm2TYk8HuPJB5e+PTWiNe3VXu+zpzRY3L4fjNqIKtVFmjIasT6fYDEmC8PYgoZtx +JhdOfQKBgCD/bDkc+VI6lwQtoQQKiSfQjKGe+6Cw9K/obzWO0uJwBvZrGLXF8tTc +MOPIv9OILt7DYxpMXAiHv8HtzH5CFVrZ/nj63Soka/j2yvUdBDrGhyIbsc4pDu+ +lCFa0ZiT/u5vRAiOkM6GuStH4HxnW9LtwBtiYXtfU7IPExJiAlsq +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/private_key b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/private_key new file mode 100644 index 0000000..e21560b --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/private_key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA0Z5zZ1dz2a22cI8ZPnZEHDt6St8DL6AzQBzz4k310Vdioyx8 +bLiu8Ffhjx5l6Pe26LerwcTUDe4X8aAyy/igTvbN1fvDl+pTqxe4UOvuv6fRIEaM +jRqNtXiMxsHNjGiQCoyJjTGzOxQ074ZN7vlU0ybZZyryTNbYJ3GxGcES64v9jBAu +V0vzuRUE+AFz6wOm0XBjKglWLUNHIusHdfD3oAP60phkkX/0zneI2V5MXxw/mDpB +3Mcc/bF+Cp8joF2ZvIw3QXO68Yg3qfJCIy9OlbMyXqEK8Y7n/HDWbW6Jf+xAkuWj +NmDse7dA3P+tvVdkOcGkVQVecVQidAc1IfKyBQIDAQABAoIBAEddUpzUQTTS11Hq +5gVF7lpORYxH8KW+PLSPJtjdAduLjKFQ++tn1OcuhDRdfQSbkUIZhfgqMqerb6tr +ht+6fZlknR9E34pQ1LtjD/U83cOSNrhuTFudtrEZoZPpVzl+P8vXnNzdFs/+SSdi +6hV5/U8F4u4kyOkwG9cR9eF2wiI+oQ/RBKCXUo3OVs9K27A/OkKsb7coL7yBsgBj +lzorS9a/DyHT2eiMKjwCZFyG4A66EkLi6t9JLJ8oTkI2WskXYeVEAbEXE57RWm44 +2OgTI/Yc2yrtXq93KD17FN1m77dqp7EPAhjGnRHNq7+0Ykr1EO1nbDfqHG4gS+4o +lfP8iwECgYEA58da0R34l93yQnK0mAtoobwvsOjADnBVhBg9L4s2eDs8liUjf0zt +7hcMdUJaa7iMuNf3qGtnZtRURc3kSOE429Or7fCAYUr/AaA7+2ekPG1vjMb50tVv +se5rwb1hvgMYe2L5ktJJAg+RcmqpY+ncJ+hP/vWwZRxUKvXba50qqEkCgYEA54ZE +mJfSueGM/63xlhP71CM4OWtTqkQGp2OmgTOsBI5q/GUXr8vMR8sCEMHAc6HyXzmL +x/RnAoa/vTX58rXBk0QjfO9esIHa452697EIaJu5w8skCLDv2e/f+Jg7o/IDyUZs +5lqhiEuH9Qc3sx2nhnSYXMZWqwh8OchI7dCSE90CgYEAzrJ1JhpxUJYI7wM2VIWQ +GPQnH8BhTj8VtEidgCHJQK2rGUcjgepMIVECtiunUXtyW4GWBedKfmSKhvnXRLs9 +pqT9JaOeCaYFBiEsfMZvq8f4e/YSYtge1PIHvO40FWzTT23zneDUZPcXQY8nYsfy +otBFTt0yIumBkhJRTIYLvakCgYA+CcttvBj6OAcJJ/n5RgeP05QoRqsXj7zcs6YV +LtxkKClg0lHjiE+H2U0HYnOISJfijk/3V3UWxzavo7wDHlLtfC+qNZYA4/rcTRKh +dm2TYk8HuPJB5e+PTWiNe3VXu+zpzRY3L4fjNqIKtVFmjIasT6fYDEmC8PYgoZtx +JhdOfQKBgCD/bDkc+VI6lwQtoQQKiSfQjKGe+6Cw9K/obzWO0uJwBvZrGLXF8tTc +MOPIv9OILt7DYxpMXAiHv8HtzH5CFVrZ/nj63SRoka/j2yvUdBDrGhyIbsc4pDu+ +lCFa0ZiT/u5vRAiOkM6GuStH4HxnW9LtwBtiYXtfU7IPExJiAlsq +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/private_key_1024 b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/private_key_1024 new file mode 100644 index 0000000..709bcd6 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/private_key_1024 @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDS5w0h8L70hkreKchVbTzfz4CrBLY4iADNSqPx9uW7DxjeHyLb +KT2eRViY/xPuPXQmfRim01QMsZWKvFr6k9WMsJ6ItNtCyKS/beONqvXOddIu+4Ih +NzEGs5v4pTJAOzraoZcVmXnfMr9G/baMYfMG47JR5HaSHDI5esa2STHt4wIDAQAB +AoGAQi7LijkYU3fJCsql2Vj8X2eogwJphHf5eHLR296U3QyxyxKOR6Q7d+1fDjQN +txeF2YYsND3hBFK+ENlm23eE7Z1tpWtnLNJ9OH84ZkPnqTnEcWsRddT/x9vKOPMz +eK8QNetD3AP5qXsjpIpgep1diWYHCyhMTAFISzvdtC7pvFECQQD2zoqwRtF26lzg +QPR02Z+L80R2VhpeLoqMIplT1bmlrPlDr/eIwvtu1eQFyGSASG2EFs1rucdJl7qu +SrJ+eyv1AkEA2sIjy8+RCk1uH8kEwYaMJ3dccqnpcMCZ1b3GncKl+ICmDCYcpfd5 +rP5tX+GL3RVw370pUApJvrVTgOpAVHYjdwJAOYz8BhLdcS9BLQG4fy7n50h4pGd7 +io6ru/Wtb0EdIybskP4NaJSe8L9rhnWuCcPZ1b1DdWVCtURuQYoliRzLqQJBAJWO +ZrSfKpS1jRVT89lu6ADPXLfTrBH2yvVS8ifG/HshUOQ7ZhidUWVQ6GvFoj46u1lr +VIQxFGu6QeV/wQ09W08CQHGkrZgu/FpS2tNvYmKNDHOna+dW452N5N81u5sRP1A8 +x9pYC9xoOGE2E8v1ocMJDPoMe0yk1QSX9mjhhwYOy28= +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/private_key_not_matching b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/private_key_not_matching new file mode 100644 index 0000000..735a9af --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/private_key_not_matching @@ -0,0 +1,48 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpgIBAAKCAQEAz90I7hABwJ27DQ0ypKEOlO8ZPoMKVMUAkTxl+48Icqo2SJxF +vKOxVd8XflJ2jor3YqzPgbuLVGolTafxzuGDYQVTNrSUgaCZMdX8O8UFxsBrQ+m9 +0pJeg+1I0OHrn8Y7VHuh5IVHNqmqwsw9TA5aLjp1i9Gc9pvGzbXEfGfnol64bvht +p3k8xMG8DZKKJNg8GUcYlLvwY+jcE8yMvQzM+gya6Y7w1JVgj4wQNjWULgqTJlUq +q1Wch9o7/tp1wzX3E4B8AeTCEsYEL9tUASp6V6/4Yf/jbGM2/nfaczj8lW0Gez6a +xHkMBh22vqLzZvvOFTX6U46KG/iWZAehKdPJrwIDAQABAoIBAQDGvQsAsoU6aJSj +Ee9NwD903nZAcoG6MvEr65eGQWdOWre0DNYQWmH/PGH2AVohR3Tn/1oXK/03JJWt +/dkQeEVoyfKZ52Xl2mseXv3fF61CLk9gi2dWoWOEt6ZbMOZbyOiJCfvrxhIkjWwa ++7PPuBk5AePJXwy4LJCTtiq61418i2Bbl6JamytgxsiVK9kZXdN6JqEVYmweMpmR +T1mzi7lssyttBIXwG8ajStUteIYLyi8d+UX4S08EyV0VGL0p5+F8xTY1jVX/t6Y0 +KbANJdjEab9mbndzbxprJlS08KBLgdnAO4w0nmINiaO2isXOLoV8SU3tTqHC3W7c +CCSKJdGBAoGBAP9vCSP1AaEjYa6sfEUgThpCo7PhRuOMEDb+4ldv9O+hzXv5I8td +gbDs1g3jyhb0yhW9uV9NsuKBtsmv1zYFswZDNbdr2S1VZPMpAx+SeLHQWy6HbU/t +oHoOO+l8erFVvR2uqit5rBDzN6/lh4SoQzYE9JDAnXJp9W0rKAdtBSLRAoGBANBT +AIErbPo4EuU13DaEa+EfoU4Abktyi+L8dpdoXMq6sHg3Mlhifr+ryoybrMMA3tmT +6ekBCSVThF0/+HAFRAJthnyBgUd0D710JDHro47Mg37CxU+V8JYqZJGHUSfqng7/ +pM7LjM99VhigquH4PoDH4YpL8vnIeEMNmny4iER/AoGBAJj8k+jpUXSFkHfh7vwo +AR9RUmLmRmL6/KsztbTQ5U6xBjV+XqXq90ZUU1A2Yk+lhXPIEkK2crGfJy9dFfTR +LQxPLNkSyxyPzMqmgaxjOc6mEDap/hqlJDx2UgPh/kpAI+inOFyZnyj3wx6ixqv5 +a2frR996vdJNDCW6d1sbPLxBAoGBAMO66IN0UJy76Izw0Olr+4v10vFdmENM6T+o +IqhZBq33P+yDN8sxJ5NgjhsT/Pruq3LT9XbVYUlvsbKHcx2U5PQ/AZejedqvokZH +g+ZfVjnJz1ZfG1GOOBBu3jSZZdfSKRVAfhFJ0A/229ihxEwxmFAY/MCaYTzsbInb +kyXRnz5zAoGBAIT9Fuk7zhfubYvkzIQ0kj/IxL3QohVRKcoGapDMSwNjTvxZdKxF +WXkhhJT095QznHP1fhp90fBKlOdsReDWfZXMYtZTqo2+ezK8qb6xMlm+LE09y+Na +f7pp1EPnIqyEX27B4aQ81M8tkCqbdlv3CdjFSusp6SsWTGTjr/5SAMDS +-----END RSA PRIVATE KEY----- + +-----BEGIN CERTIFICATE----- +MIIDNzCCAh8CCQDn8i4K9c4ErDANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJO +TDETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMRgwFgYDVQQDDA9DSEFNNTAwIHJvb3QgY2EwHhcNMTgwMjEyMTUw +NjUxWhcNMTkwNjI3MTUwNjUxWjBcMQswCQYDVQQGEwJOTDETMBEGA1UECAwKU29t +ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRUwEwYD +VQQDDAxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDRnnNnV3PZrbZwjxk+dkQcO3pK3wMvoDNAHPPiTfXRV2KjLHxsuK7wV+GPHmXo +97bot6vBxNQN7hfxoDLL+KBO9s3V+8OX6lOrF7hQ6+6/p9EgRoyNGo21eIzGwc2M +aJAKjImNMbM7FDTvhk3u+VTTJtlnKvJM1tgncbEZwRLri/2MEC5XS/O5FQT4AXPr +A6bRcGMqCVYtQ0ci6wd18PegA/rSmGSRf/TOd4jZXkxfHD+YOkHcxxz9sX4KnyOg +XZm8jDdBc7rxiDep8kIjL06VszJeoQrxjuf8cNZtbol/7ECS5aM2YOx7t0Dc/629 +V2Q5waRVBV5xVCJ0BzUh8rIFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGlkxYLr +ZI/XNjDC6RFfSFRoDc+Xpcg+GsJKKbw2+btZvAD8z7ofL01yGru9oi6u2Yy/ZDKT +liZ+gtsD8uVyRkS2skq7BvPzvoYErLmSqwlrcCbeX8uHiN7C76ll9PFtSjnwPD// +UaNyZM5dJB2eBh4/prclix+RR/FWQzkPqEVLwMcFBmnPZ0mvR2tncjpZq476Qyl9 +3jcmfms9qBfBPPjCdXqGEDgsTd2PpYRD2WDj/Ctl4rV7B2jnByullLUYIWGu0rYt +988waU5i8ie4t/TorBBLqQo/NO9jSXfEqcAnILPnv1QZanKzAAxSg7+FgFrsn359 +ihiEkx9zFUnPrdA= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/private_key_w_password b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/private_key_w_password new file mode 100644 index 0000000..ba09dc0 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/private_key_w_password @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,0C9C38C5678AECD200E024A9A5BC717A + +wbXYsR78o4DIaQbKsB4cwEFge79GMKbcMgIWK+9k86dPk09WZkj7JCSJXIxPLYOG +tFZrw/z86cakEhf90a4Moa1cwByrcFB+bpWoEqsx/C4javWxXMENbmQ5x8gDpmzT +qqLI7xnd2mYj7HcfE7eXi+Nub5w1tBxN0CWaxpR54ZVvfcPE6Od4SHGughdUN4AK +OdVIq5YuzMhuTDJKy+kGOtjH8pBWvo8S12T2UQEuusx5WUbEJ6m+E80aN7M6gCA+ +XmNTt3PsV9PfZPL2Off/90gqTBdMhwn+sEVlqYG0TAnXZQEI8ZNtAGy77CFplqdT +SmI3x8Sza7lchEMFhRiayX9pMBPUlwckVPrCoMQ4b4WkHYoGLO7dNVAA8Osud46+ +6MZKHStjdzwKz9MzWa7lXhXV+0sX5bcAzQexuE+wO8QQ/t5uwDmQHol0JVdRX8NB +/Exk6aT7mWajFvukXVirpUGWnEK2W+O8/VBzVZ7z69EjZ09Pu4Y/+cbX12LGSwMb +WVtnZY6BsrV++vikQuL3ByTBDPRHio2H8hThh1Kv8n5VEBUrk7tLUp3Z15cbfC6s +LDHX6kB2OKmmdqLOOMo4lToZfnrVK/dzeXFbtNH1POpR4/e5Nk0SyZrWo+E/AqIv +nLQ3fhLCPOB5rjAhuM8iXOwqn8HHNlv9j8mlgCcgwK7focYVc/IXARLOfFOjOA/s +EqMRbb/eKsC930NHBZkhlqRJKCwA37AMvnOhN4R0VOq/40K+62IUK9E1643KyWs0 +vWk0rFY0OKorQXzI33lbBYZ5zHt8oxGNx3us+6jGP85iv8UEaO6FpgajEUn6Gzp/ +wyvr1C/B/Hfr6eTbt4C6Fi5fMfZgM6VEcJuaFZnoC9tWdhlNsY1pwtPghMM7yBwc +1Ye0TxdF36exJWu1gXVTse1Vdc9i4QWpT2fbPQtcIgdtNk01K+2defie384IOnQQ +O8/SRsrnLRLV3IDFh/VBJS1ZVm8Zmt10yGgRwtYHntMkIopoFRWcm9/Gh3iBFKKH +OTVXxgKOUYk4qXG61N8k0M+TIdoOHZIha3Myis1tQVmA/b/4FRKPYgdrFijhXNLM +wwMHQOS14xBF2KBgaak7dMUWhGrClw1hc3HmMXuM+OLvxy+f8MC3JP2U5AuCs472 +hc41KWxioqNMPVXZgVnHf3aEec+hBFceqYnlzG+E/Gagiufu8WMySaZgzXMRb5aV +x2OVcakSKrTC5EKbLDlZ6+1NRJht7wdSefh0o/Crc9LzcFqBL0Qp3WCvyY8gDVkQ +EGqoVYOE6Hz/NX5/17F1+5VuWT7nBWABHKFFriOoJ3VR9sZhp0HiMznZEF1AwVuZ +xHtDWQemfBywEQG23qbr+o7mQASh1zki8b4fP1HQmbHhaJarjwGdiVNIgcF7s7Qk +NYNcgsc1l0KuNHvredTnYwPhv3C08IBfjtd2H9u0A+AWl5RlR4GDfv2Jzbe/F8U+ +0gxj8D2XWHlkbHIXKVk6jxj64xyNE1xB0Sv7gsDWpkaK6aw/zdsyxqiji4mThcYE +cRSl4y9CGZREaiyD8dk/uiqKfQ26c1gfOUDYS2fKjH5NKh4J80wQj0GvS6nHiDH4 +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/remote b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/remote new file mode 100644 index 0000000..195709a --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/remote @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDMzCCAhsCCQDn8i4K9c4ErzANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJO +TDETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMRgwFgYDVQQDDA9DSEFNNTAwIHJvb3QgY2EwHhcNMTgwMzIzMTIw +MTE5WhcNMjMxMDMxMTIwMTE5WjBYMQswCQYDVQQGEwJOTDETMBEGA1UECAwKU29t +ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMREwDwYD +VQQDDAhDSEFNLTU3NzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcc +IMlRp2EnOC/UIIOF2gm+wtsikv5CscDuyq9DA2QgS5TTKqivDAdOSUIcbVn8qb6/ +77viarmRXml3VHJdhR2abtY6xYKYF2SCFiyoNk6ITq+YBrCfmMh/bCYTD6c5vnl4 +SKomIArU1g1YAxHxHqZRX1oonldUdP4lqq+Qt6fllYFhHNAl5JjrrCuPpXmAW3pC +z4b3HWP/6vnbOFFMYkwGprVoAljcnAG7C7zSjW2M3RN4xA/z6Lps8qrPFB2iAXaP +ZnST1rkqctf2IDWVwloG0uJnqiigcIz6+hvf5VMU0ax+CrYqFGav/uwvPCiHcUkF +3a/O3z+4xGHaBagfHukCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAXZlNPz6raCBp +F+iyNWTGy27OyM/TZNE9QTPI28TQEmLfqCrRfq+uHhBQ3U9TgS3xX/f5b+BPHuaD +N6vl/yECAQa+0r33EFdoe8rGa0Mr5VvADcqPmk/sp9K62fRcP4aCgliDi8g9G8q1 +XNgO/EA9HhFlFKPzLPFMhq7qqPOQWO/EddoxA/qCMGZtN+TAxqLKVB0lipJoSa0x +XqtYvNWiaShPceSk4SAjAdpdhvxOpA/25uvFEISdt9zoqbs4eLUbi/9RFYaL8U4r +E+FygZMi31N6PC/Q7/tJ4DG20K/V30Y1+ogvSfdJpWk9L/CJj0VrzqJTVaKBIFVV +6PtqHPZiKA== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/old/unrelated_identity_ca b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/unrelated_identity_ca new file mode 100644 index 0000000..52cf047 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/old/unrelated_identity_ca @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDpDCCAoygAwIBAgIJALE5lRKfYHAaMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV +BAYTAk5MMRMwEQYDVQQIDApPdmVyaWpzc2VsMRAwDgYDVQQHDAdIZW5nZWxvMQ8w +DQYDVQQKDAZBRExJTksxGDAWBgNVBAMMD0NIQU01MDAgUm9vdCBDQTAeFw0xODAy +MDkxNjIwNDNaFw0zODAyMDQxNjIwNDNaMF8xCzAJBgNVBAYTAk5MMRMwEQYDVQQI +DApPdmVyaWpzc2VsMRAwDgYDVQQHDAdIZW5nZWxvMQ8wDQYDVQQKDAZBRExJTksx +GDAWBgNVBAMMD0NIQU01MDAgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAN9/NbpJDHQYHh3cEByRxnHffxEe9Sapn08Ty5xYO8LDJ4V7vU32 +/7291fITiHaovOoCRHAbKTaTtqJO56aGY45HON6KIqxljLQJJVGW/Nf2PNSHmFix +6D6bsoSOTPyKYqBNT6lB7NMn4QBTcsiE61El8p9WLQZHoYQJK5Psf7wkBqGBz8he +bcDWXFn7kIgnsaLrh77w2wi/y0MqpPwyeRInoZfYknzVNdxCPgq7csBYDoMgOgkV +G60ECXojHKz1HI4n0V8L8lZluSSVRNR0xvPFgBqO7b+Re7xb6iO9TNsFeoiMMNyp +EwM99CqPO0RRrAPiC7IDgcNGjxhne9EJFGsCAwEAAaNjMGEwHQYDVR0OBBYEFCst +gj5Ecm3HU/N7wxJluFo5+6XUMB8GA1UdIwQYMBaAFCstgj5Ecm3HU/N7wxJluFo5 ++6XUMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +CwUAA4IBAQCWibvYuPLpoNcsUdHbE7SnBbEQnDfBxBZN8xeWHwwAPEB+8eHhmIdZ +xDtCN61xr5QR+KzlEYFwKyHMp9GN3OPU1RndJrzaXz2ddAZVkBIvnQZ4JvFd+sBC +QQgEvL8GcwZPxnad/TRylM4ON3Kh0X9vfyrmWEoHephiE1LcENaFqcYr9xg3DJNh +XSrigMGZJ7IOHkvgaoneICOcYI42ZHS0fnt1G+01VKJXm3ndi5NL25GnOmlvV6yV ++1vcmdQc6YS8K8vHmrH4lX9iPfsOak6WSzzsXdqgpvyxtGJggcFaDTtmbWCAkJj0 +B7DMeaVlLClGQaKZZ7aexEx9se+IyLn2 +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/private_key b/src/security/builtin_plugins/tests/validate_local_identity/etc/private_key new file mode 100644 index 0000000..06f57d1 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/private_key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAwqVYYrx/8ASMru+K70J3J0maisrKTegrw9aZlfcH7eTx4Vbf +Y1e/b4Erm+SwA6ERwIBXb/XbmIAa9ezm+rkayGOAdfAnKwo4UHAuII8fMto5fT3m +JvqmA96OOBWAawatEAp60ICrG/6l/WfjMP1VIsOucevFvO+ixB0EKBIE+JMUrmoM +AaFUZHjw+n2ACpk+F0t8fjtL/qxxEk3LChesjGnYKe4d3h9W/JCU80sfCVfWc6vv +psY6MaoWwVT+Zw83toYUiHgpAr0q8e3n5ICkuAEF2uf2eOBogLtU3111KnYnPa8c +A9HnZ2ozRJZ2Xu7I6JP9Mrqrx/toUqqTb2v86QIDAQABAoIBAC1q32DKkx+yMBFx +m32QiLUGG6VfBC2BixS7MkMnzRXZYgcuehl4FBc0kLRjfB6cqsO8LqrVN1QyMBhK +GutN3c38SbE7RChqzhEW2+yE+Mao3Nk4ZEecHLiyaYT0n25ZtHAVwep823BAzwJ+ +BykbM45VEpNKbG1VjSktjBa9faNyZiZAEJEjVyla+6R8N4kHV52LbZcLjvJv3IQ2 +iPYRrmMyI5C23qTni0vy7yJbAXBo3CqgSlwie9FARBWT7Puu7F4mF1O1c/SnTysw +Tm3e5FzgfHipQbnRVn0w4rDprPMKmPxMnvf/Wkw0zVgNadp1Tc1I6Yj525DEQ07i +2gIn/gECgYEA4jNnY1u2Eu7x3pAQF3dRO0x35boVtuq9iwQk7q+uaZaK4RJRr+0Y +T68S3bPnfer6SHvcxtST89Bvs/j/Ky4SOaX037UYjFh6T7OIzPl+MzO1yb+VOBT6 +D6FVGEJGp8ZAITU1OfJPeTYViUeEC8tHFGoKUCk50FbB6jOf1oKtv/ECgYEA3EnB +Y7kSbJJaUuj9ciFUL/pAno86Cim3VjegK1wKgEiyDb610bhoMErovPwfVJbtcttG +eKJNuwizkRcVbj+vpjDvqqaP5eMxLl6/Nd4haPMJYzGo88Z8NJpwFRNF2KEWjOpQ +2NEvoCeRtVulCJyka2Tpljzw8cOXkxhPOe2UhHkCgYBo3entj0QO7QXm56T+LAvV +0PK45xdQEO3EuCwjGAFk5C0IgUSrqeCeeIzniZMltj1IQ1wsNbtNynEu3530t8wt +O7oVyFBUKGSz9IjUdkpClJOPr6kPMfJoMqRPtdIpz+hFPPSrI6IikKdVWHloOlp+ +pVaYqTQrWT1XRY2xli3VEQKBgGySmZN6Cx+h/oywswIGdUT0VdcQhq2to+QFpJba +VX6m1cM6hMip2Ag9U3qZ1SNPBBdBBfm9HQybHE3dj713/C2wHuAAGhpXIM1W+20k +X1knuC/AsSH9aQhQOf/ZMOq1crTfZBuI9q0782/sjGmzMsKPySU4QhUWruVb7OiD +NVkZAoGAEvihW7G+8/iOE40vGHyBqUeopAAWLciTAUIEwM/Oi3BYfNWNTWF/FWNc +nMvCZPYigY8C1vO+1iT2Frtd3CIU+f01Q3fJNJoRLlEiKLNZUJRF48OKUqjKSmsi +w6pucFO40z05YW7utApj4L82rZnOS0pd1tUI1yexqvj0i4ThJfk= +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/private_key_1024 b/src/security/builtin_plugins/tests/validate_local_identity/etc/private_key_1024 new file mode 100644 index 0000000..709bcd6 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/private_key_1024 @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDS5w0h8L70hkreKchVbTzfz4CrBLY4iADNSqPx9uW7DxjeHyLb +KT2eRViY/xPuPXQmfRim01QMsZWKvFr6k9WMsJ6ItNtCyKS/beONqvXOddIu+4Ih +NzEGs5v4pTJAOzraoZcVmXnfMr9G/baMYfMG47JR5HaSHDI5esa2STHt4wIDAQAB +AoGAQi7LijkYU3fJCsql2Vj8X2eogwJphHf5eHLR296U3QyxyxKOR6Q7d+1fDjQN +txeF2YYsND3hBFK+ENlm23eE7Z1tpWtnLNJ9OH84ZkPnqTnEcWsRddT/x9vKOPMz +eK8QNetD3AP5qXsjpIpgep1diWYHCyhMTAFISzvdtC7pvFECQQD2zoqwRtF26lzg +QPR02Z+L80R2VhpeLoqMIplT1bmlrPlDr/eIwvtu1eQFyGSASG2EFs1rucdJl7qu +SrJ+eyv1AkEA2sIjy8+RCk1uH8kEwYaMJ3dccqnpcMCZ1b3GncKl+ICmDCYcpfd5 +rP5tX+GL3RVw370pUApJvrVTgOpAVHYjdwJAOYz8BhLdcS9BLQG4fy7n50h4pGd7 +io6ru/Wtb0EdIybskP4NaJSe8L9rhnWuCcPZ1b1DdWVCtURuQYoliRzLqQJBAJWO +ZrSfKpS1jRVT89lu6ADPXLfTrBH2yvVS8ifG/HshUOQ7ZhidUWVQ6GvFoj46u1lr +VIQxFGu6QeV/wQ09W08CQHGkrZgu/FpS2tNvYmKNDHOna+dW452N5N81u5sRP1A8 +x9pYC9xoOGE2E8v1ocMJDPoMe0yk1QSX9mjhhwYOy28= +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/private_key_not_matching b/src/security/builtin_plugins/tests/validate_local_identity/etc/private_key_not_matching new file mode 100644 index 0000000..735a9af --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/private_key_not_matching @@ -0,0 +1,48 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpgIBAAKCAQEAz90I7hABwJ27DQ0ypKEOlO8ZPoMKVMUAkTxl+48Icqo2SJxF +vKOxVd8XflJ2jor3YqzPgbuLVGolTafxzuGDYQVTNrSUgaCZMdX8O8UFxsBrQ+m9 +0pJeg+1I0OHrn8Y7VHuh5IVHNqmqwsw9TA5aLjp1i9Gc9pvGzbXEfGfnol64bvht +p3k8xMG8DZKKJNg8GUcYlLvwY+jcE8yMvQzM+gya6Y7w1JVgj4wQNjWULgqTJlUq +q1Wch9o7/tp1wzX3E4B8AeTCEsYEL9tUASp6V6/4Yf/jbGM2/nfaczj8lW0Gez6a +xHkMBh22vqLzZvvOFTX6U46KG/iWZAehKdPJrwIDAQABAoIBAQDGvQsAsoU6aJSj +Ee9NwD903nZAcoG6MvEr65eGQWdOWre0DNYQWmH/PGH2AVohR3Tn/1oXK/03JJWt +/dkQeEVoyfKZ52Xl2mseXv3fF61CLk9gi2dWoWOEt6ZbMOZbyOiJCfvrxhIkjWwa ++7PPuBk5AePJXwy4LJCTtiq61418i2Bbl6JamytgxsiVK9kZXdN6JqEVYmweMpmR +T1mzi7lssyttBIXwG8ajStUteIYLyi8d+UX4S08EyV0VGL0p5+F8xTY1jVX/t6Y0 +KbANJdjEab9mbndzbxprJlS08KBLgdnAO4w0nmINiaO2isXOLoV8SU3tTqHC3W7c +CCSKJdGBAoGBAP9vCSP1AaEjYa6sfEUgThpCo7PhRuOMEDb+4ldv9O+hzXv5I8td +gbDs1g3jyhb0yhW9uV9NsuKBtsmv1zYFswZDNbdr2S1VZPMpAx+SeLHQWy6HbU/t +oHoOO+l8erFVvR2uqit5rBDzN6/lh4SoQzYE9JDAnXJp9W0rKAdtBSLRAoGBANBT +AIErbPo4EuU13DaEa+EfoU4Abktyi+L8dpdoXMq6sHg3Mlhifr+ryoybrMMA3tmT +6ekBCSVThF0/+HAFRAJthnyBgUd0D710JDHro47Mg37CxU+V8JYqZJGHUSfqng7/ +pM7LjM99VhigquH4PoDH4YpL8vnIeEMNmny4iER/AoGBAJj8k+jpUXSFkHfh7vwo +AR9RUmLmRmL6/KsztbTQ5U6xBjV+XqXq90ZUU1A2Yk+lhXPIEkK2crGfJy9dFfTR +LQxPLNkSyxyPzMqmgaxjOc6mEDap/hqlJDx2UgPh/kpAI+inOFyZnyj3wx6ixqv5 +a2frR996vdJNDCW6d1sbPLxBAoGBAMO66IN0UJy76Izw0Olr+4v10vFdmENM6T+o +IqhZBq33P+yDN8sxJ5NgjhsT/Pruq3LT9XbVYUlvsbKHcx2U5PQ/AZejedqvokZH +g+ZfVjnJz1ZfG1GOOBBu3jSZZdfSKRVAfhFJ0A/229ihxEwxmFAY/MCaYTzsbInb +kyXRnz5zAoGBAIT9Fuk7zhfubYvkzIQ0kj/IxL3QohVRKcoGapDMSwNjTvxZdKxF +WXkhhJT095QznHP1fhp90fBKlOdsReDWfZXMYtZTqo2+ezK8qb6xMlm+LE09y+Na +f7pp1EPnIqyEX27B4aQ81M8tkCqbdlv3CdjFSusp6SsWTGTjr/5SAMDS +-----END RSA PRIVATE KEY----- + +-----BEGIN CERTIFICATE----- +MIIDNzCCAh8CCQDn8i4K9c4ErDANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJO +TDETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMRgwFgYDVQQDDA9DSEFNNTAwIHJvb3QgY2EwHhcNMTgwMjEyMTUw +NjUxWhcNMTkwNjI3MTUwNjUxWjBcMQswCQYDVQQGEwJOTDETMBEGA1UECAwKU29t +ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRUwEwYD +VQQDDAxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDRnnNnV3PZrbZwjxk+dkQcO3pK3wMvoDNAHPPiTfXRV2KjLHxsuK7wV+GPHmXo +97bot6vBxNQN7hfxoDLL+KBO9s3V+8OX6lOrF7hQ6+6/p9EgRoyNGo21eIzGwc2M +aJAKjImNMbM7FDTvhk3u+VTTJtlnKvJM1tgncbEZwRLri/2MEC5XS/O5FQT4AXPr +A6bRcGMqCVYtQ0ci6wd18PegA/rSmGSRf/TOd4jZXkxfHD+YOkHcxxz9sX4KnyOg +XZm8jDdBc7rxiDep8kIjL06VszJeoQrxjuf8cNZtbol/7ECS5aM2YOx7t0Dc/629 +V2Q5waRVBV5xVCJ0BzUh8rIFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGlkxYLr +ZI/XNjDC6RFfSFRoDc+Xpcg+GsJKKbw2+btZvAD8z7ofL01yGru9oi6u2Yy/ZDKT +liZ+gtsD8uVyRkS2skq7BvPzvoYErLmSqwlrcCbeX8uHiN7C76ll9PFtSjnwPD// +UaNyZM5dJB2eBh4/prclix+RR/FWQzkPqEVLwMcFBmnPZ0mvR2tncjpZq476Qyl9 +3jcmfms9qBfBPPjCdXqGEDgsTd2PpYRD2WDj/Ctl4rV7B2jnByullLUYIWGu0rYt +988waU5i8ie4t/TorBBLqQo/NO9jSXfEqcAnILPnv1QZanKzAAxSg7+FgFrsn359 +ihiEkx9zFUnPrdA= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/private_key_w_password b/src/security/builtin_plugins/tests/validate_local_identity/etc/private_key_w_password new file mode 100644 index 0000000..ba09dc0 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/private_key_w_password @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,0C9C38C5678AECD200E024A9A5BC717A + +wbXYsR78o4DIaQbKsB4cwEFge79GMKbcMgIWK+9k86dPk09WZkj7JCSJXIxPLYOG +tFZrw/z86cakEhf90a4Moa1cwByrcFB+bpWoEqsx/C4javWxXMENbmQ5x8gDpmzT +qqLI7xnd2mYj7HcfE7eXi+Nub5w1tBxN0CWaxpR54ZVvfcPE6Od4SHGughdUN4AK +OdVIq5YuzMhuTDJKy+kGOtjH8pBWvo8S12T2UQEuusx5WUbEJ6m+E80aN7M6gCA+ +XmNTt3PsV9PfZPL2Off/90gqTBdMhwn+sEVlqYG0TAnXZQEI8ZNtAGy77CFplqdT +SmI3x8Sza7lchEMFhRiayX9pMBPUlwckVPrCoMQ4b4WkHYoGLO7dNVAA8Osud46+ +6MZKHStjdzwKz9MzWa7lXhXV+0sX5bcAzQexuE+wO8QQ/t5uwDmQHol0JVdRX8NB +/Exk6aT7mWajFvukXVirpUGWnEK2W+O8/VBzVZ7z69EjZ09Pu4Y/+cbX12LGSwMb +WVtnZY6BsrV++vikQuL3ByTBDPRHio2H8hThh1Kv8n5VEBUrk7tLUp3Z15cbfC6s +LDHX6kB2OKmmdqLOOMo4lToZfnrVK/dzeXFbtNH1POpR4/e5Nk0SyZrWo+E/AqIv +nLQ3fhLCPOB5rjAhuM8iXOwqn8HHNlv9j8mlgCcgwK7focYVc/IXARLOfFOjOA/s +EqMRbb/eKsC930NHBZkhlqRJKCwA37AMvnOhN4R0VOq/40K+62IUK9E1643KyWs0 +vWk0rFY0OKorQXzI33lbBYZ5zHt8oxGNx3us+6jGP85iv8UEaO6FpgajEUn6Gzp/ +wyvr1C/B/Hfr6eTbt4C6Fi5fMfZgM6VEcJuaFZnoC9tWdhlNsY1pwtPghMM7yBwc +1Ye0TxdF36exJWu1gXVTse1Vdc9i4QWpT2fbPQtcIgdtNk01K+2defie384IOnQQ +O8/SRsrnLRLV3IDFh/VBJS1ZVm8Zmt10yGgRwtYHntMkIopoFRWcm9/Gh3iBFKKH +OTVXxgKOUYk4qXG61N8k0M+TIdoOHZIha3Myis1tQVmA/b/4FRKPYgdrFijhXNLM +wwMHQOS14xBF2KBgaak7dMUWhGrClw1hc3HmMXuM+OLvxy+f8MC3JP2U5AuCs472 +hc41KWxioqNMPVXZgVnHf3aEec+hBFceqYnlzG+E/Gagiufu8WMySaZgzXMRb5aV +x2OVcakSKrTC5EKbLDlZ6+1NRJht7wdSefh0o/Crc9LzcFqBL0Qp3WCvyY8gDVkQ +EGqoVYOE6Hz/NX5/17F1+5VuWT7nBWABHKFFriOoJ3VR9sZhp0HiMznZEF1AwVuZ +xHtDWQemfBywEQG23qbr+o7mQASh1zki8b4fP1HQmbHhaJarjwGdiVNIgcF7s7Qk +NYNcgsc1l0KuNHvredTnYwPhv3C08IBfjtd2H9u0A+AWl5RlR4GDfv2Jzbe/F8U+ +0gxj8D2XWHlkbHIXKVk6jxj64xyNE1xB0Sv7gsDWpkaK6aw/zdsyxqiji4mThcYE +cRSl4y9CGZREaiyD8dk/uiqKfQ26c1gfOUDYS2fKjH5NKh4J80wQj0GvS6nHiDH4 +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/trusted_ca_dir/identity_ca b/src/security/builtin_plugins/tests/validate_local_identity/etc/trusted_ca_dir/identity_ca new file mode 100644 index 0000000..7e2675c --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/trusted_ca_dir/identity_ca @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEmTCCA4GgAwIBAgIIZ5gEIUFhO5wwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE +BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp +ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDIx +MjE1MDUwMFoYDzIyMjIwMjIyMjIyMjAwWjBfMQswCQYDVQQGEwJOTDETMBEGA1UE +CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk +MRgwFgYDVQQDEw9DSEFNNTAwIHJvb3QgY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQC6Fa3TheL+UrdZCp9GhU/2WbneP2t/avUa3muwDttPxeI2XU9k +ZjBR95mAXme4SPXHk5+YDN319AqIje3oKhzky/ngvKH2GkoJKYxWnuDBfMEHdViz +2Q9/xso2ZvH50ukwWa0pfx2/EVV1wRxeQcRd/UVfq3KTJizG0M88mOYvGEAw3LFf +zef7k1aCuOofQmBvLukUudcYpMzfyHFp7lQqU4CcrrR5RtmfiUfrWfdGLea2iPDB +pJgN8ESOMwEHtOTEBDclYnH9L4t7CHQz+fXXS5IWFsDK9fCMQjnxDsDVeNrNzTYL +FaZrMg9S6IUQCEsQWsnq5weS8omOpVLUm9klAgMBAAGjggFVMIIBUTAMBgNVHRME +BTADAQH/MB0GA1UdDgQWBBQg2FZB/j8uWDVnJhjwXkX278znSTAfBgNVHSMEGDAW +gBQg2FZB/j8uWDVnJhjwXkX278znSTAPBgNVHQ8BAf8EBQMDB/+AMIHvBgNVHSUB +Af8EgeQwgeEGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwME +BggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK +KwYBBAGCNwoDAwYKKwYBBAGCNwoDBAYJYIZIAYb4QgQBBgsrBgEEAYI3CgMEAQYI +KwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUIAgIGCisGAQQBgjcU +AgIGCCsGAQUFBwMJBggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZI +hvcNAQELBQADggEBAKHmwejWRwGE1wf1k2rG8SNRV/neGsZ6Qfqf6co3TpR/Wi1s +iZDvSeT/rbqNBS7z34xnG88NIUwu00y78e8Mfon31ZZbK4Uo7fla9/D3ukdJqPQC +LKdbKJjR2kH+KCukY/1rghjJ8/X+t2egBit0LCOdsFCl07Sfksb9kpGUIZSFcYYm +geqhjhoNwxazzHiw+QWHC5HG9248JIizBmy1aymNWuMnPudhjHAnPcsIlqMVNq3t +Rv9ap7S8JeCxHVRPJvJeCwXWvW3dW/v3xH52Yn/fqRblN1w9Fxz5NhopKx0gj/Jd +sw2N4Fk4gaOWEolFpa0bwNw8nAx7moehZpowzfw= +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/trusted_ca_dir/root_CA_RSA.crt b/src/security/builtin_plugins/tests/validate_local_identity/etc/trusted_ca_dir/root_CA_RSA.crt new file mode 100644 index 0000000..61346df --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/trusted_ca_dir/root_CA_RSA.crt @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEtjCCA56gAwIBAgIBATANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50 +aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu +Y29tMB4XDTE4MDYxMTAwMDAwMFoXDTI3MDYxMDIzNTk1OVowcjELMAkGA1UEBhMC +TkwxCzAJBgNVBAgTAk9WMRMwEQYDVQQKEwpBRExpbmsgSVNUMRkwFwYDVQQDExBJ +ZGVudGl0eSBDQSBUZXN0MSYwJAYJKoZIhvcNAQkBFhdpbmZvQGlzdC5hZGxpbmt0 +ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANRf3XKmM6O+ +WoYPNpOAdkGKKZHLJ8ZuPxVVBMX6oJAlcOmkhLzfkHSA+gl/OWaMOXIEtN512gyL +YszBf1RImwVzRjJFwIxzGzVQ68jYNj+qBbsOt+IG+hs3wgVCLFkCh+J7hXUgvk8A +eRM/SRrI42dQfcgKUAMNi4/iX6Vs+FV9pHB63L4PiLA9hfUE25sH6EsIC7icvGDJ +6cGG94glVSHDI1NtXfsNHY+NGY/jYKtQZklqU3lew5I60aJIsea+Wk6PJiz4hyXv +XVVmrcNeG1g4OEFgiSXZC2XknDw8t9+ELprGNvuJvTFxwPMAgLeF4IhEQC9dQY2W +BRwUxtZBzukCAwEAAaOCAVUwggFRMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFER4 +R6N3MQ1Wl7gn+R8wwHloDCVZMB8GA1UdIwQYMBaAFER4R6N3MQ1Wl7gn+R8wwHlo +DCVZMA8GA1UdDwEB/wQFAwMH/4Awge8GA1UdJQEB/wSB5DCB4QYIKwYBBQUHAwEG +CCsGAQUFBwMCBggrBgEFBQcDAwYIKwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3 +AgEVBgorBgEEAYI3AgEWBgorBgEEAYI3CgMBBgorBgEEAYI3CgMDBgorBgEEAYI3 +CgMEBglghkgBhvhCBAEGCysGAQQBgjcKAwQBBggrBgEFBQcDBQYIKwYBBQUHAwYG +CCsGAQUFBwMHBggrBgEFBQgCAgYKKwYBBAGCNxQCAgYIKwYBBQUHAwkGCCsGAQUF +BwMNBggrBgEFBQcDDgYHKwYBBQIDBTANBgkqhkiG9w0BAQsFAAOCAQEAwXuEWDG3 +aAyL+DsGr0B4YMLjHtx6FjzkJOpTtXQhkrtSMpD3Xytl7Wfz8lyWuTnbrk8F4gWO +IkJR/NdMGW27SmeYU0z7QAGRDwtHX6kqqizQbCwf4F6P/2QftcLp1VrlsIlb0gyx +gLjpGmn5TT7gj+ahW0iIRglOwhzCvkNu6agYpdGwVirSyLShy/Hq303DZSbVuktz +5/PmZKpufnoGqURNnJqbV4TQipE0FiDmp2o+gVgJ+DVRhiCdfk68Xp7+TlmxCDfZ +C3qb18qrwAZ4AL3T9/RlzfkXh4ME9V6wqa5Y6j7Vwx5Ef2OHL+mnMnoNSXDLRh6j +45ky66su5dROpA== +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/trusted_ca_dir_not_matching/not_matching_trusted_ca.crt b/src/security/builtin_plugins/tests/validate_local_identity/etc/trusted_ca_dir_not_matching/not_matching_trusted_ca.crt new file mode 100644 index 0000000..35506b8 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/trusted_ca_dir_not_matching/not_matching_trusted_ca.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIENDCCAxygAwIBAgIBAjANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJOTDEL +MAkGA1UECBMCT1YxEzARBgNVBAoTCkFETGluayBJU1QxGTAXBgNVBAMTEElkZW50 +aXR5IENBIFRlc3QxJjAkBgkqhkiG9w0BCQEWF2luZm9AaXN0LmFkbGlua3RlY2gu +Y29tMB4XDTE4MDYxMzAwMDAwMFoXDTI3MDYxMDIzNTk1OVowfTELMAkGA1UEBhMC +TkwxCzAJBgNVBAgTAk9WMRMwEQYDVQQKEwpBRExpbmsgSVNUMSQwIgYDVQQDExtJ +ZGVudGl0eSBDQSBUZXN0IFdpdGggQ2hhaW4xJjAkBgkqhkiG9w0BCQEWF2luZm9A +aXN0LmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA1r8Q0V8ZVeBs8tPMF0N+JlBynl1Zn/89vwSsU4m7y6ixUcW/y3r12CMeA0cH +g6yOaOdHsZ8pRlPRwy9YmeOwLsMOUHAURP2uPiTjSf3pttUIf0jv602GyirNzoS7 +7mHiyTtV80ZMzZlLIJ3gaJJlG4DjitFuFcjv8sOmviFjkn1kOjkAz1nKgsCiHvvg +fcJlYPrtLfle9SzvZ3MTq4ob+/EFu9nt5bYYs7p7Br1TGWctUw98l2mSn/FhfDBw +9bb7ZhcKB7W6PGy2Os5AnkdTJKHoOQT+RmnHzPBhab0BoKuy8IhfW2GyqC8rL5Tm +/UVLUvnx4Zzqz//3IyA2FTb1HQIDAQABo4HJMIHGMAwGA1UdEwQFMAMBAf8wHQYD +VR0OBBYEFE1VQk0XOEk9F5hPhBLHp0rncJcJMB8GA1UdIwQYMBaAFER4R6N3MQ1W +l7gn+R8wwHloDCVZMA8GA1UdDwEB/wQFAwMH/4AwZQYDVR0lAQH/BFswWQYIKwYB +BQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYIKwYBBQUHAwQGCCsGAQUFBwMIBggr +BgEFBQcDCQYIKwYBBQUHAw0GCCsGAQUFBwMOBgcrBgEFAgMFMA0GCSqGSIb3DQEB +CwUAA4IBAQCbl7ed4p66G6WquxO7ceZFvYKn3kDErjCfXHcqHxBnA2xTpoZCGj95 +Qpirqo6N4UcLX5sn3CmgyVk0dYvlti/53FJgZ9XQDNxBuEYWPkY7vO+Uo0WdYpGz +ZDNIUQpiPMA7bHvwKldTIs77xxtnw9kbBU2k0xQyb2tdZNfD5YqSI1MeUtpEpNFW +sbC8+mQ3clzWpjF8eHH1fFSAmlJ+z1Uqmtt2FK0vRz+MQcpydwvpMnfqGdcwhGPQ +X4HZreLObjBA8KUEkUB3+rZXuELBgkk/c8/jRZl7QF5jJDLQCCLg7KoYBKN2GuTt +/dzeSnP7VZm/nTL8wpCvKgSOwOGgklf2 +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/etc/unrelated_identity_ca b/src/security/builtin_plugins/tests/validate_local_identity/etc/unrelated_identity_ca new file mode 100644 index 0000000..52cf047 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/etc/unrelated_identity_ca @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDpDCCAoygAwIBAgIJALE5lRKfYHAaMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV +BAYTAk5MMRMwEQYDVQQIDApPdmVyaWpzc2VsMRAwDgYDVQQHDAdIZW5nZWxvMQ8w +DQYDVQQKDAZBRExJTksxGDAWBgNVBAMMD0NIQU01MDAgUm9vdCBDQTAeFw0xODAy +MDkxNjIwNDNaFw0zODAyMDQxNjIwNDNaMF8xCzAJBgNVBAYTAk5MMRMwEQYDVQQI +DApPdmVyaWpzc2VsMRAwDgYDVQQHDAdIZW5nZWxvMQ8wDQYDVQQKDAZBRExJTksx +GDAWBgNVBAMMD0NIQU01MDAgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAN9/NbpJDHQYHh3cEByRxnHffxEe9Sapn08Ty5xYO8LDJ4V7vU32 +/7291fITiHaovOoCRHAbKTaTtqJO56aGY45HON6KIqxljLQJJVGW/Nf2PNSHmFix +6D6bsoSOTPyKYqBNT6lB7NMn4QBTcsiE61El8p9WLQZHoYQJK5Psf7wkBqGBz8he +bcDWXFn7kIgnsaLrh77w2wi/y0MqpPwyeRInoZfYknzVNdxCPgq7csBYDoMgOgkV +G60ECXojHKz1HI4n0V8L8lZluSSVRNR0xvPFgBqO7b+Re7xb6iO9TNsFeoiMMNyp +EwM99CqPO0RRrAPiC7IDgcNGjxhne9EJFGsCAwEAAaNjMGEwHQYDVR0OBBYEFCst +gj5Ecm3HU/N7wxJluFo5+6XUMB8GA1UdIwQYMBaAFCstgj5Ecm3HU/N7wxJluFo5 ++6XUMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +CwUAA4IBAQCWibvYuPLpoNcsUdHbE7SnBbEQnDfBxBZN8xeWHwwAPEB+8eHhmIdZ +xDtCN61xr5QR+KzlEYFwKyHMp9GN3OPU1RndJrzaXz2ddAZVkBIvnQZ4JvFd+sBC +QQgEvL8GcwZPxnad/TRylM4ON3Kh0X9vfyrmWEoHephiE1LcENaFqcYr9xg3DJNh +XSrigMGZJ7IOHkvgaoneICOcYI42ZHS0fnt1G+01VKJXm3ndi5NL25GnOmlvV6yV ++1vcmdQc6YS8K8vHmrH4lX9iPfsOak6WSzzsXdqgpvyxtGJggcFaDTtmbWCAkJj0 +B7DMeaVlLClGQaKZZ7aexEx9se+IyLn2 +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_identity/src/ca.crt b/src/security/builtin_plugins/tests/validate_local_identity/src/ca.crt new file mode 100644 index 0000000..426d312 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/src/ca.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkTCCAnmgAwIBAgIJAJvGJOEKNct1MA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV +BAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxGDAWBgNVBAMMD0NIQU01MDAgcm9vdCBjYTAeFw0xODAy +MTIxNTA1MDVaFw0yMDEyMDIxNTA1MDVaMF8xCzAJBgNVBAYTAk5MMRMwEQYDVQQI +DApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQx +GDAWBgNVBAMMD0NIQU01MDAgcm9vdCBjYTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAM/dCO4QAcCduw0NMqShDpTvGT6DClTFAJE8ZfuPCHKqNkicRbyj +sVXfF35Sdo6K92Ksz4G7i1RqJU2n8c7hg2EFUza0lIGgmTHV/DvFBcbAa0PpvdKS +XoPtSNDh65/GO1R7oeSFRzapqsLMPUwOWi46dYvRnPabxs21xHxn56JeuG74bad5 +PMTBvA2SiiTYPBlHGJS78GPo3BPMjL0MzPoMmumO8NSVYI+MEDY1lC4KkyZVKqtV +nIfaO/7adcM19xOAfAHkwhLGBC/bVAEqelev+GH/42xjNv532nM4/JVtBns+msR5 +DAYdtr6i82b7zhU1+lOOihv4lmQHoSnTya8CAwEAAaNQME4wHQYDVR0OBBYEFFYr +0CpiwxgFcZnW6IQEhxGv/vwiMB8GA1UdIwQYMBaAFFYr0CpiwxgFcZnW6IQEhxGv +/vwiMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKbBt0ht72fdtxwm +Kr0pOsKyDW0Rd5Ca5aDK4qAhDL0AD5+O6ShGYCnFNDGk3J5Yzawp8VoKrhDZZyUt +z2b0jNucVapAvPMA4066QxeIfvFmWcS73l7vjjeUoKWmNNGWprTg3RLsacTorKuY +ZRL7wsThfrhvg4B/OOIWKp5MEwIrUfnQzUca8getF2eyTt6QcMtE29AW5+01QTzj +fxZgzkmJFYBE2K/TLMDBDd+bz/8XnmPrJ01VUntXiXenTGTcIbJerB6GYQojjvhy +ZrOeuHTON1ndFiQkpeZA67ByZjkKVoJG3I8fwBjzcLE7u/QAQptVPjJXXcSpL7fA +a1tOvqw= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/src/security/builtin_plugins/tests/validate_local_identity/src/id.crt b/src/security/builtin_plugins/tests/validate_local_identity/src/id.crt new file mode 100644 index 0000000..7c03aae --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/src/id.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDNzCCAh8CCQDn8i4K9c4ErDANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJO +TDETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMRgwFgYDVQQDDA9DSEFNNTAwIHJvb3QgY2EwHhcNMTgwMjEyMTUw +NjUxWhcNMTkwNjI3MTUwNjUxWjBcMQswCQYDVQQGEwJOTDETMBEGA1UECAwKU29t +ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRUwEwYD +VQQDDAxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDRnnNnV3PZrbZwjxk+dkQcO3pK3wMvoDNAHPPiTfXRV2KjLHxsuK7wV+GPHmXo +97bot6vBxNQN7hfxoDLL+KBO9s3V+8OX6lOrF7hQ6+6/p9EgRoyNGo21eIzGwc2M +aJAKjImNMbM7FDTvhk3u+VTTJtlnKvJM1tgncbEZwRLri/2MEC5XS/O5FQT4AXPr +A6bRcGMqCVYtQ0ci6wd18PegA/rSmGSRf/TOd4jZXkxfHD+YOkHcxxz9sX4KnyOg +XZm8jDdBc7rxiDep8kIjL06VszJeoQrxjuf8cNZtbol/7ECS5aM2YOx7t0Dc/629 +V2Q5waRVBV5xVCJ0BzUh8rIFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGlkxYLr +ZI/XNjDC6RFfSFRoDc+Xpcg+GsJKKbw2+btZvAD8z7ofL01yGru9oi6u2Yy/ZDKT +liZ+gtsD8uVyRkS2skq7BvPzvoYErLmSqwlrcCbeX8uHiN7C76ll9PFtSjnwPD// +UaNyZM5dJB2eBh4/prclix+RR/FWQzkPqEVLwMcFBmnPZ0mvR2tncjpZq476Qyl9 +3jcmfms9qBfBPPjCdXqGEDgsTd2PpYRD2WDj/Ctl4rV7B2jnByullLUYIWGu0rYt +988waU5i8ie4t/TorBBLqQo/NO9jSXfEqcAnILPnv1QZanKzAAxSg7+FgFrsn359 +ihiEkx9zFUnPrdA= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/src/security/builtin_plugins/tests/validate_local_identity/src/priv.pem b/src/security/builtin_plugins/tests/validate_local_identity/src/priv.pem new file mode 100644 index 0000000..b560f66 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/src/priv.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEA0Z5zZ1dz2a22cI8ZPnZEHDt6St8DL6AzQBzz4k310Vdioyx8 +bLiu8Ffhjx5l6Pe26LerwcTUDe4X8aAyy/igTvbN1fvDl+pTqxe4UOvuv6fRIEaM +jRqNtXiMxsHNjGiQCoyJjTGzOxQ074ZN7vlU0ybZZyryTNbYJ3GxGcES64v9jBAu +V0vzuRUE+AFz6wOm0XBjKglWLUNHIusHdfD3oAP60phkkX/0zneI2V5MXxw/mDpB +3Mcc/bF+Cp8joF2ZvIw3QXO68Yg3qfJCIy9OlbMyXqEK8Y7n/HDWbW6Jf+xAkuWj +NmDse7dA3P+tvVdkOcGkVQVecVQidAc1IfKyBQIDAQABAoIBAEddUpzUQTTS11Hq +5gVF7lpORYxH8KW+PLSPJtjdAduLjKFQ++tn1OcuhDRdfQSbkUIZhfgqMqerb6tr +ht+6fZlknR9E34pQ1LtjD/U83cOSNrhuTFudtrEZoZPpVzl+P8vXnNzdFs/+SSdi +6hV5/U8F4u4kyOkwG9cR9eF2wiI+oQ/RBKCXUo3OVs9K27A/OkKsb7coL7yBsgBj +lzorS9a/DyHT2eiMKjwCZFyG4A66EkLi6t9JLJ8oTkI2WskXYeVEAbEXE57RWm44 +2OgTI/Yc2yrtXq93KD17FN1m77dqp7EPAhjGnRHNq7+0Ykr1EO1nbDfqHG4gS+4o +lfP8iwECgYEA58da0R34l93yQnK0mAtoobwvsOjADnBVhBg9L4s2eDs8liUjf0zt +7hcMdUJaa7iMuNf3qGtnZtRURc3kSOE429Or7fCAYUr/AaA7+2ekPG1vjMb50tVv +se5rwb1hvgMYe2L5ktJJAg+RcmqpY+ncJ+hP/vWwZRxUKvXba50qqEkCgYEA54ZE +mJfSueGM/63xlhP71CM4OWtTqkQGp2OmgTOsBI5q/GUXr8vMR8sCEMHAc6HyXzmL +x/RnAoa/vTX58rXBk0QjfO9esIHa452697EIaJu5w8skCLDv2e/f+Jg7o/IDyUZs +5lqhiEuH9Qc3sx2nhnSYXMZWqwh8OchI7dCSE90CgYEAzrJ1JhpxUJYI7wM2VIWQ +GPQnH8BhTj8VtEidgCHJQK2rGUcjgepMIVECtiunUXtyW4GWBedKfmSKhvnXRLs9 +pqT9JaOeCaYFBiEsfMZvq8f4e/YSYtge1PIHvO40FWzTT23zneDUZPcXQY8nYsfy +otBFTt0yIumBkhJRTIYLvakCgYA+CcttvBj6OAcJJ/n5RgeP05QoRqsXj7zcs6YV +LtxkKClg0lHjiE+H2U0HYnOISJfijk/3V3UWxzavo7wDHlLtfC+qNZYA4/rcTRKh +dm2TYk8HuPJB5e+PTWiNe3VXu+zpzRY3L4fjNqIKtVFmjIasT6fYDEmC8PYgoZtx +JhdOfQKBgCD/bDkc+VI6lwQtoQQKiSfQjKGe+6Cw9K/obzWO0uJwBvZrGLXF8tTc +MOPIv9OILt7DYxpMXAiHv8HtzH5CFVrZ/nj63SRoka/j2yvUdBDrGhyIbsc4pDu+ +lCFa0ZiT/u5vRAiOkM6GuStH4HxnW9LtwBtiYXtfU7IPExJiAlsq +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/src/security/builtin_plugins/tests/validate_local_identity/src/remote b/src/security/builtin_plugins/tests/validate_local_identity/src/remote new file mode 100644 index 0000000..195709a --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/src/remote @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDMzCCAhsCCQDn8i4K9c4ErzANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJO +TDETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMRgwFgYDVQQDDA9DSEFNNTAwIHJvb3QgY2EwHhcNMTgwMzIzMTIw +MTE5WhcNMjMxMDMxMTIwMTE5WjBYMQswCQYDVQQGEwJOTDETMBEGA1UECAwKU29t +ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMREwDwYD +VQQDDAhDSEFNLTU3NzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMcc +IMlRp2EnOC/UIIOF2gm+wtsikv5CscDuyq9DA2QgS5TTKqivDAdOSUIcbVn8qb6/ +77viarmRXml3VHJdhR2abtY6xYKYF2SCFiyoNk6ITq+YBrCfmMh/bCYTD6c5vnl4 +SKomIArU1g1YAxHxHqZRX1oonldUdP4lqq+Qt6fllYFhHNAl5JjrrCuPpXmAW3pC +z4b3HWP/6vnbOFFMYkwGprVoAljcnAG7C7zSjW2M3RN4xA/z6Lps8qrPFB2iAXaP +ZnST1rkqctf2IDWVwloG0uJnqiigcIz6+hvf5VMU0ax+CrYqFGav/uwvPCiHcUkF +3a/O3z+4xGHaBagfHukCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAXZlNPz6raCBp +F+iyNWTGy27OyM/TZNE9QTPI28TQEmLfqCrRfq+uHhBQ3U9TgS3xX/f5b+BPHuaD +N6vl/yECAQa+0r33EFdoe8rGa0Mr5VvADcqPmk/sp9K62fRcP4aCgliDi8g9G8q1 +XNgO/EA9HhFlFKPzLPFMhq7qqPOQWO/EddoxA/qCMGZtN+TAxqLKVB0lipJoSa0x +XqtYvNWiaShPceSk4SAjAdpdhvxOpA/25uvFEISdt9zoqbs4eLUbi/9RFYaL8U4r +E+FygZMi31N6PC/Q7/tJ4DG20K/V30Y1+ogvSfdJpWk9L/CJj0VrzqJTVaKBIFVV +6PtqHPZiKA== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/src/security/builtin_plugins/tests/validate_local_identity/src/unrelated_identity_ca b/src/security/builtin_plugins/tests/validate_local_identity/src/unrelated_identity_ca new file mode 100644 index 0000000..f2bec0c --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/src/unrelated_identity_ca @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDpDCCAoygAwIBAgIJALE5lRKfYHAaMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV +BAYTAk5MMRMwEQYDVQQIDApPdmVyaWpzc2VsMRAwDgYDVQQHDAdIZW5nZWxvMQ8w +DQYDVQQKDAZBRExJTksxGDAWBgNVBAMMD0NIQU01MDAgUm9vdCBDQTAeFw0xODAy +MDkxNjIwNDNaFw0zODAyMDQxNjIwNDNaMF8xCzAJBgNVBAYTAk5MMRMwEQYDVQQI +DApPdmVyaWpzc2VsMRAwDgYDVQQHDAdIZW5nZWxvMQ8wDQYDVQQKDAZBRExJTksx +GDAWBgNVBAMMD0NIQU01MDAgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAN9/NbpJDHQYHh3cEByRxnHffxEe9Sapn08Ty5xYO8LDJ4V7vU32 +/7291fITiHaovOoCRHAbKTaTtqJO56aGY45HON6KIqxljLQJJVGW/Nf2PNSHmFix +6D6bsoSOTPyKYqBNT6lB7NMn4QBTcsiE61El8p9WLQZHoYQJK5Psf7wkBqGBz8he +bcDWXFn7kIgnsaLrh77w2wi/y0MqpPwyeRInoZfYknzVNdxCPgq7csBYDoMgOgkV +G60ECXojHKz1HI4n0V8L8lZluSSVRNR0xvPFgBqO7b+Re7xb6iO9TNsFeoiMMNyp +EwM99CqPO0RRrAPiC7IDgcNGjxhne9EJFGsCAwEAAaNjMGEwHQYDVR0OBBYEFCst +gj5Ecm3HU/N7wxJluFo5+6XUMB8GA1UdIwQYMBaAFCstgj5Ecm3HU/N7wxJluFo5 ++6XUMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +CwUAA4IBAQCWibvYuPLpoNcsUdHbE7SnBbEQnDfBxBZN8xeWHwwAPEB+8eHhmIdZ +xDtCN61xr5QR+KzlEYFwKyHMp9GN3OPU1RndJrzaXz2ddAZVkBIvnQZ4JvFd+sBC +QQgEvL8GcwZPxnad/TRylM4ON3Kh0X9vfyrmWEoHephiE1LcENaFqcYr9xg3DJNh +XSrigMGZJ7IOHkvgaoneICOcYI42ZHS0fnt1G+01VKJXm3ndi5NL25GnOmlvV6yV ++1vcmdQc6YS8K8vHmrH4lX9iPfsOak6WSzzsXdqgpvyxtGJggcFaDTtmbWCAkJj0 +B7DMeaVlLClGQaKZZ7aexEx9se+IyLn2 +-----END CERTIFICATE----- \ No newline at end of file diff --git a/src/security/builtin_plugins/tests/validate_local_identity/src/validate_local_identity_utests.c b/src/security/builtin_plugins/tests/validate_local_identity/src/validate_local_identity_utests.c new file mode 100644 index 0000000..2d27668 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_identity/src/validate_local_identity_utests.c @@ -0,0 +1,2110 @@ +/** @file qos_utests.c + * @brief Unit tests for qos APIs + * + */ +/* CUnit includes. */ +#include +#include +#include "dds/ddsrt/environ.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "assert.h" + + +/* Test helper includes. */ +#include "common/src/loader.h" + + +#include "dds/security/dds_security_api.h" +#include "dds/security/openssl_support.h" + +#include +#include +#include + +static const char * PROPERTY_IDENTITY_CA = "dds.sec.auth.identity_ca"; +static const char * PROPERTY_PRIVATE_KEY = "dds.sec.auth.private_key"; +static const char * PROPERTY_PASSWORD = "dds.sec.auth.password"; +static const char * PROPERTY_IDENTITY_CERT = "dds.sec.auth.identity_certificate"; +static const char * PROPERTY_TRUSTED_CA_DIR = "dds.sec.auth.trusted_ca_dir"; + +static const char *identity_certificate_filename = "identity_certificate"; +static const char *identity_certificate = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEQTCCAymgAwIBAgIINpuaAAnrQZIwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE3MDIy\n" + "MjIyMjIwMFoYDzIyMjIwMjIyMjIyMjAwWjBcMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRUwEwYDVQQDEwxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n" + "ggEKAoIBAQDCpVhivH/wBIyu74rvQncnSZqKyspN6CvD1pmV9wft5PHhVt9jV79v\n" + "gSub5LADoRHAgFdv9duYgBr17Ob6uRrIY4B18CcrCjhQcC4gjx8y2jl9PeYm+qYD\n" + "3o44FYBrBq0QCnrQgKsb/qX9Z+Mw/VUiw65x68W876LEHQQoEgT4kxSuagwBoVRk\n" + "ePD6fYAKmT4XS3x+O0v+rHESTcsKF6yMadgp7h3eH1b8kJTzSx8JV9Zzq++mxjox\n" + "qhbBVP5nDze2hhSIeCkCvSrx7efkgKS4AQXa5/Z44GiAu1TfXXUqdic9rxwD0edn\n" + "ajNElnZe7sjok/0yuqvH+2hSqpNva/zpAgMBAAGjggEAMIH9MAwGA1UdDwQFAwMH\n" + "/4AwgewGA1UdJQSB5DCB4QYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYI\n" + "KwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3AgEVBgorBgEEAYI3AgEWBgorBgEE\n" + "AYI3CgMBBgorBgEEAYI3CgMDBgorBgEEAYI3CgMEBglghkgBhvhCBAEGCysGAQQB\n" + "gjcKAwQBBggrBgEFBQcDBQYIKwYBBQUHAwYGCCsGAQUFBwMHBggrBgEFBQgCAgYK\n" + "KwYBBAGCNxQCAgYIKwYBBQUHAwkGCCsGAQUFBwMNBggrBgEFBQcDDgYHKwYBBQID\n" + "BTANBgkqhkiG9w0BAQsFAAOCAQEAawdHy0Xw7nTK2ltp91Ion6fJ7hqYuj///zr7\n" + "Adt6uonpDh/xl3esuwcFimIJrJrHujnGkL0nLddRCikmnzuBMNDWS6yq0/Ckl/YG\n" + "yjNr44dlX24wo+MVAgkj3/8CyWDZ3a8kBg9QT3bs2SqbjmhTrXN1DRyf9S5vJysE\n" + "I7V1gTN66BeKL64hOrAlRVrEu8Ds6TWL6Q/YH+61ViZkoLTeSaPjH4nknaFr4C35\n" + "iji0JhkyfRHRRVPHFnaj25AkxOrSV64qVKoTMjDl5fji5iMGtjm6iJ7q05ml/qDl\n" + "nLotHXemZNvYhbwUmRzbt4Dls9EMH4VRbP85I94nM5TAvtHVNA==\n" + "-----END CERTIFICATE-----\n"; + +static const char *identity_ca_filename = "identity_ca"; +static const char *identity_ca = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEmTCCA4GgAwIBAgIIZ5gEIUFhO5wwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDIx\n" + "MjE1MDUwMFoYDzIyMjIwMjIyMjIyMjAwWjBfMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRgwFgYDVQQDEw9DSEFNNTAwIHJvb3QgY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" + "DwAwggEKAoIBAQC6Fa3TheL+UrdZCp9GhU/2WbneP2t/avUa3muwDttPxeI2XU9k\n" + "ZjBR95mAXme4SPXHk5+YDN319AqIje3oKhzky/ngvKH2GkoJKYxWnuDBfMEHdViz\n" + "2Q9/xso2ZvH50ukwWa0pfx2/EVV1wRxeQcRd/UVfq3KTJizG0M88mOYvGEAw3LFf\n" + "zef7k1aCuOofQmBvLukUudcYpMzfyHFp7lQqU4CcrrR5RtmfiUfrWfdGLea2iPDB\n" + "pJgN8ESOMwEHtOTEBDclYnH9L4t7CHQz+fXXS5IWFsDK9fCMQjnxDsDVeNrNzTYL\n" + "FaZrMg9S6IUQCEsQWsnq5weS8omOpVLUm9klAgMBAAGjggFVMIIBUTAMBgNVHRME\n" + "BTADAQH/MB0GA1UdDgQWBBQg2FZB/j8uWDVnJhjwXkX278znSTAfBgNVHSMEGDAW\n" + "gBQg2FZB/j8uWDVnJhjwXkX278znSTAPBgNVHQ8BAf8EBQMDB/+AMIHvBgNVHSUB\n" + "Af8EgeQwgeEGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwME\n" + "BggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK\n" + "KwYBBAGCNwoDAwYKKwYBBAGCNwoDBAYJYIZIAYb4QgQBBgsrBgEEAYI3CgMEAQYI\n" + "KwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUIAgIGCisGAQQBgjcU\n" + "AgIGCCsGAQUFBwMJBggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZI\n" + "hvcNAQELBQADggEBAKHmwejWRwGE1wf1k2rG8SNRV/neGsZ6Qfqf6co3TpR/Wi1s\n" + "iZDvSeT/rbqNBS7z34xnG88NIUwu00y78e8Mfon31ZZbK4Uo7fla9/D3ukdJqPQC\n" + "LKdbKJjR2kH+KCukY/1rghjJ8/X+t2egBit0LCOdsFCl07Sfksb9kpGUIZSFcYYm\n" + "geqhjhoNwxazzHiw+QWHC5HG9248JIizBmy1aymNWuMnPudhjHAnPcsIlqMVNq3t\n" + "Rv9ap7S8JeCxHVRPJvJeCwXWvW3dW/v3xH52Yn/fqRblN1w9Fxz5NhopKx0gj/Jd\n" + "sw2N4Fk4gaOWEolFpa0bwNw8nAx7moehZpowzfw=\n" + "-----END CERTIFICATE-----\n"; + +static const char *private_key_filename = "private_key"; +static const char *private_key_pem = + "data:,-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEogIBAAKCAQEAwqVYYrx/8ASMru+K70J3J0maisrKTegrw9aZlfcH7eTx4Vbf\n" + "Y1e/b4Erm+SwA6ERwIBXb/XbmIAa9ezm+rkayGOAdfAnKwo4UHAuII8fMto5fT3m\n" + "JvqmA96OOBWAawatEAp60ICrG/6l/WfjMP1VIsOucevFvO+ixB0EKBIE+JMUrmoM\n" + "AaFUZHjw+n2ACpk+F0t8fjtL/qxxEk3LChesjGnYKe4d3h9W/JCU80sfCVfWc6vv\n" + "psY6MaoWwVT+Zw83toYUiHgpAr0q8e3n5ICkuAEF2uf2eOBogLtU3111KnYnPa8c\n" + "A9HnZ2ozRJZ2Xu7I6JP9Mrqrx/toUqqTb2v86QIDAQABAoIBAC1q32DKkx+yMBFx\n" + "m32QiLUGG6VfBC2BixS7MkMnzRXZYgcuehl4FBc0kLRjfB6cqsO8LqrVN1QyMBhK\n" + "GutN3c38SbE7RChqzhEW2+yE+Mao3Nk4ZEecHLiyaYT0n25ZtHAVwep823BAzwJ+\n" + "BykbM45VEpNKbG1VjSktjBa9faNyZiZAEJEjVyla+6R8N4kHV52LbZcLjvJv3IQ2\n" + "iPYRrmMyI5C23qTni0vy7yJbAXBo3CqgSlwie9FARBWT7Puu7F4mF1O1c/SnTysw\n" + "Tm3e5FzgfHipQbnRVn0w4rDprPMKmPxMnvf/Wkw0zVgNadp1Tc1I6Yj525DEQ07i\n" + "2gIn/gECgYEA4jNnY1u2Eu7x3pAQF3dRO0x35boVtuq9iwQk7q+uaZaK4RJRr+0Y\n" + "T68S3bPnfer6SHvcxtST89Bvs/j/Ky4SOaX037UYjFh6T7OIzPl+MzO1yb+VOBT6\n" + "D6FVGEJGp8ZAITU1OfJPeTYViUeEC8tHFGoKUCk50FbB6jOf1oKtv/ECgYEA3EnB\n" + "Y7kSbJJaUuj9ciFUL/pAno86Cim3VjegK1wKgEiyDb610bhoMErovPwfVJbtcttG\n" + "eKJNuwizkRcVbj+vpjDvqqaP5eMxLl6/Nd4haPMJYzGo88Z8NJpwFRNF2KEWjOpQ\n" + "2NEvoCeRtVulCJyka2Tpljzw8cOXkxhPOe2UhHkCgYBo3entj0QO7QXm56T+LAvV\n" + "0PK45xdQEO3EuCwjGAFk5C0IgUSrqeCeeIzniZMltj1IQ1wsNbtNynEu3530t8wt\n" + "O7oVyFBUKGSz9IjUdkpClJOPr6kPMfJoMqRPtdIpz+hFPPSrI6IikKdVWHloOlp+\n" + "pVaYqTQrWT1XRY2xli3VEQKBgGySmZN6Cx+h/oywswIGdUT0VdcQhq2to+QFpJba\n" + "VX6m1cM6hMip2Ag9U3qZ1SNPBBdBBfm9HQybHE3dj713/C2wHuAAGhpXIM1W+20k\n" + "X1knuC/AsSH9aQhQOf/ZMOq1crTfZBuI9q0782/sjGmzMsKPySU4QhUWruVb7OiD\n" + "NVkZAoGAEvihW7G+8/iOE40vGHyBqUeopAAWLciTAUIEwM/Oi3BYfNWNTWF/FWNc\n" + "nMvCZPYigY8C1vO+1iT2Frtd3CIU+f01Q3fJNJoRLlEiKLNZUJRF48OKUqjKSmsi\n" + "w6pucFO40z05YW7utApj4L82rZnOS0pd1tUI1yexqvj0i4ThJfk=\n" + "-----END RSA PRIVATE KEY-----\n"; + +static const char *unrelated_identity_ca_filename = "unrelated_identity_ca"; +static const char *unrelated_identity_ca = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIDpDCCAoygAwIBAgIJALE5lRKfYHAaMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV\n" + "BAYTAk5MMRMwEQYDVQQIDApPdmVyaWpzc2VsMRAwDgYDVQQHDAdIZW5nZWxvMQ8w\n" + "DQYDVQQKDAZBRExJTksxGDAWBgNVBAMMD0NIQU01MDAgUm9vdCBDQTAeFw0xODAy\n" + "MDkxNjIwNDNaFw0zODAyMDQxNjIwNDNaMF8xCzAJBgNVBAYTAk5MMRMwEQYDVQQI\n" + "DApPdmVyaWpzc2VsMRAwDgYDVQQHDAdIZW5nZWxvMQ8wDQYDVQQKDAZBRExJTksx\n" + "GDAWBgNVBAMMD0NIQU01MDAgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\n" + "ADCCAQoCggEBAN9/NbpJDHQYHh3cEByRxnHffxEe9Sapn08Ty5xYO8LDJ4V7vU32\n" + "/7291fITiHaovOoCRHAbKTaTtqJO56aGY45HON6KIqxljLQJJVGW/Nf2PNSHmFix\n" + "6D6bsoSOTPyKYqBNT6lB7NMn4QBTcsiE61El8p9WLQZHoYQJK5Psf7wkBqGBz8he\n" + "bcDWXFn7kIgnsaLrh77w2wi/y0MqpPwyeRInoZfYknzVNdxCPgq7csBYDoMgOgkV\n" + "G60ECXojHKz1HI4n0V8L8lZluSSVRNR0xvPFgBqO7b+Re7xb6iO9TNsFeoiMMNyp\n" + "EwM99CqPO0RRrAPiC7IDgcNGjxhne9EJFGsCAwEAAaNjMGEwHQYDVR0OBBYEFCst\n" + "gj5Ecm3HU/N7wxJluFo5+6XUMB8GA1UdIwQYMBaAFCstgj5Ecm3HU/N7wxJluFo5\n" + "+6XUMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB\n" + "CwUAA4IBAQCWibvYuPLpoNcsUdHbE7SnBbEQnDfBxBZN8xeWHwwAPEB+8eHhmIdZ\n" + "xDtCN61xr5QR+KzlEYFwKyHMp9GN3OPU1RndJrzaXz2ddAZVkBIvnQZ4JvFd+sBC\n" + "QQgEvL8GcwZPxnad/TRylM4ON3Kh0X9vfyrmWEoHephiE1LcENaFqcYr9xg3DJNh\n" + "XSrigMGZJ7IOHkvgaoneICOcYI42ZHS0fnt1G+01VKJXm3ndi5NL25GnOmlvV6yV\n" + "+1vcmdQc6YS8K8vHmrH4lX9iPfsOak6WSzzsXdqgpvyxtGJggcFaDTtmbWCAkJj0\n" + "B7DMeaVlLClGQaKZZ7aexEx9se+IyLn2\n" + "-----END CERTIFICATE-----\n"; + +static const char *invalid_identity_certificate_filename = "invalid_identity_certificate"; +static const char *invalid_identity_certificate = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIDNzCCAh8CCQDn8i4K9c4ErDANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJO\n" + "TDETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0\n" + "cyBQdHkgTHRkMRgwFgYDVTQDDA9DSEFNNTAwIHJvb3QgY2EwHhcNMTgwMjEyMTUw\n" + "NjUxWhcNMTkwNjI3MTUwNjUxWjBcMQswCQYDVQQGEwJOTDETMBEGA1UECAwKU29t\n" + "ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRUwEwYD\n" + "VQQDDAxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB\n" + "AQDRnnNnV3PZrbZwjxk+dkQcO3pK3wMvoDNAHPPiTfXRV2KjLHxsuK7wV+GPHmXo\n" + "97bot6vBxNQN7hfxoDLL+KBO9s3V+8OX6lOrF7hQ6+6/p9EgRoyNGo21eIzGwc2M\n" + "aJAKjImNMbM7FDTvhk3u+VTTJtlnKvJM1tgncbEZwRLri/2MEC5XS/O5FQT4AXPr\n" + "A6bRcGMqCVYtQ0ci6wd18PegA/rSmGSRf/TOd4jZXkxfHD+YOkHcxxz9sX4KnyOg\n" + "XZm8jDdBc7rxiDep8kIjL06VszJeoQrxjuf8cNZtbol/7ECS5aM2YOx7t0Dc/629\n" + "V2Q5waRVBV5xVCJ0BzUh8rIFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGlkxYLr\n" + "ZI/XNjDC6RFfSFRoDc+Xpcg+GsJKKbw2+btZvAD8z7ofL01yGru9oi6u2Yy/ZDKT\n" + "liZ+gtsD8uVyRkS2skq7BvPzvoYErLmSqwlrcCbeX8uHiN7C76ll9PFtSjnwPD//\n" + "UaNyZM5dJB2eBh4/prclix+RR/FWQzkPqEVLwMcFBmnPZ0mvR2tncjpZq476Qyl9\n" + "3jcmfms9qBfBPPjCdXqGEDgsTd2PpYRD2WDj/Ctl4rV7B2jnByullLUYIWGu0rYt\n" + "988waU5i8ie4t/TorBBLqQo/NO9jSXfEqcAnILPnv1QZanKzAAxSg7+FgFrsn359\n" + "ihiEkx9zFUnPrdA=\n" + "-----END CERTIFICATE-----\n"; + +static const char *invalid_identity_ca_filename = "invalid_identity_ca"; +static const char *invalid_identity_ca = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIDljCCAn6gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UEBhMCTkwx\n" + "EzARBgNVBAgMCk92ZXJpanNzZWwxEDAOBgNVBAcMB0hlbmdlbG8xDzANBgNVBAoM\n" + "BkFETElOSzEYMBYGA1UEAwwPQ0hBTTUwMCBSb290IENBMB4XDTE4MDIwOTE2Mjky\n" + "MVoXDTI4MDIwNzE2MjkyMVowVTELMAkGA1UEBhMCTkwxEzARBgNVBAgMCk92ZXJp\n" + "anNzZWwxDzANBgNVBAoMBkFETElOSzEgMB4GA1UEAwwXQ0hBTTUwMCBJbnRlcm1l\n" + "ZGlhdGUgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwucuU/L6N\n" + "iYxYJ7tyzcdzwXwYbr4GynZE4u2Sd7hcXrQGxTotm9BEhOZWscSGvH+UJSp0Vrb4\n" + "3zDppiJ76ys6PeSBw1PpxdO97fO+eAE5DoXRj0a9lmnjbsV6waZ2GxgYQNVmKqbI\n" + "uPDfW+jsmRcTO94s05GWQshHeiqxuEUAv3/Qe2vOhulrg4YDcXrIDWK93cr1EmRX\n" + "Eq3Ck+Fjwtk5wAk3TANv2XQkVfS80jYAurL8J+XC2kyYB7e8KO92zqlfVXXMC3NI\n" + "YDcq86bAI4NNMjVE2zIVheMLoOEXaV7KUTYfEQABZl76aWLDxjED9kf371tcrZzJ\n" + "6xZ1M/rPGNblAgMBAAGjZjBkMB0GA1UdDgQWBBQngrlZqhQptCR4p04zqHamYUx7\n" + "RTAfBgNVHSMEGDAWgBQrLYI+RHJtx1Pze8MSZbhaOful1DASBgNVHRMBAf8ECDAG\n" + "AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEAfMmiQ0tv\n" + "o3K3xwSS621tsfkijUTx920hAe1XYY2XKrG7a/MJBhStex5A3AfqPOY9UMihkBl9\n" + "3hgxOaddX9SAf2eLk2JLhqxZi1U/GVzT5h10AKLA5WUXIK4UGz3JRqhEm7V39t/N\n" + "G0LCdpWOZueezkfO6eGcAvOKthdd32a3zbn+rzzDHdsjzxhEEv8d8x1Xf4xH2dgk\n" + "HlpmpvXMfG/1aCzIpWGEPdkB7WR694GiCmh7hnFBiY+h1GFj2l5dThd51QqAlncM\n" + "u+NmlPCrFZL0ulwRFeo80KOwDpxkqgavDlP9irdWqM9VHybjGu0xFHCeElz9M6od\n" + "ym/MCh4ax7jDxg==\n" + "-----END CERTIFICATE-----\n"; + +static const char *identity_certificate_1024key = + "-----BEGIN CERTIFICATE-----\n" + "MIICrjCCAZYCCQDn8i4K9c4ErjANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJO\n" + "TDETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0\n" + "cyBQdHkgTHRkMRgwFgYDVQQDDA9DSEFNNTAwIHJvb3QgY2EwHhcNMTgwMjE2MTAy\n" + "MzM2WhcNMjMwODA5MTAyMzM2WjBXMQswCQYDVQQGEwJOTDETMBEGA1UECAwKU29t\n" + "ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRAwDgYD\n" + "VQQDDAdDSEFNNTY5MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDS5w0h8L70\n" + "hkreKchVbTzfz4CrBLY4iADNSqPx9uW7DxjeHyLbKT2eRViY/xPuPXQmfRim01QM\n" + "sZWKvFr6k9WMsJ6ItNtCyKS/beONqvXOddIu+4IhNzEGs5v4pTJAOzraoZcVmXnf\n" + "Mr9G/baMYfMG47JR5HaSHDI5esa2STHt4wIDAQABMA0GCSqGSIb3DQEBCwUAA4IB\n" + "AQBdZ2ijHYH8TkOGBqzsNwnNwPaDb/NA0vAO9T5kSOm8HA8vKHnNza+DeUJN+5P/\n" + "P4fLK7UZqpQN32MpvXL0068g99RLjAzAsEVn+0FTyc08r9p/KO/dxxdMKeET7Cpv\n" + "rMpu3W0A/EJptCQsTEZI0iqts7T2qQVXzoDlnUwEt3xdmKYJ9jbEq1UUCeexD3nP\n" + "LB+JtUtfGevVzIoBjHv0qA3ePA24jDUlx5bxFeoIDC4tEewvUG5ZekftsRdNe3fk\n" + "3LkwyK+4NN1ZCa2+S5SOAfjZA2o6qXiq/le0vWRgl7AHEgDr6w7xoRsw4K5dQ+0R\n" + "eKtsBC4XO1GqrNYdKuJb1MhI\n" + "-----END CERTIFICATE-----\n"; + +static const char *invalid_private_key_filename = "invalid_private_key"; +static const char *invalid_private_key = + "data:,-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEowIBAAKCAQEA0Z5zZ1dz2a22cI8ZPnZEHDt6St8DL6AzQBzz4k310Vdioyx8\n" + "bLiu8Ffhjx5l6Pe26LerwcTUDe4X8aAyy/igTvbN1fvDl+pTqxe4UOvuv6fRIEaM\n" + "jRqNtXiMxsHNjGiQCoyJjTGzOxQ074ZN7vlU0ybZZyryTNbYJ3GxGcES64v9jBAu\n" + "V0vzuRUE+AFz6wOm0XBjKglWLUNHIusHdfD3oAP60phkkX/0zneI2V5MXxw/mDpB\n" + "3Mcc/bF+Cp8joF2ZvIw3QXO68Yg3qfJCIy9OlbMyXqEK8Y7n/HDWbW6Jf+xAkuWj\n" + "NmDse7dA3P+tvVdkOcGkVQVecVQidAc1IfKyBQIDAQABAoIBAEddUpzUQTTS11Hq\n" + "5gVF7lpORYxH8KW+PLSPJtjdAduLjKAQ++tn1OcuhDRdfQSbkUIZhfgqMqerb6tr\n" + "ht+6fZlknR9E34pQ1LtjD/U83cOSNrhuTFudtrEZoZPpVzl+P8vXnNzdFs/+SSdi\n" + "6hV5/U8F4u4kyOkwG9cR9eF2wiI+oQ/RBKCXUo3OVs9K27A/OkKsb7coL7yBsgBj\n" + "lzorS9a/DyHT2eiMKjwCZFyG4A66EkLi6t9JLJ8oTkI2WskXYeVEAbEXE57RWm44\n" + "2OgTgfsgYgf2ftXq93KD17FN1m77dqp7EPAhjGnRHNq7+0Ykr1EO1nbDfqHG4gS+4o\n" + "lfP8iwECgYEA58da0R34l93yQnK0mAtoobwvsOjADnBVhBg9L4s2eDs8liUjf0zt\n" + "7hcMdUJaa7iMuNf3qGtnZtRURc3kSOE429Or7fCAYUr/AaA7+2ekPG1vjMb50tVv\n" + "se5rwb1hvgMYe2L5ktJJAg+RcmqpY+ncJ+hP/vWwZRxUKvXba50qqEkCgYEA54ZE\n" + "mJfSueGM/63xlhP71CM4OWtTqkQGp2OmgTOsBI5q/GUXr8vMR8sCEMHAc6HyXzmL\n" + "x/RnAoa/vTX58rXBk0QjfO9esIHa452697EIaJu5w8skCLDv2e/f+Jg7o/IDyUZs\n" + "5lqhiEuH9Qc3sx2nhnSYXMZWqwh8OchI7dCSE90CgYEAzrJ1JhpxUJYI7wM2VIWQ\n" + "GPQnH8BhTj8VtEidgCHJQK2rGUcjgepMIVECtiunUXtyW4GWBedKfmSKhvnXRLs9\n" + "pqT9JaOeCaYFBiEsfMZvqUY4e/YSYtge1PIHvO40FWzTT23zneDUZPcXQY8nYsfy\n" + "otBFTt0yIumBkhJRTIYLvakCgYA+CcttvBj6OAcJJ/n5RgeP05QoRqsXj7zcs6YV\n" + "LtxkKClg0lHjiE+H2U0HYnOISJfijk/3V3UWxzavo7wDHlLtfC+qNZYA4/rcTRKh\n" + "dm2TYk8HuPJB5e+PTWiNe3VXu+zpzRY3L4fjNqIKtVFmjIasT6fYDEmC8PYgoZtx\n" + "JhdOfQKBgCD/bDkc+VI6lwQtoQQKiSfQjKGe+6Cw9K/obzWO0uJwBvZrGLXF8tTc\n" + "MOPIv9OILt7DYxpMXAiHv8HtzH5CFVrZ/nj63Soka/j2yvUdBDrGhyIbsc4pDu+\n" + "lCFa0ZiT/u5vRAiOkM6GuStH4HxnW9LtwBtiYXtfU7IPExJiAlsq\n" + "-----END RSA PRIVATE KEY-----\n"; + +static const char *private_key_1024 = + "data:,-----BEGIN RSA PRIVATE KEY-----\n" + "MIICXAIBAAKBgQDS5w0h8L70hkreKchVbTzfz4CrBLY4iADNSqPx9uW7DxjeHyLb\n" + "KT2eRViY/xPuPXQmfRim01QMsZWKvFr6k9WMsJ6ItNtCyKS/beONqvXOddIu+4Ih\n" + "NzEGs5v4pTJAOzraoZcVmXnfMr9G/baMYfMG47JR5HaSHDI5esa2STHt4wIDAQAB\n" + "AoGAQi7LijkYU3fJCsql2Vj8X2eogwJphHf5eHLR296U3QyxyxKOR6Q7d+1fDjQN\n" + "txeF2YYsND3hBFK+ENlm23eE7Z1tpWtnLNJ9OH84ZkPnqTnEcWsRddT/x9vKOPMz\n" + "eK8QNetD3AP5qXsjpIpgep1diWYHCyhMTAFISzvdtC7pvFECQQD2zoqwRtF26lzg\n" + "QPR02Z+L80R2VhpeLoqMIplT1bmlrPlDr/eIwvtu1eQFyGSASG2EFs1rucdJl7qu\n" + "SrJ+eyv1AkEA2sIjy8+RCk1uH8kEwYaMJ3dccqnpcMCZ1b3GncKl+ICmDCYcpfd5\n" + "rP5tX+GL3RVw370pUApJvrVTgOpAVHYjdwJAOYz8BhLdcS9BLQG4fy7n50h4pGd7\n" + "io6ru/Wtb0EdIybskP4NaJSe8L9rhnWuCcPZ1b1DdWVCtURuQYoliRzLqQJBAJWO\n" + "ZrSfKpS1jRVT89lu6ADPXLfTrBH2yvVS8ifG/HshUOQ7ZhidUWVQ6GvFoj46u1lr\n" + "VIQxFGu6QeV/wQ09W08CQHGkrZgu/FpS2tNvYmKNDHOna+dW452N5N81u5sRP1A8\n" + "x9pYC9xoOGE2E8v1ocMJDPoMe0yk1QSX9mjhhwYOy28=\n" + "-----END RSA PRIVATE KEY-----\n"; + +static const char *private_key_w_password_filename = "private_key_w_password"; +static const char *private_key_w_password = + "data:,-----BEGIN RSA PRIVATE KEY-----\n" + "Proc-Type: 4,ENCRYPTED\n" + "DEK-Info: AES-256-CBC,0C9C38C5678AECD200E024A9A5BC717A\n" + "\n" + "wbXYsR78o4DIaQbKsB4cwEFge79GMKbcMgIWK+9k86dPk09WZkj7JCSJXIxPLYOG\n" + "tFZrw/z86cakEhf90a4Moa1cwByrcFB+bpWoEqsx/C4javWxXMENbmQ5x8gDpmzT\n" + "qqLI7xnd2mYj7HcfE7eXi+Nub5w1tBxN0CWaxpR54ZVvfcPE6Od4SHGughdUN4AK\n" + "OdVIq5YuzMhuTDJKy+kGOtjH8pBWvo8S12T2UQEuusx5WUbEJ6m+E80aN7M6gCA+\n" + "XmNTt3PsV9PfZPL2Off/90gqTBdMhwn+sEVlqYG0TAnXZQEI8ZNtAGy77CFplqdT\n" + "SmI3x8Sza7lchEMFhRiayX9pMBPUlwckVPrCoMQ4b4WkHYoGLO7dNVAA8Osud46+\n" + "6MZKHStjdzwKz9MzWa7lXhXV+0sX5bcAzQexuE+wO8QQ/t5uwDmQHol0JVdRX8NB\n" + "/Exk6aT7mWajFvukXVirpUGWnEK2W+O8/VBzVZ7z69EjZ09Pu4Y/+cbX12LGSwMb\n" + "WVtnZY6BsrV++vikQuL3ByTBDPRHio2H8hThh1Kv8n5VEBUrk7tLUp3Z15cbfC6s\n" + "LDHX6kB2OKmmdqLOOMo4lToZfnrVK/dzeXFbtNH1POpR4/e5Nk0SyZrWo+E/AqIv\n" + "nLQ3fhLCPOB5rjAhuM8iXOwqn8HHNlv9j8mlgCcgwK7focYVc/IXARLOfFOjOA/s\n" + "EqMRbb/eKsC930NHBZkhlqRJKCwA37AMvnOhN4R0VOq/40K+62IUK9E1643KyWs0\n" + "vWk0rFY0OKorQXzI33lbBYZ5zHt8oxGNx3us+6jGP85iv8UEaO6FpgajEUn6Gzp/\n" + "wyvr1C/B/Hfr6eTbt4C6Fi5fMfZgM6VEcJuaFZnoC9tWdhlNsY1pwtPghMM7yBwc\n" + "1Ye0TxdF36exJWu1gXVTse1Vdc9i4QWpT2fbPQtcIgdtNk01K+2defie384IOnQQ\n" + "O8/SRsrnLRLV3IDFh/VBJS1ZVm8Zmt10yGgRwtYHntMkIopoFRWcm9/Gh3iBFKKH\n" + "OTVXxgKOUYk4qXG61N8k0M+TIdoOHZIha3Myis1tQVmA/b/4FRKPYgdrFijhXNLM\n" + "wwMHQOS14xBF2KBgaak7dMUWhGrClw1hc3HmMXuM+OLvxy+f8MC3JP2U5AuCs472\n" + "hc41KWxioqNMPVXZgVnHf3aEec+hBFceqYnlzG+E/Gagiufu8WMySaZgzXMRb5aV\n" + "x2OVcakSKrTC5EKbLDlZ6+1NRJht7wdSefh0o/Crc9LzcFqBL0Qp3WCvyY8gDVkQ\n" + "EGqoVYOE6Hz/NX5/17F1+5VuWT7nBWABHKFFriOoJ3VR9sZhp0HiMznZEF1AwVuZ\n" + "xHtDWQemfBywEQG23qbr+o7mQASh1zki8b4fP1HQmbHhaJarjwGdiVNIgcF7s7Qk\n" + "NYNcgsc1l0KuNHvredTnYwPhv3C08IBfjtd2H9u0A+AWl5RlR4GDfv2Jzbe/F8U+\n" + "0gxj8D2XWHlkbHIXKVk6jxj64xyNE1xB0Sv7gsDWpkaK6aw/zdsyxqiji4mThcYE\n" + "cRSl4y9CGZREaiyD8dk/uiqKfQ26c1gfOUDYS2fKjH5NKh4J80wQj0GvS6nHiDH4\n" + "-----END RSA PRIVATE KEY-----\n"; + +static const char *private_key_password ="CHAM569"; + +const char *ec_identity_certificate_filename = "ec_identity_certificate"; +const char *ec_identity_certificate = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIICOzCCAeGgAwIBAgICEAAwCgYIKoZIzj0EAwIwZTELMAkGA1UEBhMCTkwxEzAR\n" + "BgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2d5IEIu\n" + "Vi4xIDAeBgNVBAMMF0NIQU1fNTcwIENBIGNlcnRpZmljYXRlMB4XDTE5MDIxODEw\n" + "NTI0MVoXDTQ2MDcwNjEwNTI0MVowazELMAkGA1UEBhMCTkwxEzARBgNVBAgMClNv\n" + "bWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2d5IEIuVi4xJjAkBgNV\n" + "BAMMHUNIQU1fNTcwIElkZW50aXR5IGNlcnRpZmljYXRlMFkwEwYHKoZIzj0CAQYI\n" + "KoZIzj0DAQcDQgAEnbV79f5j2iTkDCbFMlVVs396YOoNViwKheBbhVoBG2n8I3mY\n" + "M9Zg1dmrHh16HsJfrTCbc0VAOdkH91mNRPZr46N7MHkwCQYDVR0TBAIwADAsBglg\n" + "hkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0O\n" + "BBYEFMZoftcgs1FL1FBUJhKGvpvqVaHqMB8GA1UdIwQYMBaAFHUuWr3OtGtMktK9\n" + "QnKSSydxn4ewMAoGCCqGSM49BAMCA0gAMEUCIQCyp777C9Tih7Asybj6ELAYS9xq\n" + "vFhV6CJGk9ixW1AXdwIgKs9CEPx+Ajk3RErPm6OaVcsVLRKGBn7UuCR6VxNItWk=\n" + "-----END CERTIFICATE-----\n"; + +const char *ec_private_key_filename = "ec_private_key"; +const char *ec_private_key = + "data:,-----BEGIN PRIVATE KEY-----\n" + "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgP3SnBXzcCc0uUEiG\n" + "0CPNdcV0hBewOnVoh4d9q9E5U5ihRANCAASdtXv1/mPaJOQMJsUyVVWzf3pg6g1W\n" + "LAqF4FuFWgEbafwjeZgz1mDV2aseHXoewl+tMJtzRUA52Qf3WY1E9mvj\n" + "-----END PRIVATE KEY-----\n"; + +static const char *ec_password ="CHAM-570"; + +const char *ec_private_key_w_password_filename = "ec_private_key_w_password"; +const char *ec_private_key_w_password = + "data:,-----BEGIN EC PRIVATE KEY-----\n" + "Proc-Type: 4,ENCRYPTED\n" + "DEK-Info: AES-256-CBC,11055B75D406068EB1FF850646228EA9\n" + "\n" + "GUnwN8e2gvUkopN3ak+2dK1dSTSKSJguers3h5C+qQDq57By933ijCCjUTu2LY/F\n" + "ERH6m8UD6H5ij/QDsXLx6tH/dFQ7An+Zao3eD2N2zquGED/OfTQJFv3gBKs4RUtg\n" + "66dfuv9mNSXt7Rnu9uBNtodm5JGifczdmIPHn0mNY2g=\n" + "-----END EC PRIVATE KEY-----"; + +const char *ec_identity_ca_filename = "ec_identity_ca"; +const char *ec_identity_ca = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIICEDCCAbegAwIBAgIJAPOifu8ejrRRMAoGCCqGSM49BAMCMGUxCzAJBgNVBAYT\n" + "Ak5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQKDBZBRExJTksgVGVjaG5v\n" + "bG9neSBCLlYuMSAwHgYDVQQDDBdDSEFNXzU3MCBDQSBjZXJ0aWZpY2F0ZTAeFw0x\n" + "OTAyMTgxMDQwMTZaFw00NjA3MDYxMDQwMTZaMGUxCzAJBgNVBAYTAk5MMRMwEQYD\n" + "VQQIDApTb21lLVN0YXRlMR8wHQYDVQQKDBZBRExJTksgVGVjaG5vbG9neSBCLlYu\n" + "MSAwHgYDVQQDDBdDSEFNXzU3MCBDQSBjZXJ0aWZpY2F0ZTBZMBMGByqGSM49AgEG\n" + "CCqGSM49AwEHA0IABMXCYXBHEryADoYXMEE0Jw9aHlA7p3KVFzuypxuez0n7rKoX\n" + "k9kanNtrw5o2X4WSWKM7zkH4I6AU7xSAQgJN+8GjUDBOMB0GA1UdDgQWBBR1Llq9\n" + "zrRrTJLSvUJykksncZ+HsDAfBgNVHSMEGDAWgBR1Llq9zrRrTJLSvUJykksncZ+H\n" + "sDAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0cAMEQCIHKRM3VeB2F7z3nJT752\n" + "gY5mNdj91ulmNX84TXA7UHNKAiA2ytpsV4OKURHkjyn1gnW48JDKtHGZF6/tMNvX\n" + "VrDITA==\n" + "-----END CERTIFICATE-----\n"; + + +const char *ec_identity_certificate_unsupported_filename = "ec_identity_certificate_unsupported"; +const char *ec_identity_certificate_unsupported = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIICFTCCAbygAwIBAgICEAEwCgYIKoZIzj0EAwIwWjELMAkGA1UEBhMCTkwxEzAR\n" + "BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5\n" + "IEx0ZDETMBEGA1UEAwwKQ0hBTTUwMF9DQTAeFw0xODAyMTkxMDMyMjRaFw0xOTAy\n" + "MTkxMDMyMjRaMGExCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw\n" + "HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxGjAYBgNVBAMMEUNIQU01\n" + "NjkgdW5zdXAga2V5MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQIDMgAEKt3HYPnDlEOS\n" + "zYqTzT2patyreLHN2Jty22KXwjaNAjgrwujdPr+MW38DsyBF5Yn9o3sweTAJBgNV\n" + "HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp\n" + "Y2F0ZTAdBgNVHQ4EFgQUG9MuQz3W/AKA98AyOKhI2af9I+0wHwYDVR0jBBgwFoAU\n" + "ACsYsaEsZfjfRVrj0IBmcsncVyMwCgYIKoZIzj0EAwIDRwAwRAIgfhisahVmgghI\n" + "GaaQavdKHpM/OTVODZPzYjky6Am+z08CIBidnuuznXrZtr78oy/tAES/7Lz8P5Iw\n" + "Q1y5Vo8CdXQQ\n" + "-----END CERTIFICATE-----\n"; + +const char *ec_private_key_unsupported_filename = "ec_private_key_unsupported"; +const char *ec_private_key_unsupported = + "data:,-----BEGIN PRIVATE KEY-----\n" + "MG8CAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQIEVTBTAgEBBBh8p6kwBS7jT86ctN33\n" + "Vs4vosHh7upPZBWhNAMyAAQq3cdg+cOUQ5LNipPNPalq3Kt4sc3Ym3LbYpfCNo0C\n" + "OCvC6N0+v4xbfwOzIEXlif0=\n" + "-----END PRIVATE KEY-----\n"; + + +const char *private_key_not_matching_filename = "private_key_not_matching"; +const char *private_key_not_matching = + "data:,-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEpgIBAAKCAQEAz90I7hABwJ27DQ0ypKEOlO8ZPoMKVMUAkTxl+48Icqo2SJxF\n" + "vKOxVd8XflJ2jor3YqzPgbuLVGolTafxzuGDYQVTNrSUgaCZMdX8O8UFxsBrQ+m9\n" + "0pJeg+1I0OHrn8Y7VHuh5IVHNqmqwsw9TA5aLjp1i9Gc9pvGzbXEfGfnol64bvht\n" + "p3k8xMG8DZKKJNg8GUcYlLvwY+jcE8yMvQzM+gya6Y7w1JVgj4wQNjWULgqTJlUq\n" + "q1Wch9o7/tp1wzX3E4B8AeTCEsYEL9tUASp6V6/4Yf/jbGM2/nfaczj8lW0Gez6a\n" + "xHkMBh22vqLzZvvOFTX6U46KG/iWZAehKdPJrwIDAQABAoIBAQDGvQsAsoU6aJSj\n" + "Ee9NwD903nZAcoG6MvEr65eGQWdOWre0DNYQWmH/PGH2AVohR3Tn/1oXK/03JJWt\n" + "/dkQeEVoyfKZ52Xl2mseXv3fF61CLk9gi2dWoWOEt6ZbMOZbyOiJCfvrxhIkjWwa\n" + "+7PPuBk5AePJXwy4LJCTtiq61418i2Bbl6JamytgxsiVK9kZXdN6JqEVYmweMpmR\n" + "T1mzi7lssyttBIXwG8ajStUteIYLyi8d+UX4S08EyV0VGL0p5+F8xTY1jVX/t6Y0\n" + "KbANJdjEab9mbndzbxprJlS08KBLgdnAO4w0nmINiaO2isXOLoV8SU3tTqHC3W7c\n" + "CCSKJdGBAoGBAP9vCSP1AaEjYa6sfEUgThpCo7PhRuOMEDb+4ldv9O+hzXv5I8td\n" + "gbDs1g3jyhb0yhW9uV9NsuKBtsmv1zYFswZDNbdr2S1VZPMpAx+SeLHQWy6HbU/t\n" + "oHoOO+l8erFVvR2uqit5rBDzN6/lh4SoQzYE9JDAnXJp9W0rKAdtBSLRAoGBANBT\n" + "AIErbPo4EuU13DaEa+EfoU4Abktyi+L8dpdoXMq6sHg3Mlhifr+ryoybrMMA3tmT\n" + "6ekBCSVThF0/+HAFRAJthnyBgUd0D710JDHro47Mg37CxU+V8JYqZJGHUSfqng7/\n" + "pM7LjM99VhigquH4PoDH4YpL8vnIeEMNmny4iER/AoGBAJj8k+jpUXSFkHfh7vwo\n" + "AR9RUmLmRmL6/KsztbTQ5U6xBjV+XqXq90ZUU1A2Yk+lhXPIEkK2crGfJy9dFfTR\n" + "LQxPLNkSyxyPzMqmgaxjOc6mEDap/hqlJDx2UgPh/kpAI+inOFyZnyj3wx6ixqv5\n" + "a2frR996vdJNDCW6d1sbPLxBAoGBAMO66IN0UJy76Izw0Olr+4v10vFdmENM6T+o\n" + "IqhZBq33P+yDN8sxJ5NgjhsT/Pruq3LT9XbVYUlvsbKHcx2U5PQ/AZejedqvokZH\n" + "g+ZfVjnJz1ZfG1GOOBBu3jSZZdfSKRVAfhFJ0A/229ihxEwxmFAY/MCaYTzsbInb\n" + "kyXRnz5zAoGBAIT9Fuk7zhfubYvkzIQ0kj/IxL3QohVRKcoGapDMSwNjTvxZdKxF\n" + "WXkhhJT095QznHP1fhp90fBKlOdsReDWfZXMYtZTqo2+ezK8qb6xMlm+LE09y+Na\n" + "f7pp1EPnIqyEX27B4aQ81M8tkCqbdlv3CdjFSusp6SsWTGTjr/5SAMDS\n" + "-----END RSA PRIVATE KEY-----\n"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_authentication *auth = NULL; + + +CU_Init(ddssec_builtin_validate_local_identity) +{ + /* Only need the authentication plugin. */ + plugins = load_plugins(NULL /* Access Control */, + &auth /* Authentication */, + NULL /* Cryptograpy */); + return plugins ? 0 : -1; +} + + +CU_Clean(ddssec_builtin_validate_local_identity) +{ + unload_plugins(plugins); + return 0; +} + + +static void +dds_security_property_init( + DDS_Security_PropertySeq *seq, + DDS_Security_unsigned_long size) +{ + seq->_length = size; + seq->_maximum = size; + seq->_buffer = ddsrt_malloc(size * sizeof(DDS_Security_Property_t)); + memset(seq->_buffer, 0, size * sizeof(DDS_Security_Property_t)); +} + +static void +dds_security_property_deinit( + DDS_Security_PropertySeq *seq) +{ + uint32_t i; + + for (i = 0; i < seq->_length; i++) { + ddsrt_free(seq->_buffer[i].name); + ddsrt_free(seq->_buffer[i].value); + } + ddsrt_free(seq->_buffer); +} + +static void +print_guid( + const char *msg, + DDS_Security_GUID_t *guid) +{ + uint32_t i, j; + + printf("%s=", msg); + for (i = 0; i < 3; i++) { + for (j = 0; j < 4; j++) { + printf("%02x", guid->prefix[i*4+j]); + } + printf(":"); + } + for (i = 0; i < 3; i++) { + printf("%02x", guid->entityId.entityKey[i]); + } + printf(":%02x\n", guid->entityId.entityKind); +} + +static void +reset_exception( + DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void fill_participant_qos(DDS_Security_Qos *participant_qos, + bool is_file_certificate, const char *certificate, + bool is_file_ca, const char *ca, + bool is_file_private_key, const char *private_key, + const char* password, + const char* trusted_ca_dir){ + + char identity_cert_path[1024]; + char identity_CA_path[1024]; + char private_key_path[1024]; + char trusted_ca_dir_path[1024]; + unsigned size = 3; + + password ? size++ : size; + trusted_ca_dir ? size++ : size; + + memset(participant_qos, 0, sizeof(*participant_qos)); + dds_security_property_init(&participant_qos->property.value, size); + + participant_qos->property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + participant_qos->property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + participant_qos->property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + + + if( is_file_certificate){ +#ifdef WIN32 + snprintf(identity_cert_path, 1024, "file:%s\\validate_local_identity\\etc\\%s", CONFIG_ENV_TESTS_DIR, certificate); +#else + snprintf(identity_cert_path, 1024, "file:%s/validate_local_identity/etc/%s", CONFIG_ENV_TESTS_DIR, certificate); +#endif + participant_qos->property.value._buffer[0].value = ddsrt_strdup(identity_cert_path); + } + else{ + participant_qos->property.value._buffer[0].value = ddsrt_strdup(certificate); + } + + if( is_file_ca){ +#ifdef WIN32 + snprintf(identity_CA_path, 1024, "file:%s\\validate_local_identity\\etc\\%s", CONFIG_ENV_TESTS_DIR,ca); +#else + snprintf(identity_CA_path, 1024, "file:%s/validate_local_identity/etc/%s", CONFIG_ENV_TESTS_DIR,ca); +#endif + participant_qos->property.value._buffer[1].value = ddsrt_strdup(identity_CA_path); + } + else { + participant_qos->property.value._buffer[1].value = ddsrt_strdup(ca); + } + + if( is_file_private_key){ + #ifdef WIN32 + snprintf(private_key_path, 1024, "file:%s\\validate_local_identity\\etc\\%s", CONFIG_ENV_TESTS_DIR,private_key); + #else + snprintf(private_key_path, 1024, "file:%s/validate_local_identity/etc/%s", CONFIG_ENV_TESTS_DIR, private_key); + #endif + participant_qos->property.value._buffer[2].value = ddsrt_strdup(private_key_path); + } + else{ + participant_qos->property.value._buffer[2].value = ddsrt_strdup(private_key); + } + + if( password ){ + participant_qos->property.value._buffer[3].name = ddsrt_strdup(PROPERTY_PASSWORD); + participant_qos->property.value._buffer[3].value = ddsrt_strdup(password); + } + + if( trusted_ca_dir ){ + #ifdef WIN32 + snprintf(trusted_ca_dir_path, 1024, "%s\\validate_local_identity\\etc\\%s", CONFIG_ENV_TESTS_DIR,trusted_ca_dir); + #else + snprintf(trusted_ca_dir_path, 1024, "%s/validate_local_identity/etc/%s", CONFIG_ENV_TESTS_DIR, trusted_ca_dir); + #endif + participant_qos->property.value._buffer[size-1].name = ddsrt_strdup(PROPERTY_TRUSTED_CA_DIR); + participant_qos->property.value._buffer[size-1].value = ddsrt_strdup(trusted_ca_dir_path); + } + + +} + +CU_Test(ddssec_builtin_validate_local_identity,happy_day) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + DDS_Security_boolean success; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate, + false, identity_ca, + false, private_key_pem, + NULL, + NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT_FATAL (result == DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + + print_guid("adjusted_participant_guid", &adjusted_participant_guid); + CU_ASSERT (memcmp(&adjusted_participant_guid.entityId, &entityId, sizeof(entityId)) == 0); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + /* validate with file */ + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, true, identity_certificate_filename, + true, identity_ca_filename, + true, private_key_filename, + NULL, + NULL); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT_FATAL (result == DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + + print_guid("adjusted_participant_guid", &adjusted_participant_guid); + CU_ASSERT (memcmp(&adjusted_participant_guid.entityId, &entityId, sizeof(entityId)) == 0); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + + + +} + +CU_Test(ddssec_builtin_validate_local_identity,invalid_certificate) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, invalid_identity_certificate, + false, identity_ca, + false, private_key_pem, + NULL, + NULL); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + /* test with file */ + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, true, invalid_identity_certificate_filename, + false, identity_ca, + false, private_key_pem, + NULL, + NULL); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); +} + + +CU_Test(ddssec_builtin_validate_local_identity,invalid_root) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate, + false, invalid_identity_ca, + false, private_key_pem, + NULL, + NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + /* test with file */ + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate, + true, invalid_identity_ca_filename, + false, private_key_pem, + NULL, + NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_validate_local_identity,invalid_chain) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate, + false, unrelated_identity_ca, + false, private_key_pem, + NULL, + NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + /* test with file input*/ + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate, + true, unrelated_identity_ca_filename, + false, private_key_pem, + NULL, + NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + +} + +CU_Test(ddssec_builtin_validate_local_identity,certificate_key_to_small) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate_1024key, + false, identity_ca, + false, private_key_pem, + NULL, + NULL); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); +} + + +CU_Test(ddssec_builtin_validate_local_identity,invalid_private_key) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate, + false, identity_ca, + false, invalid_private_key, + NULL, + NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + /*test with file input */ + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate, + false, identity_ca, + true, invalid_private_key_filename, + NULL, + NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); +} + + +CU_Test(ddssec_builtin_validate_local_identity,private_key_to_small) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate, + false, identity_ca, + false, private_key_1024, + NULL, + NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); +} + + +CU_Test(ddssec_builtin_validate_local_identity,missing_certificate_property) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + memset(&participant_qos, 0, sizeof(participant_qos)); + dds_security_property_init(&participant_qos.property.value, 3); + participant_qos.property.value._buffer[0].name = ddsrt_strdup("dds.sec.auth.identity_cert"); + participant_qos.property.value._buffer[0].value = ddsrt_strdup(identity_certificate); + participant_qos.property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + participant_qos.property.value._buffer[1].value = ddsrt_strdup(identity_ca); + participant_qos.property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + participant_qos.property.value._buffer[2].value = ddsrt_strdup(private_key_1024); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT_FATAL (exception.message != NULL); + assert(exception.message != NULL); // for Clang's static analyzer + CU_ASSERT(strcmp(exception.message, "validate_local_identity: missing property 'dds.sec.auth.identity_certificate'") == 0); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); +} + + +CU_Test(ddssec_builtin_validate_local_identity,missing_ca_property) +{ + DDS_Security_ValidationResult_t result; + + /* Dummy (even un-initialized) data for now. */ + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + memset(&participant_qos, 0, sizeof(participant_qos)); + dds_security_property_init(&participant_qos.property.value, 3); + participant_qos.property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + participant_qos.property.value._buffer[0].value = ddsrt_strdup(identity_certificate); + participant_qos.property.value._buffer[1].name = ddsrt_strdup("dds.sec.auth.identit_ca"); + participant_qos.property.value._buffer[1].value = ddsrt_strdup(identity_ca); + participant_qos.property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + participant_qos.property.value._buffer[2].value = ddsrt_strdup(private_key_1024); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT_FATAL (exception.message != NULL); + assert(exception.message != NULL); // for Clang's static analyzer + CU_ASSERT(strcmp(exception.message, "validate_local_identity: missing property 'dds.sec.auth.identity_ca'") == 0); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_validate_local_identity,missing_private_key_property) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + memset(&participant_qos, 0, sizeof(participant_qos)); + dds_security_property_init(&participant_qos.property.value, 2); + participant_qos.property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + participant_qos.property.value._buffer[0].value = ddsrt_strdup(identity_certificate); + participant_qos.property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + participant_qos.property.value._buffer[1].value = ddsrt_strdup(identity_ca); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT_FATAL (exception.message != NULL); + assert(exception.message != NULL); // for Clang's static analyzer + CU_ASSERT(strcmp(exception.message, "validate_local_identity: missing property 'dds.sec.auth.private_key'") == 0); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_validate_local_identity,unsupported_certification_format) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + char *cert; + size_t len; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + len = strlen("uri:") + strlen(&identity_certificate[6]) + 1; + cert = ddsrt_malloc(len); + + snprintf(cert, len, "uri:%s", &identity_certificate[6]); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, cert, + false, identity_ca, + false, private_key_pem, + NULL, NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + ddsrt_free(cert); +} + +CU_Test(ddssec_builtin_validate_local_identity,encrypted_key) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate, + false, identity_ca, + false, private_key_w_password, + private_key_password, NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result == DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + + print_guid("adjusted_participant_guid", &adjusted_participant_guid); + CU_ASSERT (memcmp(&adjusted_participant_guid.entityId, &entityId, sizeof(entityId)) == 0); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + /* test with file */ + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate, + false, identity_ca, + true, private_key_w_password_filename, + private_key_password, NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result == DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + + print_guid("adjusted_participant_guid", &adjusted_participant_guid); + CU_ASSERT (memcmp(&adjusted_participant_guid.entityId, &entityId, sizeof(entityId)) == 0); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_validate_local_identity,encrypted_key_no_password) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate, + false, identity_ca, + false, private_key_w_password, + NULL, + NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + /*test with file */ + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate, + false, identity_ca, + true, private_key_w_password_filename, + NULL, + NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_validate_local_identity,encrypted_key_invalid_password) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate, + false, identity_ca, + false, private_key_w_password, + "invalid", + NULL); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + /*test with file */ + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate, + false, identity_ca, + true, private_key_w_password_filename, + "invalid", + NULL); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_validate_local_identity,happy_day_eliptic) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + DDS_Security_boolean success; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, ec_identity_certificate, + false, ec_identity_ca, + false, ec_private_key, + NULL, + NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT_FATAL (result == DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + + print_guid("adjusted_participant_guid", &adjusted_participant_guid); + CU_ASSERT (memcmp(&adjusted_participant_guid.entityId, &entityId, sizeof(entityId)) == 0); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + /* test with file */ + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, true, ec_identity_certificate_filename, + true, ec_identity_ca_filename, + true, ec_private_key_filename, + NULL, + NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT_FATAL (result == DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + + print_guid("adjusted_participant_guid", &adjusted_participant_guid); + CU_ASSERT (memcmp(&adjusted_participant_guid.entityId, &entityId, sizeof(entityId)) == 0); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + +} + + +CU_Test(ddssec_builtin_validate_local_identity,encrypted_ec_key) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, ec_identity_certificate, + false, ec_identity_ca, + false, ec_private_key_w_password, + ec_password, + NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT_FATAL (result == DDS_SECURITY_VALIDATION_OK); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + + print_guid("adjusted_participant_guid", &adjusted_participant_guid); + CU_ASSERT_FATAL (memcmp(&adjusted_participant_guid.entityId, &entityId, sizeof(entityId)) == 0); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + /* test with file */ + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, ec_identity_certificate, + false, ec_identity_ca, + true, ec_private_key_w_password_filename, + ec_password, + NULL); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result == DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + + CU_ASSERT (memcmp(&adjusted_participant_guid.entityId, &entityId, sizeof(entityId)) == 0); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_validate_local_identity,elliptic_unsupported_certificate) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + memset(&participant_qos, 0, sizeof(participant_qos)); + dds_security_property_init(&participant_qos.property.value, 3); + participant_qos.property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + participant_qos.property.value._buffer[0].value = ddsrt_strdup(ec_identity_certificate_unsupported); + participant_qos.property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + participant_qos.property.value._buffer[1].value = ddsrt_strdup(ec_identity_ca); + participant_qos.property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + participant_qos.property.value._buffer[2].value = ddsrt_strdup(ec_private_key); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_validate_local_identity,elliptic_unsupported_private_key) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + memset(&participant_qos, 0, sizeof(participant_qos)); + dds_security_property_init(&participant_qos.property.value, 3); + participant_qos.property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + participant_qos.property.value._buffer[0].value = ddsrt_strdup(ec_identity_certificate); + participant_qos.property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + participant_qos.property.value._buffer[1].value = ddsrt_strdup(ec_identity_ca); + participant_qos.property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + participant_qos.property.value._buffer[2].value = ddsrt_strdup(ec_private_key_unsupported); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); +} + +CU_Test(ddssec_builtin_validate_local_identity,return_freed_handle) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + DDS_Security_boolean success; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + memset(&participant_qos, 0, sizeof(participant_qos)); + dds_security_property_init(&participant_qos.property.value, 3); + participant_qos.property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + participant_qos.property.value._buffer[0].value = ddsrt_strdup(identity_certificate); + participant_qos.property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + participant_qos.property.value._buffer[1].value = ddsrt_strdup(identity_ca); + participant_qos.property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + participant_qos.property.value._buffer[2].value = ddsrt_strdup(private_key_pem); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT_FATAL (result == DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + + print_guid("adjusted_participant_guid", &adjusted_participant_guid); + CU_ASSERT (memcmp(&adjusted_participant_guid.entityId, &entityId, sizeof(entityId)) == 0); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + CU_ASSERT_FATAL (success); + + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + CU_ASSERT_FALSE (success); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); +} + + +CU_Test(ddssec_builtin_validate_local_identity,no_file) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + /* validate with file */ + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, true, identity_certificate_filename, + false, identity_ca, + true, "invalid_filename", + NULL, + NULL); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT_FATAL (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT_FATAL (local_identity_handle == DDS_SECURITY_HANDLE_NIL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, true, identity_certificate_filename, + true, "invalid_filename", + true, private_key_filename, + NULL, + NULL); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT_FATAL (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT_FATAL (local_identity_handle == DDS_SECURITY_HANDLE_NIL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, true, "invalid_filename", + true, identity_ca_filename, + false, private_key_pem, + NULL, + NULL); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT_FATAL (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT_FATAL (local_identity_handle == DDS_SECURITY_HANDLE_NIL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + +} + +CU_Test(ddssec_builtin_validate_local_identity,with_extended_certificate_check) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_GUID_t adjusted_participant_guid; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; + DDS_Security_EntityId_t entityId = {{0xa0,0xa1,0xa2},0x1}; + DDS_Security_boolean success; + + /* Check if we actually have the validate_local_identity() function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (auth->validate_local_identity != NULL); + + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, false, identity_certificate, + false, identity_ca, + false, private_key_pem, + NULL, + "trusted_ca_dir"); + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + /* We expected the validation to have succeeded. */ + CU_ASSERT_FATAL (result == DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + + print_guid("adjusted_participant_guid", &adjusted_participant_guid); + CU_ASSERT (memcmp(&adjusted_participant_guid.entityId, &entityId, sizeof(entityId)) == 0); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + CU_ASSERT_TRUE (success); + + local_identity_handle = DDS_SECURITY_HANDLE_NIL; + reset_exception(&exception); + + /* validate with file */ + memset(&adjusted_participant_guid, 0, sizeof(adjusted_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, true, identity_certificate_filename, + true, identity_ca_filename, + true, private_key_filename, + NULL, + "trusted_ca_dir_not_matching"); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &adjusted_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + + /* We expected the validation to have succeeded. */ + CU_ASSERT_FATAL (result != DDS_SECURITY_VALIDATION_OK); + CU_ASSERT (local_identity_handle == DDS_SECURITY_HANDLE_NIL); + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + +} diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_File_empty.txt b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_File_empty.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_File_text.txt b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_File_text.txt new file mode 100644 index 0000000..c1991b0 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_File_text.txt @@ -0,0 +1,3 @@ +This is just a file to see how the Security Plugin +reacts when it receives a file that doesn't contain +expected content, but just some text. diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_check_create_participant.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_check_create_participant.p7s new file mode 100644 index 0000000..8992b03 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_check_create_participant.p7s @@ -0,0 +1,199 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----988CFBB47A225358D7A5B33A4CA9AD64" + +This is an S/MIME signed message + +------988CFBB47A225358D7A5B33A4CA9AD64 +Content-Type: text/plain + + + + + + + + 1 + + 1 + NONE + SIGN + ENCRYPT + + TRUE + + + + FALSE + ENCRYPT + TRUE + SIGN + Topic1 + + true + + true + + + FALSE + ENCRYPT + TRUE + SIGN + Topic2 + + true + + true + + + + + + + 2 + + 1 + NONE + SIGN + ENCRYPT + + TRUE + + + + FALSE + ENCRYPT + TRUE + SIGN + Topic1 + + true + + false + + + FALSE + ENCRYPT + TRUE + SIGN + Topic2 + + true + + true + + + + + + + 3 + + 1 + NONE + SIGN + ENCRYPT + + TRUE + + + + FALSE + ENCRYPT + TRUE + SIGN + Topic1 + + false + + false + + + FALSE + ENCRYPT + TRUE + SIGN + Topic2 + + false + + false + + + + + + + 4 + + 1 + NONE + SIGN + ENCRYPT + + FALSE + + + + FALSE + ENCRYPT + TRUE + SIGN + Topic1 + + true + + true + + + + + + +------988CFBB47A225358D7A5B33A4CA9AD64 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAyWjAvBgkqhkiG9w0BCQQxIgQg9ZheySVcKVr9eNKQTeuBdR0z +Cbgnm4HbSvO8/V0a7CAwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBACn66JQOghwlIQUMDQ0s +vMCGMl7OcZtxDdNQ2BYajufv+JGaf46xP6TWk4+c+bDq+9XTDFoTr/KY2XP7vKVD +RSAm9nlqChzzsKF/7yYdzOP8hILF644PT837mP+E5ss4EYPoPByQLVPWr1B52xWB +N/kixmZcMxe4btXqE8LGlSsPNioniZsDBRlDOcdFjxTL/3Ksgv6fX2gSEJgYVBH/ +xZ+Cpf4TsdtVDrQwUynck1+BogRtcofnkBFuKozqzwvzDQoLfW2fMnct5Jd7KPwM +6kN/bRvOEMGYTKYRgfJVdM4rZqbfdRlVnCj+pza4dIHmf5BDSOlsbRqWyJPRmQ8S +JkM= + +------988CFBB47A225358D7A5B33A4CA9AD64-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_check_create_participant.xml b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_check_create_participant.xml new file mode 100644 index 0000000..37749a3 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_check_create_participant.xml @@ -0,0 +1,147 @@ + + + + + + + 1 + + 1 + NONE + SIGN + ENCRYPT + + TRUE + + + + FALSE + ENCRYPT + TRUE + SIGN + Topic1 + + true + + true + + + FALSE + ENCRYPT + TRUE + SIGN + Topic2 + + true + + true + + + + + + + 2 + + 1 + NONE + SIGN + ENCRYPT + + TRUE + + + + FALSE + ENCRYPT + TRUE + SIGN + Topic1 + + true + + false + + + FALSE + ENCRYPT + TRUE + SIGN + Topic2 + + true + + true + + + + + + + 3 + + 1 + NONE + SIGN + ENCRYPT + + TRUE + + + + FALSE + ENCRYPT + TRUE + SIGN + Topic1 + + false + + false + + + FALSE + ENCRYPT + TRUE + SIGN + Topic2 + + false + + false + + + + + + + 4 + + 1 + NONE + SIGN + ENCRYPT + + FALSE + + + + FALSE + ENCRYPT + TRUE + SIGN + Topic1 + + true + + true + + + + + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_full.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_full.p7s new file mode 100644 index 0000000..4ea8fe8 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_full.p7s @@ -0,0 +1,267 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----05DBD6F6E587875751A79EAC78048D60" + +This is an S/MIME signed message + +------05DBD6F6E587875751A79EAC78048D60 +Content-Type: text/plain + + + + + + + + 20 + + 0 + 23 + + + 100 + 120 + + 200 + + + + false + + + TRUE + + + SIGN_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + + + + OwnShip?ata + + + FALSE + + + false + + + false + + + true + + + SIGN + + + ENCRYPT + + + + + Kinematics + + + true + + + true + + + true + + + false + + + NONE + + + NONE + + + + + *other + + + true + + + true + + + true + + + true + + + NONE + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT + + + + + + + + 100 + 120 + + 20 + + 0 + 23 + + 200 + 30 + + + + 1 + + + 0 + + + SIGN + + + ENCRYPT + + + NONE + + + + + OwnShipData + + + true + + + true + + + false + + + false + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT + + + + + + + + +------05DBD6F6E587875751A79EAC78048D60 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQg0GyBZYdNlmQT2Nv1CHrUEB6+ +C0U0yXvpmj5+mlGojPAwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAJXrVHO7KdgYM20uGGNL +P4VRPmYVWoWIkl5/OEzZ8uirs+oGJR7tYLiFl1wzXUzPBB/03qsANmlshDpFgbmV +thTV7AGRg3SXUDa/cG4N9PupE5VRZaVdbcbdH1DfoIZCLLp4HK3HgqUXkH9vnC92 +tdtgzxZOCrQ4A6WbGiBkWr5LtMWg2lnwPp55vrfRoh6u0qVEumD+VQi+Lroo9M1E +659LB2dwEcNb1g1HyoodpKlUSsbGsY/JA7bbNrw/KIGVYcoXfmpgWmtzUjfpkPDj +zVPImqr6jdxP4quGmGWRmrLHPrEYJscJqCwjNTi6naXnAvaE4nxQ4HBgveEodTuP +8tM= + +------05DBD6F6E587875751A79EAC78048D60-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_full.xml b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_full.xml new file mode 100644 index 0000000..4ff15ab --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_full.xml @@ -0,0 +1,215 @@ + + + + + + + 20 + + 0 + 23 + + + 100 + 120 + + 200 + + + + false + + + TRUE + + + SIGN_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + + + + OwnShip?ata + + + FALSE + + + false + + + false + + + true + + + SIGN + + + ENCRYPT + + + + + Kinematics + + + true + + + true + + + true + + + false + + + NONE + + + NONE + + + + + *other + + + true + + + true + + + true + + + true + + + NONE + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT + + + + + + + + 100 + 120 + + 20 + + 0 + 23 + + 200 + 30 + + + + 1 + + + 0 + + + SIGN + + + ENCRYPT + + + NONE + + + + + OwnShipData + + + true + + + true + + + false + + + false + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT + + + + + + + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_invalid_data.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_invalid_data.p7s new file mode 100644 index 0000000..ba75bfe --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_invalid_data.p7s @@ -0,0 +1,175 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----1A6607CDB3CA97628720C3874B28523D" + +This is an S/MIME signed message + +------1A6607CDB3CA97628720C3874B28523D +Content-Type: text/plain + + + + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + false + + + TRUE + + + SIGN_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + + + * + + + true + + + true + + + false + + + false + + + ENCRYPT_WITH_ + + + ENCRYPT + + + + + OwnShip?ata + + + FALSE + + + false + + + false + + + true + + + SIGN + + + ENCRYPT + + + + + Kinematics + + + true + + + true + + + true + + + false + + + NONE + + + NONE + + + + + + +------1A6607CDB3CA97628720C3874B28523D +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQg16RVkhnhbWczLVFXDHVD6lPy +G5w7StRkpXgPtz/r+5MwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAJsBPV85r3vm0jr/YWKo +J1j054f+gdqnrfH9kv6dvhg/IAK67mfWDHYUUah6D/1HFJve5KMR8tBu2j770M42 +rDjUBVQADqwWc+9ymiGcIjav9r1+YVTzOCHZnASJyqWPakCwwrdMthb2bB//ASmL +rHOxsJZs68r0ci8ZC4bPbe0m8gAC8lkAvfhIr0/WLO4zhdhVaSrKNKptEjTVGRan +KcjoHAiNOhxWZfwZ+OVEp6Rnax4xcpGK3oyCcg9v8zGKj9rDX917K3VfW9Guo+Px +fZ1u+ukL2GgvzPMdJuU0Uw6mPbWMPeAKbIFwLR9P8iXtKuj2HHqteFVbcyIQXZSE +nRM= + +------1A6607CDB3CA97628720C3874B28523D-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_invalid_data.xml b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_invalid_data.xml new file mode 100644 index 0000000..d445705 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_invalid_data.xml @@ -0,0 +1,123 @@ + + + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + false + + + TRUE + + + SIGN_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + + + * + + + true + + + true + + + false + + + false + + + ENCRYPT_WITH_ + + + ENCRYPT + + + + + OwnShip?ata + + + FALSE + + + false + + + false + + + true + + + SIGN + + + ENCRYPT + + + + + Kinematics + + + true + + + true + + + true + + + false + + + NONE + + + NONE + + + + + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_invalid_element.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_invalid_element.p7s new file mode 100644 index 0000000..9a51a3f --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_invalid_element.p7s @@ -0,0 +1,178 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----4B1AFE4A648D807454B86C7DDD6F392C" + +This is an S/MIME signed message + +------4B1AFE4A648D807454B86C7DDD6F392C +Content-Type: text/plain + + + + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + false + + + TRUE + + + SIGN_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT + + Unidentified Flying Object + + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + + + * + + + true + + + true + + + false + + + false + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT + + + + + OwnShip?ata + + + FALSE + + + false + + + false + + + true + + + SIGN + + + ENCRYPT + + + + + Kinematics + + + true + + + true + + + true + + + false + + + NONE + + + NONE + + + + + + +------4B1AFE4A648D807454B86C7DDD6F392C +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgLhPNfJcKb6QszZuyFWmmLGOQ +ZDTY0NBpcqMym1+AijAwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBABwNsFseYbpH+mGslN/g +UY1RNq8f9pFOhTn89NAu94xJgZ2wu5izmSsaEK8K8nrPnxTouD7b5P5w5JQnEVU5 +m2yDD62ZdrlNm51u6VS1JoleHleTEyseagVYlLk+R2FYIH8xfjT0e6jc93qIlm+f +XehwwbCsVUUdy3ViV9APoFP6b5YB+bXe6AtMMTobhEzplqs7GzOFzzC4YuhHSvi2 +sVFXmlHFwOKKIS7he8467breo+SYunv5IttcyqypltydmEcOndCQ2uAWiPvsJIat +DyIkewjrWFL/0l/uTDmk3EUcTmmugVkhykmkfb9subqMHXKbDkcXgZgggR57/9+n +eOU= + +------4B1AFE4A648D807454B86C7DDD6F392C-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_invalid_element.xml b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_invalid_element.xml new file mode 100644 index 0000000..81f5ea6 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_invalid_element.xml @@ -0,0 +1,126 @@ + + + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + false + + + TRUE + + + SIGN_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT + + Unidentified Flying Object + + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + + + * + + + true + + + true + + + false + + + false + + + ENCRYPT_WITH_ORIGIN_AUTHENTICATION + + + ENCRYPT + + + + + OwnShip?ata + + + FALSE + + + false + + + false + + + true + + + SIGN + + + ENCRYPT + + + + + Kinematics + + + true + + + true + + + true + + + false + + + NONE + + + NONE + + + + + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_not_signed.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_not_signed.p7s new file mode 100644 index 0000000..30fa20a --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_not_signed.p7s @@ -0,0 +1,62 @@ + + + + + + + + 0 + 230 + + + + + false + + + true + + + ENCRYPT + + + ENCRYPT + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + ENCRYPT + + + ENCRYPT + + + + + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_ok.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_ok.p7s new file mode 100644 index 0000000..c39903f --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_ok.p7s @@ -0,0 +1,114 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----DB94A190D9780A24156FB0E8F1E76B5F" + +This is an S/MIME signed message + +------DB94A190D9780A24156FB0E8F1E76B5F +Content-Type: text/plain + + + + + + + + + 0 + 230 + + + + + false + + + true + + + ENCRYPT + + + ENCRYPT + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + ENCRYPT + + + ENCRYPT + + + + + + +------DB94A190D9780A24156FB0E8F1E76B5F +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGSAYJKoZIhvcNAQcCoIIGOTCCBjUCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCAnswggJ3AgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggeQwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTgwOTEzMDczOTUwWjAvBgkqhkiG9w0BCQQxIgQgXv8DkvlwebXMwHDbNc0/Pc30 +gyG3xWCnwet49TRMWFsweQYJKoZIhvcNAQkPMWwwajALBglghkgBZQMEASowCwYJ +YIZIAWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG9w0DAgIC +AIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwDQYJKoZI +hvcNAQEBBQAEggEANy8t0EFmv5j1n0+mMn2ut3Chu8PSJceC8gd34IiKq79uC1O3 +PbL9xgiJ2vz7QiTEEeNL2q+CG77cXOcHGUWa4nvbggr/9CqLfHEKGQxDfyXlJZfM +8l550xIXRRBOQ7ilOGLD4QJFfbf9XA4rMuRe8WEYN3FleAaYBJag1tMPg1SS6tgA +BBDM9b1kXHU319zYOk6kZFjlbwHv6XO22SEVRUpXrKudAI8hrGvwksF/+W0S/jS5 +NmYtj/1oMGlCGIaA5rs27H9CkgwrzoMQ3MsR98JlwEUSa4PEe8CClsIziOulQxsp +MicBlMWL0rzpBPVfPTE4gZ/kP7hGBDEQlRzVTA== + +------DB94A190D9780A24156FB0E8F1E76B5F-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_unknown_ca.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_unknown_ca.p7s new file mode 100644 index 0000000..9f07e40 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Governance_unknown_ca.p7s @@ -0,0 +1,117 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----F38FD3F34A584E774726CA12090D0B48" + +This is an S/MIME signed message + +------F38FD3F34A584E774726CA12090D0B48 +Content-Type: text/plain + + + + + + + + + 0 + 230 + + + + + false + + + true + + + ENCRYPT + + + ENCRYPT + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + ENCRYPT + + + ENCRYPT + + + + + + +------F38FD3F34A584E774726CA12090D0B48 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGywYJKoZIhvcNAQcCoIIGvDCCBrgCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggPKMIIDxjCCAq4CCQCBuTktP0h8BDANBgkqhkiG9w0BAQsFADCB +pDEWMBQGA1UEBwwNTG9jYWxpdHkgTmFtZTEhMB8GA1UECwwYT3JnYW5pemF0aW9u +YWwgVW5pdCBOYW1lMRwwGgYJKoZIhvcNAQkBFg1FbWFpbCBBZGRyZXNzMQswCQYD +VQQGEwJVUzELMAkGA1UECAwCTkoxGjAYBgNVBAoMEUV4YW1wbGUgU2lnbmVyIENB +MRMwEQYDVQQDDApFeGFtcGxlIENBMB4XDTE4MDgxNTA4NTE0MVoXDTQzMDgwOTA4 +NTE0MVowgaQxFjAUBgNVBAcMDUxvY2FsaXR5IE5hbWUxITAfBgNVBAsMGE9yZ2Fu +aXphdGlvbmFsIFVuaXQgTmFtZTEcMBoGCSqGSIb3DQEJARYNRW1haWwgQWRkcmVz +czELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5KMRowGAYDVQQKDBFFeGFtcGxlIFNp +Z25lciBDQTETMBEGA1UEAwwKRXhhbXBsZSBDQTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALStAQ0yjM2qAWwsOXdX3hiyoZ6DDHWOTNI5LoCZGaN9rUZe +MY0waSxWNQ0ruURgZISeOFkdQTAE81Em+UaZI+MZvfYcEcSlVtF6yve/WnIzRYWu +f917moMCAInktfch4E6mskr4h7n+9sEz+3GsQS8SQRtwUe+PiXzjZrqHSbLC4Kn3 +/b8Mt+Ww3a4FyjHDZQJZsGSvrScr0Gq3xeKfMwb+KYNEnmh0o4os0gEGA4KUR+/1 +YDl1NmxQnm/AIMqwJzeaezBoMn0Nsi+OlAms85imGURNj9BCEJZBWwuuNL5ECDAq +WLOM3AKUsApVgtGd8/OLWW1RwYkW8uqTtkIR87MCAwEAATANBgkqhkiG9w0BAQsF +AAOCAQEAokKC77/kvxlObLSwkT5+7+S+DeznLBRiGVEh8+9PQw1q91sjiOZWf0e3 +T3XPH7CR/NDYoQJkrsqzIwKYrj41z/1jAs+HkH45NpTFiGlUFXNs5iwNh4RUqgf4 +e78Mge4q7pHMFzWTEwEn4DJMGcDDjLW1kN8GobGwHR7O0MpAJKrqcBSo+SPomnQv +TgiEMQ+Vlz0EJx6JPsq8c7HrxlSdeDAAWIOww/wcGyzlpYEoyz6voSSfdhMt5iy5 +k5BvhBJnTiJTasCHy9KRuis/6qpTZKEj0d7J7LAqpGh8oRIphMwCbFYQT0QBgV6p +gM8Ufss/RZ6CshMNxz7KtIYpvmxPPTGCAsUwggLBAgEBMIGyMIGkMRYwFAYDVQQH +DA1Mb2NhbGl0eSBOYW1lMSEwHwYDVQQLDBhPcmdhbml6YXRpb25hbCBVbml0IE5h +bWUxHDAaBgkqhkiG9w0BCQEWDUVtYWlsIEFkZHJlc3MxCzAJBgNVBAYTAlVTMQsw +CQYDVQQIDAJOSjEaMBgGA1UECgwRRXhhbXBsZSBTaWduZXIgQ0ExEzARBgNVBAMM +CkV4YW1wbGUgQ0ECCQCBuTktP0h8BDANBglghkgBZQMEAgEFAKCB5DAYBgkqhkiG +9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xODA5MTMwOTIyMzha +MC8GCSqGSIb3DQEJBDEiBCBe/wOS+XB5tczAcNs1zT89zfSDIbfFYKfB63j1NExY +WzB5BgkqhkiG9w0BCQ8xbDBqMAsGCWCGSAFlAwQBKjALBglghkgBZQMEARYwCwYJ +YIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqGSIb3DQMCAgIAgDANBggqhkiG9w0D +AgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIBKDANBgkqhkiG9w0BAQEFAASCAQAy +baJVxRJcZ3wYtb/TfQUDKNmaz7pYWNoKNxkPyKUerMOAZ9n0yvySNJUpzG+kJJNi +Ib792GXdmP4hdz4qC4Zx3S7H26OAYcOsTwd6+O/xcv8H7PQoPD+3fplhIvLtpIlS +//9ghpBXbUowdgzeDrYBpzRLqUth58IxsHd9cJQCCboKZIv8+6eP9fn1OD/CLGV3 +BNMvmeP88LU8UgtiivmmEJZ0fRtDVAGRIWykT1AvTfl69Pv9VKDuUW3qkuMwz7lW +Dv0c624BYPbQWdU7W5//iy4kSfwrtXtag7aovUbcwkmb2qb5v5c5ZqNoLPUvUpIG +KZUh0/aBuBovjwHZMcgl + +------F38FD3F34A584E774726CA12090D0B48-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_ca.pem b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_ca.pem new file mode 100644 index 0000000..2372ae0 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_ca.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV +BAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQKDBZBRExJTksgVGVj +aG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNvbTAgFw0xODA3MzAx +MjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMCTkwxEzARBgNVBAgM +ClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4xFzAV +BgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blIDehV6XCxrnGXusTCD +uFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9wicp3BGSpZZax/TcO +NjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLsDFFC+a0qn2RFh37r +cWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074BRDXVivx+wVD951L +FNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiySogRWAmKhysLQudu +kHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNVHQ4EFgQURWMbWvBK +ZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJvRV1/tyc1R82k0+gw +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ysVtvHnk2hpu9yND +LCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9XVh0rGoR/6nHzo3TI +eiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9yghhKHHqNDvSsAL0 +KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbtlLX3QnwVOmaRyzyl +PiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42+OyLqcH1rKT6Xhcs +hjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb6SDB340BFmtgDHbF +HQ== +-----END CERTIFICATE----- diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_ca_key.pem b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_ca_key.pem new file mode 100644 index 0000000..22fac8b --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_ca_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blIDehV6XCxr +nGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9wicp3BGSp +ZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLsDFFC+a0q +n2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074BRDXVivx ++wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiySogRWAmK +hysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABAoIBABWqhMSCr+7Mr3O3 +bIymOr+CT4xWI8S47hmKGFCLTrNsfy7cQZ9PdHkm7Ez+rCx+KwQaTrwz7EM/e8aH +q2zimMn4YXxeS7MFdM+Xvp/Y0BhXMd1j8Nk0x14+WHmQ88YfA4szdrHDekR+6oB6 +5Lc2fAfNbCGdpRksCQWDndrvIOda1swKW1RsGWHPGtSM1qOg09A4CeASqbsxZfdL +9MgI7aJKYnvJrUhqsNZU3fuOrLDNl7/JvdI08nYLnNkEvbDYbdfH0Q/4laKsSJcp +0jM6tPrxbHMDmBEwullVPrVqJX+n6Hvz3E8C9QiZq8NWbJUc5FntLx8ynbiJg6Lb +1w49WxECgYEA8yVky++3v0ZMKZeSeGj3MuKuEJ2q3UdmsKXA+Pyq0rL/hh7r2oUY +dQDs23BIuaHeIZxAGaMeMjoYQBi+G50XfwHZSMqivxX/yYkXxOJfPQvVLDbqCIWS +94qU4/xo50IkCNxpvRwfpKG2ce5YG7jrQkfb5I6TfKUWAaXpmaQnbYsCgYEAxaVn +Hzw3OdY7q6kURSY6a8KqtcuN0lNKeUb68vZemmZ0FNKmyh+xGVFXXlvmJpQgr5Zm +2W2a1C1oPq2DEdvSKt/aTHVIazG9TtFK1WAXpLxmlXlyqWRv+IvdVkph+p/3dIT0 +Ilaglgbndth4xk0c1zqy3g4VlAgWgKKi5owZ/j8CgYEAndsFGbHEJZZKFCannSzo +cEzinT7/kzGr5bt3ES9Y5/n2Euk4TmJignPbUowPaxU/1apPo1VXYVx+Kf7mTZ8r +hfV5T9ze1BhAPGOY3uXo1wU7nLz6LBYsWDHMgEd7A8jZBDe1HmWH1aZ3gHgxE652 +bk2g4T3/WskDBIbmpi0AvAkCgYBKAfFnRMj5IzscwCcS7YmaqD377MiiJQYR+34k +VBSAhDSbR3Wk4dESxd6NOqQndff3R74jVGNRZ99M+PPHUCSWYVQApToEyY81YDFB +TMYNrW5MMjm5LB6xVs3+bcPacOPcAZzY7s8a3mL1oYE339AY16X6eBOkZpLmf/+3 +jGZ/SQKBgQDkyxymL4xJGV8HCDontJZiBStD954GH1AgqEAOdQxU5vW4ySQ7yRoT +ajb8tH052yWW11Mxd0TRW9qbVI0/4/4lR86sODYLFbgrHAMBl7mxJ8Qwi4zdI9Am +FXGkj5SX2bYrf2f0YvCHNUbELTd4mF6kAH0Eg6kHRXLsSbhtWC7D3Q== +-----END RSA PRIVATE KEY----- diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_expired.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_expired.p7s new file mode 100644 index 0000000..bf35bf7 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_expired.p7s @@ -0,0 +1,243 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----11798C99B4C31493D0479BB8A2064C72" + +This is an S/MIME signed message + +------11798C99B4C31493D0479BB8A2064C72 +Content-Type: text/plain + + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2016-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=Spare cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + ALLOW + + + + +------11798C99B4C31493D0479BB8A2064C72 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgXPEkUvQgZwRMdZgxT8k/mrsJ +delB0E3RjpayHUkKYzowgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAA/TNULF62fO5mfjXm1L +Yk4Dg/5ZxAF/grDAjamo5v2fxGn6B1rrkj8YtyB1FEA0moM/cL31kNXNMqLvFdhY +lHCmX8x5PHkKzLihTIMx6diSCupBvvqUACeA7Ir1A3tMqW5tYYMg6sZ/YolgLLFG +8XmhttpEibtZm90MN3Xpsa4TiW5PlEWHC5ai3tyeyd/RCVoeQJVA0pAytmjdf2Mw +C3W/28tUxVCAjdlqXYap6jWZlNv/43P5HED837bF5iqoa1dTvDirca6WPanNjp28 +GQDi4bnD1kAk8wAKIm14qwS+fzxM3SKxJtdQuUCx+s/tPma4bLCqt843ok35SoWo +QKM= + +------11798C99B4C31493D0479BB8A2064C72-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_expired.xml b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_expired.xml new file mode 100644 index 0000000..f408942 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_expired.xml @@ -0,0 +1,191 @@ + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2016-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=Spare cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + ALLOW + + + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_full.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_full.p7s new file mode 100644 index 0000000..a8e71c1 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_full.p7s @@ -0,0 +1,243 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----D2957343698C311655D075C56A04A68D" + +This is an S/MIME signed message + +------D2957343698C311655D075C56A04A68D +Content-Type: text/plain + + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=Spare cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + ALLOW + + + + +------D2957343698C311655D075C56A04A68D +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgcYMSlCRiboSPUqMbBIKL7lBv +QJlEFiHrJ5t/aOJZbi0wgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAJsR4q4Eeorhd4sQaw+D +PErzkTuI1PEDzv2oYy3U/w4ZdGF2TJQqZ/OqiKEtmwqVAKfuPb9XQLPSENtn2uZC +wz9ZcvMJ4/GOOMWezN6J65pfuAeEWa0oGCcAASl7tuk+QpAK3MY8L5hxCPb6sfr9 +jslfMqJ+WYgrOVuqWMAYZoXwIgJ1GdREXOXoCnyEkwy6Prk6NhSDO6Jl91PxcZWG +ZITu7y/mklX8cSx09MNyOfefFhCIfNnXGJu0HUTYluTFd1LgRan6f0uyPR2zBLlE +qzuaetvpNlUclf8dywlazI8oRjfrusYo3tiKG+hHkjrXc7WHOh+I08Tqeyue+0tg +cjw= + +------D2957343698C311655D075C56A04A68D-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_full.xml b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_full.xml new file mode 100644 index 0000000..0be3fa2 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_full.xml @@ -0,0 +1,191 @@ + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=Spare cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + ALLOW + + + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_invalid_data.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_invalid_data.p7s new file mode 100644 index 0000000..b3b969e --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_invalid_data.p7s @@ -0,0 +1,219 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----62BE4CE8CF1FCB0420A2F2884B1618E6" + +This is an S/MIME signed message + +------62BE4CE8CF1FCB0420A2F2884B1618E6 +Content-Type: text/plain + + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 430 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + + +------62BE4CE8CF1FCB0420A2F2884B1618E6 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQghoicue+FOmdIHF9rpsNCfmjP ++ZyN+t9kCdmR68JCJU0wgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAI0BX2tu2DbQjvuzKG35 +myNBcOC9ZzRDqJEtmQhcY/2hAJzurlnclJVTEXFyXdpV4ywtA+lQvbtToh11AvnY +IY1QWNVm19mfO1J6m6PFu18tizd30sG7p1TZKxGB3zDeVVqmedZ+o7QJHv9/ixzz +Pyo2B9tG5Su94+ADc0LQNyGICjeMr7L6dhFDsm7fXBi8pMBKy/zEAynTA3r1ibsn +5zlizPMlad2HCaYv44x7Xksg9FSbzJwJpTiprbQbZSUPYk4WlfVz0l4plzRKu4AP +lCOsdRE6C6GQFnK5bLyndu3Ycp10niwfkfobruCDyigu+gjZtmmF/T7A8Xkk1uvx +fAM= + +------62BE4CE8CF1FCB0420A2F2884B1618E6-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_invalid_data.xml b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_invalid_data.xml new file mode 100644 index 0000000..5ebb397 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_invalid_data.xml @@ -0,0 +1,167 @@ + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 430 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_invalid_element.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_invalid_element.p7s new file mode 100644 index 0000000..521f4cf --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_invalid_element.p7s @@ -0,0 +1,219 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----3EE420429594FF1492D49B1EEBFBAF0E" + +This is an S/MIME signed message + +------3EE420429594FF1492D49B1EEBFBAF0E +Content-Type: text/plain + + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + + +------3EE420429594FF1492D49B1EEBFBAF0E +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgk4Y6Rw4+DVfETNs8Ddv6rnhK +w7EwwZ9nE7SiujxSsDEwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAGkiiP+V49XZIwqbpqwN +RHv0tn06/BAuRGNybse1GkVzlNmuwbGObUUpKtKh4VxN8XuTfH5uuLEqftN2LvGG +zEiyosHX0gjsX6hihqoIcbfdsKpxd/OPCr/iNdOKWCSyV0aqaP3fc9Y2L1xVdXfn +avjfd8wief+ERfwKlsbHYsgh6/zwhVeMt2mzr8T0c+ICC99+XXmSvpnGJ89amYub +NnQwdxTp4PBQhudXixG3LrZ1CZafoLRz+x9vEIVF9oFyy7kMkeFtjd7aXc346Ama +djOu1LtzvWZKOMeGYVaSiQMl4HhpOh/embx+AClH/Hf1o7AA+ivF8vZgUDAAK2GD +rx8= + +------3EE420429594FF1492D49B1EEBFBAF0E-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_invalid_element.xml b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_invalid_element.xml new file mode 100644 index 0000000..6f38953 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_invalid_element.xml @@ -0,0 +1,167 @@ + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_lack_of_not_after.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_lack_of_not_after.p7s new file mode 100644 index 0000000..804f556 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_lack_of_not_after.p7s @@ -0,0 +1,95 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----E9994989EF5BC12DCCE6563CF088037D" + +This is an S/MIME signed message + +------E9994989EF5BC12DCCE6563CF088037D +Content-Type: text/plain + + + + + + /O=Internet Widgits Pty Ltd/ST=Some-State/C=NL/CN=CHAM500 cert + + + 2015-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + + + ALLOW + + + + +------E9994989EF5BC12DCCE6563CF088037D +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgVn6yZWB0OOqW+6/ubhU1M4pT +tL+lh8qj9izsf/c3gKMwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAKhwx+Ew2m6lHQxL0I0K +Z0fdN8+19XGKYPWNuGwDR5MYpMX5jin/w/FgzeG5gSHqB51PRLJjH81incNVcRCf +bRKvwOv8b4J8D14ZG28SoNCsKejbXccFuA967ir+GHYrh0V9ikM/TwPuhosxclM5 +hZQuvRKig6Fum+PmGO7sLNyIPB1ODE8gbz0IiY9l6Zlp0xEe/+4YYpBL+GKamnlS +boRrfgGaTaWWi9EnjZWmJkFBO9vC08XZQ1akCubC0G8Kki0X3ZXJVXkX3AxjvZJY +XDdstpKWbfqlWzkYlJSI/I96BO2ZXY7nnsQU+8tvPV/6k6BaC80m0FhoTQJfDdLR +WnA= + +------E9994989EF5BC12DCCE6563CF088037D-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_lack_of_not_after.xml b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_lack_of_not_after.xml new file mode 100644 index 0000000..27e5fb9 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_lack_of_not_after.xml @@ -0,0 +1,43 @@ + + + + + /O=Internet Widgits Pty Ltd/ST=Some-State/C=NL/CN=CHAM500 cert + + + 2015-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + + + ALLOW + + + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_lack_of_not_before.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_lack_of_not_before.p7s new file mode 100644 index 0000000..a21bac6 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_lack_of_not_before.p7s @@ -0,0 +1,95 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----E0088C6C0B487BC746E35E87718DA89E" + +This is an S/MIME signed message + +------E0088C6C0B487BC746E35E87718DA89E +Content-Type: text/plain + + + + + + /O=Internet Widgits Pty Ltd/ST=Some-State/C=NL/CN=CHAM500 cert + + + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + + + ALLOW + + + + +------E0088C6C0B487BC746E35E87718DA89E +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgOCgkm0Mu6pRSDhlMd5/7OGhr +3TedLdpw5DQNC60vDgYwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBALYwxGivvBYfCdRADnYd +ysgBOITPhEY+TqqqEtiX4cIyeEdZGMFxcciMxbXVB1qy7js7PM+tbZ/+ICutyA7J +dkU9cNO9hLM/LYASv9B9zpgxMecYcA9rx7OEpM3Sr2eXOTbu2j3gUoCun7y8f+yv +iiYUORa0cX8oFnq++rQXHE/0rOVd17tboLvsy97Tro8o1e7WFA2gkJsCyo4QF+Lg +yz8IKdKMIRLpEl07bGIcIq4gvarQnN3qT1KuOMrDQD29CFZMwCO/TSGVeZYRHdW9 +s1hhmrTlkmlhPyXG9yxm9PH9UHZyfhkbrhIXZtN6M/7SO8VfTMfotyTbFtuatzzL +fz4= + +------E0088C6C0B487BC746E35E87718DA89E-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_lack_of_not_before.xml b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_lack_of_not_before.xml new file mode 100644 index 0000000..6c3f892 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_lack_of_not_before.xml @@ -0,0 +1,43 @@ + + + + + /O=Internet Widgits Pty Ltd/ST=Some-State/C=NL/CN=CHAM500 cert + + + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + + + ALLOW + + + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_not_signed.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_not_signed.p7s new file mode 100644 index 0000000..8759d91 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_not_signed.p7s @@ -0,0 +1,33 @@ + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + + + * + + + + DENY + + + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_notyet.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_notyet.p7s new file mode 100644 index 0000000..7fd4098 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_notyet.p7s @@ -0,0 +1,243 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----F87E07CA6CCEAB50B03A143AC2354EB4" + +This is an S/MIME signed message + +------F87E07CA6CCEAB50B03A143AC2354EB4 +Content-Type: text/plain + + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2035-09-15T01:00:00 + 2046-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=Spare cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + ALLOW + + + + +------F87E07CA6CCEAB50B03A143AC2354EB4 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQg0GGu1gWhHWhfWnmg55AIr4tv +zMK0kIxNfJYQbb7LpJ8wgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBALsPI2+b0w+iUPJGJeMd +VdrY7s/GZYm6M8qOA5fmh3144bY1rZRjdHjXtLdaNDNN1Z5buRCiQcklAilf6O14 +7u6a5HR12N4LTbg3OYQplwz4ed/wBsL726htmkAK3JogGk5OVLqmmdrz3UOD8IaZ +wAfx2tpj3VJOVuW0XsqOrzQpnOjGWcPeOw6NAxRH1gLsxBP9HDz5+wrsKXjV/zG8 +dFTaZ0bKnBXTp5ccc9jB4qbcllC9nlJkJszGqvwOP7zWBAOXeU+joUGM4Bt+8Pmt +pKsVAmEqMpc368RMayDBWtTqUWpUKvDh4HSkuOGD4Hj5ViAoLFjisROhIK2d98XI +cRQ= + +------F87E07CA6CCEAB50B03A143AC2354EB4-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_notyet.xml b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_notyet.xml new file mode 100644 index 0000000..99fec50 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_notyet.xml @@ -0,0 +1,191 @@ + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2035-09-15T01:00:00 + 2046-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=Spare cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + ALLOW + + + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_ok.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_ok.p7s new file mode 100644 index 0000000..052075b --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_ok.p7s @@ -0,0 +1,85 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----6B91005B007BBA8EDE10CD1CE487DB27" + +This is an S/MIME signed message + +------6B91005B007BBA8EDE10CD1CE487DB27 +Content-Type: text/plain + + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + + + * + + + + DENY + + + + +------6B91005B007BBA8EDE10CD1CE487DB27 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgl3LfUhn9L0vG/3QRPVYptcYw +/NH5HMN99aMe9JAT+LAwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAHe9vakfXPvbpgMeqlhG +SW6Z3uVA3Yri9bgQDpJ9daIUsM0/TLBSQVs85twTMXvqUSntKbfSGehxDQ9F+yje +mOEPMIwxOqcVyc2jpqoYsUWqpwiiZyk49DHUFrOfWJUx+rKdBftZWkxD05Wkovhk +2d4hGS/65Haoho4Z0AZwcyH+F52FZMiqw7I9FKrPlhxvJfQXmhIjOKtnvWnQ+Ar7 +YYiSrBEHMCy82LF1aKzz0nkL1SYWQHuQX475qoU4LMYY1J8WsD3rSBeq4GYZrl2K +X/JcOquMYqjfJLMYZY4fsc3FgEBkKNqJz1tDZ3ir24VMl+WsbEjVK8oXe/wt4V0U +aNQ= + +------6B91005B007BBA8EDE10CD1CE487DB27-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_ok.xml b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_ok.xml new file mode 100644 index 0000000..8759d91 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_ok.xml @@ -0,0 +1,33 @@ + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + + + * + + + + DENY + + + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_unknown_ca.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_unknown_ca.p7s new file mode 100644 index 0000000..6a2905a --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_unknown_ca.p7s @@ -0,0 +1,87 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----7FBACED8776E5A4CF7612C83F9C33E17" + +This is an S/MIME signed message + +------7FBACED8776E5A4CF7612C83F9C33E17 +Content-Type: text/plain + + + + + + /C=NL/ST=Some-State/O=ADLINK Technolocy Inc./CN=adlinktech.com + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + + + * + + + + DENY + + + + +------7FBACED8776E5A4CF7612C83F9C33E17 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGywYJKoZIhvcNAQcCoIIGvDCCBrgCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggPKMIIDxjCCAq4CCQCBuTktP0h8BDANBgkqhkiG9w0BAQsFADCB +pDEWMBQGA1UEBwwNTG9jYWxpdHkgTmFtZTEhMB8GA1UECwwYT3JnYW5pemF0aW9u +YWwgVW5pdCBOYW1lMRwwGgYJKoZIhvcNAQkBFg1FbWFpbCBBZGRyZXNzMQswCQYD +VQQGEwJVUzELMAkGA1UECAwCTkoxGjAYBgNVBAoMEUV4YW1wbGUgU2lnbmVyIENB +MRMwEQYDVQQDDApFeGFtcGxlIENBMB4XDTE4MDgxNTA4NTE0MVoXDTQzMDgwOTA4 +NTE0MVowgaQxFjAUBgNVBAcMDUxvY2FsaXR5IE5hbWUxITAfBgNVBAsMGE9yZ2Fu +aXphdGlvbmFsIFVuaXQgTmFtZTEcMBoGCSqGSIb3DQEJARYNRW1haWwgQWRkcmVz +czELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5KMRowGAYDVQQKDBFFeGFtcGxlIFNp +Z25lciBDQTETMBEGA1UEAwwKRXhhbXBsZSBDQTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALStAQ0yjM2qAWwsOXdX3hiyoZ6DDHWOTNI5LoCZGaN9rUZe +MY0waSxWNQ0ruURgZISeOFkdQTAE81Em+UaZI+MZvfYcEcSlVtF6yve/WnIzRYWu +f917moMCAInktfch4E6mskr4h7n+9sEz+3GsQS8SQRtwUe+PiXzjZrqHSbLC4Kn3 +/b8Mt+Ww3a4FyjHDZQJZsGSvrScr0Gq3xeKfMwb+KYNEnmh0o4os0gEGA4KUR+/1 +YDl1NmxQnm/AIMqwJzeaezBoMn0Nsi+OlAms85imGURNj9BCEJZBWwuuNL5ECDAq +WLOM3AKUsApVgtGd8/OLWW1RwYkW8uqTtkIR87MCAwEAATANBgkqhkiG9w0BAQsF +AAOCAQEAokKC77/kvxlObLSwkT5+7+S+DeznLBRiGVEh8+9PQw1q91sjiOZWf0e3 +T3XPH7CR/NDYoQJkrsqzIwKYrj41z/1jAs+HkH45NpTFiGlUFXNs5iwNh4RUqgf4 +e78Mge4q7pHMFzWTEwEn4DJMGcDDjLW1kN8GobGwHR7O0MpAJKrqcBSo+SPomnQv +TgiEMQ+Vlz0EJx6JPsq8c7HrxlSdeDAAWIOww/wcGyzlpYEoyz6voSSfdhMt5iy5 +k5BvhBJnTiJTasCHy9KRuis/6qpTZKEj0d7J7LAqpGh8oRIphMwCbFYQT0QBgV6p +gM8Ufss/RZ6CshMNxz7KtIYpvmxPPTGCAsUwggLBAgEBMIGyMIGkMRYwFAYDVQQH +DA1Mb2NhbGl0eSBOYW1lMSEwHwYDVQQLDBhPcmdhbml6YXRpb25hbCBVbml0IE5h +bWUxHDAaBgkqhkiG9w0BCQEWDUVtYWlsIEFkZHJlc3MxCzAJBgNVBAYTAlVTMQsw +CQYDVQQIDAJOSjEaMBgGA1UECgwRRXhhbXBsZSBTaWduZXIgQ0ExEzARBgNVBAMM +CkV4YW1wbGUgQ0ECCQCBuTktP0h8BDANBglghkgBZQMEAgEFAKCB5DAYBgkqhkiG +9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xODA5MTMwOTIzMDNa +MC8GCSqGSIb3DQEJBDEiBCCvP08gFBO7651mPPDFQ2suhL+eprGCGuRLXmiBmdvx +ITB5BgkqhkiG9w0BCQ8xbDBqMAsGCWCGSAFlAwQBKjALBglghkgBZQMEARYwCwYJ +YIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqGSIb3DQMCAgIAgDANBggqhkiG9w0D +AgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIBKDANBgkqhkiG9w0BAQEFAASCAQB/ +4EQel+0LsmiNFCUjWM68u4ZvPtFBpeDe456DJuG6QR0LIzW42U7N4P2ZTIqjpGZx +YekBCNdkiVy6ER5IA4WfcKd6zXZEuXVxkMrGpJlqGdd+IdZpTsrBygGZJS4vMUfD +/6ty6OycET88RmJIu4V/TM3yLVKzHuj6TxCXb4OIYx8g3mdXUwUrp6DGgqggRSPJ +tatbpnqGZGcvty8MusXVnjnEwUWnJ/jojypY3MyL4MTbjufjv0K6NKQ3RzoLssot +SLq0YDLwvX/s9sLXDCedAwFXBS/6Qv56v0M2x4o8e3Eul7gGTMuCd/dJ0BhF8CW+ +IGxR5I3xXssh/AuWRRtV + +------7FBACED8776E5A4CF7612C83F9C33E17-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_unknown_subject.p7s b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_unknown_subject.p7s new file mode 100644 index 0000000..fb488c7 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_unknown_subject.p7s @@ -0,0 +1,85 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----7B161F9203F175A7F82A389A3E044741" + +This is an S/MIME signed message + +------7B161F9203F175A7F82A389A3E044741 +Content-Type: text/plain + + + + + + gibberish + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + + + * + + + + DENY + + + + +------7B161F9203F175A7F82A389A3E044741 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQg44QSCYJrKGm9hdPbOKQjrnQ8 +LXMSbo0mve1cRKvrm3gwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAH/fJ90OwloC73faPAGC +VRZrhW/gSsy/1VnprvWdDAU1ZZK+srIISFZAy19LcApTis0Vy9yz2PG8pue49R+y +UF6mCDSuN/l9SRBdUN+CXQdQ8sGq5SHXNhGzSX/nbR20ol4cSUMpKlEGx66E0KUW +tkk8HzYw7aHMiwK2E2Y0sbm/M/rdmAbgEoywYfvc25V4FHP66TstfCLBjN9Hz3bH +WcrCZuPjZo6vBd/rIJQSlgH81aCWn5RfCIccbc3iogwzIhYxAr6d+4do3LNa6H80 +W6CMgl0AnWFfa4QwnXFUzb1/W2rFjHp453w1Cbqk4Ll4ZlVJr4fzIuyuJMQlMrmK +1P0= + +------7B161F9203F175A7F82A389A3E044741-- + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_unknown_subject.xml b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_unknown_subject.xml new file mode 100644 index 0000000..8a55faf --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/etc/Test_Permissions_unknown_subject.xml @@ -0,0 +1,33 @@ + + + + + gibberish + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + + + * + + + + DENY + + + diff --git a/src/security/builtin_plugins/tests/validate_local_permissions/src/validate_local_permissions_utests.c b/src/security/builtin_plugins/tests/validate_local_permissions/src/validate_local_permissions_utests.c new file mode 100644 index 0000000..2db3d15 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_local_permissions/src/validate_local_permissions_utests.c @@ -0,0 +1,1018 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/io.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "config_env.h" + +static const char *PROPERTY_IDENTITY_CA = "dds.sec.auth.identity_ca"; +static const char *PROPERTY_PRIVATE_KEY = "dds.sec.auth.private_key"; +static const char *PROPERTY_IDENTITY_CERT = "dds.sec.auth.identity_certificate"; +static const char *PROPERTY_PERMISSIONS_CA = "dds.sec.access.permissions_ca"; +static const char *PROPERTY_PERMISSIONS = "dds.sec.access.permissions"; +static const char *PROPERTY_GOVERNANCE = "dds.sec.access.governance"; + +static const char *RELATIVE_PATH_TO_ETC_DIR = "/validate_local_permissions/etc/"; + +static const char *AUTH_IDENTITY_CERT = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEQTCCAymgAwIBAgIINpuaAAnrQZIwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE3MDIy\n" + "MjIyMjIwMFoYDzIyMjIwMjIyMjIyMjAwWjBcMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRUwEwYDVQQDEwxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n" + "ggEKAoIBAQDCpVhivH/wBIyu74rvQncnSZqKyspN6CvD1pmV9wft5PHhVt9jV79v\n" + "gSub5LADoRHAgFdv9duYgBr17Ob6uRrIY4B18CcrCjhQcC4gjx8y2jl9PeYm+qYD\n" + "3o44FYBrBq0QCnrQgKsb/qX9Z+Mw/VUiw65x68W876LEHQQoEgT4kxSuagwBoVRk\n" + "ePD6fYAKmT4XS3x+O0v+rHESTcsKF6yMadgp7h3eH1b8kJTzSx8JV9Zzq++mxjox\n" + "qhbBVP5nDze2hhSIeCkCvSrx7efkgKS4AQXa5/Z44GiAu1TfXXUqdic9rxwD0edn\n" + "ajNElnZe7sjok/0yuqvH+2hSqpNva/zpAgMBAAGjggEAMIH9MAwGA1UdDwQFAwMH\n" + "/4AwgewGA1UdJQSB5DCB4QYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYI\n" + "KwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3AgEVBgorBgEEAYI3AgEWBgorBgEE\n" + "AYI3CgMBBgorBgEEAYI3CgMDBgorBgEEAYI3CgMEBglghkgBhvhCBAEGCysGAQQB\n" + "gjcKAwQBBggrBgEFBQcDBQYIKwYBBQUHAwYGCCsGAQUFBwMHBggrBgEFBQgCAgYK\n" + "KwYBBAGCNxQCAgYIKwYBBQUHAwkGCCsGAQUFBwMNBggrBgEFBQcDDgYHKwYBBQID\n" + "BTANBgkqhkiG9w0BAQsFAAOCAQEAawdHy0Xw7nTK2ltp91Ion6fJ7hqYuj///zr7\n" + "Adt6uonpDh/xl3esuwcFimIJrJrHujnGkL0nLddRCikmnzuBMNDWS6yq0/Ckl/YG\n" + "yjNr44dlX24wo+MVAgkj3/8CyWDZ3a8kBg9QT3bs2SqbjmhTrXN1DRyf9S5vJysE\n" + "I7V1gTN66BeKL64hOrAlRVrEu8Ds6TWL6Q/YH+61ViZkoLTeSaPjH4nknaFr4C35\n" + "iji0JhkyfRHRRVPHFnaj25AkxOrSV64qVKoTMjDl5fji5iMGtjm6iJ7q05ml/qDl\n" + "nLotHXemZNvYhbwUmRzbt4Dls9EMH4VRbP85I94nM5TAvtHVNA==\n" + "-----END CERTIFICATE-----\n"; + +static const char *AUTH_IDENTITY_CA = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEmTCCA4GgAwIBAgIIZ5gEIUFhO5wwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDIx\n" + "MjE1MDUwMFoYDzIyMjIwMjIyMjIyMjAwWjBfMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRgwFgYDVQQDEw9DSEFNNTAwIHJvb3QgY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" + "DwAwggEKAoIBAQC6Fa3TheL+UrdZCp9GhU/2WbneP2t/avUa3muwDttPxeI2XU9k\n" + "ZjBR95mAXme4SPXHk5+YDN319AqIje3oKhzky/ngvKH2GkoJKYxWnuDBfMEHdViz\n" + "2Q9/xso2ZvH50ukwWa0pfx2/EVV1wRxeQcRd/UVfq3KTJizG0M88mOYvGEAw3LFf\n" + "zef7k1aCuOofQmBvLukUudcYpMzfyHFp7lQqU4CcrrR5RtmfiUfrWfdGLea2iPDB\n" + "pJgN8ESOMwEHtOTEBDclYnH9L4t7CHQz+fXXS5IWFsDK9fCMQjnxDsDVeNrNzTYL\n" + "FaZrMg9S6IUQCEsQWsnq5weS8omOpVLUm9klAgMBAAGjggFVMIIBUTAMBgNVHRME\n" + "BTADAQH/MB0GA1UdDgQWBBQg2FZB/j8uWDVnJhjwXkX278znSTAfBgNVHSMEGDAW\n" + "gBQg2FZB/j8uWDVnJhjwXkX278znSTAPBgNVHQ8BAf8EBQMDB/+AMIHvBgNVHSUB\n" + "Af8EgeQwgeEGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwME\n" + "BggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK\n" + "KwYBBAGCNwoDAwYKKwYBBAGCNwoDBAYJYIZIAYb4QgQBBgsrBgEEAYI3CgMEAQYI\n" + "KwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUIAgIGCisGAQQBgjcU\n" + "AgIGCCsGAQUFBwMJBggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZI\n" + "hvcNAQELBQADggEBAKHmwejWRwGE1wf1k2rG8SNRV/neGsZ6Qfqf6co3TpR/Wi1s\n" + "iZDvSeT/rbqNBS7z34xnG88NIUwu00y78e8Mfon31ZZbK4Uo7fla9/D3ukdJqPQC\n" + "LKdbKJjR2kH+KCukY/1rghjJ8/X+t2egBit0LCOdsFCl07Sfksb9kpGUIZSFcYYm\n" + "geqhjhoNwxazzHiw+QWHC5HG9248JIizBmy1aymNWuMnPudhjHAnPcsIlqMVNq3t\n" + "Rv9ap7S8JeCxHVRPJvJeCwXWvW3dW/v3xH52Yn/fqRblN1w9Fxz5NhopKx0gj/Jd\n" + "sw2N4Fk4gaOWEolFpa0bwNw8nAx7moehZpowzfw=\n" + "-----END CERTIFICATE-----\n"; + +static const char *AUTH_PRIVATE_KEY = + "data:,-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEogIBAAKCAQEAwqVYYrx/8ASMru+K70J3J0maisrKTegrw9aZlfcH7eTx4Vbf\n" + "Y1e/b4Erm+SwA6ERwIBXb/XbmIAa9ezm+rkayGOAdfAnKwo4UHAuII8fMto5fT3m\n" + "JvqmA96OOBWAawatEAp60ICrG/6l/WfjMP1VIsOucevFvO+ixB0EKBIE+JMUrmoM\n" + "AaFUZHjw+n2ACpk+F0t8fjtL/qxxEk3LChesjGnYKe4d3h9W/JCU80sfCVfWc6vv\n" + "psY6MaoWwVT+Zw83toYUiHgpAr0q8e3n5ICkuAEF2uf2eOBogLtU3111KnYnPa8c\n" + "A9HnZ2ozRJZ2Xu7I6JP9Mrqrx/toUqqTb2v86QIDAQABAoIBAC1q32DKkx+yMBFx\n" + "m32QiLUGG6VfBC2BixS7MkMnzRXZYgcuehl4FBc0kLRjfB6cqsO8LqrVN1QyMBhK\n" + "GutN3c38SbE7RChqzhEW2+yE+Mao3Nk4ZEecHLiyaYT0n25ZtHAVwep823BAzwJ+\n" + "BykbM45VEpNKbG1VjSktjBa9faNyZiZAEJEjVyla+6R8N4kHV52LbZcLjvJv3IQ2\n" + "iPYRrmMyI5C23qTni0vy7yJbAXBo3CqgSlwie9FARBWT7Puu7F4mF1O1c/SnTysw\n" + "Tm3e5FzgfHipQbnRVn0w4rDprPMKmPxMnvf/Wkw0zVgNadp1Tc1I6Yj525DEQ07i\n" + "2gIn/gECgYEA4jNnY1u2Eu7x3pAQF3dRO0x35boVtuq9iwQk7q+uaZaK4RJRr+0Y\n" + "T68S3bPnfer6SHvcxtST89Bvs/j/Ky4SOaX037UYjFh6T7OIzPl+MzO1yb+VOBT6\n" + "D6FVGEJGp8ZAITU1OfJPeTYViUeEC8tHFGoKUCk50FbB6jOf1oKtv/ECgYEA3EnB\n" + "Y7kSbJJaUuj9ciFUL/pAno86Cim3VjegK1wKgEiyDb610bhoMErovPwfVJbtcttG\n" + "eKJNuwizkRcVbj+vpjDvqqaP5eMxLl6/Nd4haPMJYzGo88Z8NJpwFRNF2KEWjOpQ\n" + "2NEvoCeRtVulCJyka2Tpljzw8cOXkxhPOe2UhHkCgYBo3entj0QO7QXm56T+LAvV\n" + "0PK45xdQEO3EuCwjGAFk5C0IgUSrqeCeeIzniZMltj1IQ1wsNbtNynEu3530t8wt\n" + "O7oVyFBUKGSz9IjUdkpClJOPr6kPMfJoMqRPtdIpz+hFPPSrI6IikKdVWHloOlp+\n" + "pVaYqTQrWT1XRY2xli3VEQKBgGySmZN6Cx+h/oywswIGdUT0VdcQhq2to+QFpJba\n" + "VX6m1cM6hMip2Ag9U3qZ1SNPBBdBBfm9HQybHE3dj713/C2wHuAAGhpXIM1W+20k\n" + "X1knuC/AsSH9aQhQOf/ZMOq1crTfZBuI9q0782/sjGmzMsKPySU4QhUWruVb7OiD\n" + "NVkZAoGAEvihW7G+8/iOE40vGHyBqUeopAAWLciTAUIEwM/Oi3BYfNWNTWF/FWNc\n" + "nMvCZPYigY8C1vO+1iT2Frtd3CIU+f01Q3fJNJoRLlEiKLNZUJRF48OKUqjKSmsi\n" + "w6pucFO40z05YW7utApj4L82rZnOS0pd1tUI1yexqvj0i4ThJfk=\n" + "-----END RSA PRIVATE KEY-----\n"; + +static struct plugins_hdl *g_plugins = NULL; +static dds_security_authentication *g_auth = NULL; +static dds_security_access_control *g_access_control = NULL; +static char *g_path_to_etc_dir = NULL; + +/* Prepare a property sequence. */ +static void dds_security_property_init(DDS_Security_PropertySeq *seq, DDS_Security_unsigned_long size) +{ + seq->_length = size; + seq->_maximum = size; + seq->_buffer = ddsrt_malloc(size * sizeof(DDS_Security_Property_t)); + memset(seq->_buffer, 0, size * sizeof(DDS_Security_Property_t)); +} + +/* Cleanup a property sequence.*/ +static void dds_security_property_deinit(DDS_Security_PropertySeq *seq) +{ + uint32_t i; + + for (i = 0; i < seq->_length; i++) + { + ddsrt_free(seq->_buffer[i].name); + ddsrt_free(seq->_buffer[i].value); + } + ddsrt_free(seq->_buffer); +} + +/* Find a property within a sequence.*/ +static DDS_Security_Property_t *dds_security_property_find(DDS_Security_PropertySeq *seq, const char *name) +{ + DDS_Security_Property_t *prop = NULL; + uint32_t i; + for (i = 0; (i < seq->_length) && (prop == NULL); i++) + { + if (strcmp(seq->_buffer[i].name, name) == 0) + { + prop = &(seq->_buffer[i]); + } + } + return prop; +} + +/* Cleanup exception contents.*/ +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +/* Glue two strings together */ +static char *combine_strings(const char *prefix, const char *postfix) +{ + char *str; + ddsrt_asprintf(&str, "%s%s", prefix, postfix); + return str; +} + +/* Use the given file to create a proper file uri (with directory).*/ +static char *create_uri_file(const char *file) +{ + char *uri; + char *dir; + if (file) + { + dir = combine_strings("file:", g_path_to_etc_dir); + uri = combine_strings(dir, file); + ddsrt_free(dir); + } + else + { + uri = ddsrt_strdup("file:"); + } + return uri; +} + +/* Read the given file contents and transform it into a data uri.*/ +static char *create_uri_data(const char *file) +{ + char *data = NULL; + char *location; + char *contents; + + if (file) + { + location = combine_strings(g_path_to_etc_dir, file); + if (location) + { + contents = load_file_contents(location); + if (contents) + { + data = combine_strings("data:,", contents); + ddsrt_free(contents); + } + ddsrt_free(location); + } + } + else + { + data = ddsrt_strdup("data:,"); + } + + return data; +} + +/* Fill the security properties of a participant QoS with the + * authorization and access_control values. */ +static void fill_property_policy(DDS_Security_PropertyQosPolicy *property, const char *permission_ca, const char *permission_uri, const char *governance_uri) +{ + dds_security_property_init(&property->value, 6); + /* Authentication properties. */ + property->value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + property->value._buffer[0].value = ddsrt_strdup(AUTH_IDENTITY_CERT); + property->value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + property->value._buffer[1].value = ddsrt_strdup(AUTH_IDENTITY_CA); + property->value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + property->value._buffer[2].value = ddsrt_strdup(AUTH_PRIVATE_KEY); + /* AccessControl properties. */ + property->value._buffer[3].name = ddsrt_strdup(PROPERTY_PERMISSIONS_CA); + property->value._buffer[3].value = permission_ca ? ddsrt_strdup(permission_ca) : NULL; + property->value._buffer[4].name = ddsrt_strdup(PROPERTY_PERMISSIONS); + property->value._buffer[4].value = permission_uri ? ddsrt_strdup(permission_uri) : NULL; + property->value._buffer[5].name = ddsrt_strdup(PROPERTY_GOVERNANCE); + property->value._buffer[5].value = governance_uri ? ddsrt_strdup(governance_uri) : NULL; +} + +/* Open a local identity by calling the authorization plugin with + * properly created dummy values and the given participant QoS.*/ +static DDS_Security_IdentityHandle create_local_identity(DDS_Security_Qos *participant_qos) +{ + DDS_Security_IdentityHandle local_id_hdl = DDS_SECURITY_HANDLE_NIL; + DDS_Security_ValidationResult_t result; + DDS_Security_DomainId domain_id = 0; + DDS_Security_GUID_t local_participant_guid; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb}; + DDS_Security_EntityId_t entityId = {{0xb0, 0xb1, 0xb2}, 0x1}; + + CU_ASSERT_FATAL(g_auth->validate_local_identity != NULL); + + memset(&local_participant_guid, 0, sizeof(local_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + /* Now call the function. */ + result = g_auth->validate_local_identity( + g_auth, + &local_id_hdl, + &local_participant_guid, + domain_id, + participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) + { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + reset_exception(&exception); + + return local_id_hdl; +} + +/* Close the given local identity by returning its handle to the + * authorization plugin.*/ +static void clear_local_identity(DDS_Security_IdentityHandle local_id_hdl) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (local_id_hdl != DDS_SECURITY_HANDLE_NIL) + { + success = g_auth->return_identity_handle(g_auth, local_id_hdl, &exception); + if (!success) + { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } +} + +/* Prepare the global link to the test's "etc" directory.*/ +static void set_path_to_etc_dir(void) +{ + ddsrt_asprintf(&g_path_to_etc_dir, "%s%s", CONFIG_ENV_TESTS_DIR, RELATIVE_PATH_TO_ETC_DIR); +} + +/* Initialize the participant QoS with security related properties. + * It will transform the given files into proper uri's. + * A NULL will result in a file uri without actual link.*/ +static void qos_init_file(DDS_Security_Qos *participant_qos, const char *certificate_filename, const char *permission_filename, const char *governance_filename) +{ + char *permission_ca; + char *permission_uri; + char *governance_uri; + + permission_ca = create_uri_file(certificate_filename); + permission_uri = create_uri_file(permission_filename); + governance_uri = create_uri_file(governance_filename); + + memset(participant_qos, 0, sizeof(*participant_qos)); + fill_property_policy(&(participant_qos->property), + permission_ca, + permission_uri, + governance_uri); + + ddsrt_free(permission_ca); + ddsrt_free(permission_uri); + ddsrt_free(governance_uri); +} + +/* Initialize the participant QoS with security related properties. + * It will transform the given files into data uri's. + * A NULL will result in a data uri without actual data.*/ +static void qos_init_data(DDS_Security_Qos *participant_qos, const char *certificate_filename, const char *permission_filename, const char *governance_filename) +{ + char *permission_ca; + char *permission_uri; + char *governance_uri; + + permission_ca = create_uri_data(certificate_filename); + permission_uri = create_uri_data(permission_filename); + governance_uri = create_uri_data(governance_filename); + CU_ASSERT_FATAL(permission_ca != NULL); + CU_ASSERT_FATAL(permission_uri != NULL); + CU_ASSERT_FATAL(governance_uri != NULL); + + memset(participant_qos, 0, sizeof(*participant_qos)); + fill_property_policy(&(participant_qos->property), + permission_ca, + permission_uri, + governance_uri); + + ddsrt_free(permission_ca); + ddsrt_free(permission_uri); + ddsrt_free(governance_uri); +} + +/* Initialize the participant QoS with security related properties. + * A NULL will result in an uri with an unknown type.*/ +static void qos_init_type(DDS_Security_Qos *participant_qos, const char *certificate_filename, const char *permission_filename, const char *governance_filename) +{ + char *permission_ca; + char *permission_uri; + char *governance_uri; + + if (certificate_filename) + permission_ca = create_uri_file(certificate_filename); + else + permission_ca = ddsrt_strdup("unknown_type:,just some data"); + if (permission_filename) + permission_uri = create_uri_file(permission_filename); + else + permission_uri = ddsrt_strdup("unknown_type:,just some data"); + if (governance_filename) + governance_uri = create_uri_file(governance_filename); + else + governance_uri = ddsrt_strdup("unknown_type:,just some data"); + + memset(participant_qos, 0, sizeof(*participant_qos)); + fill_property_policy(&(participant_qos->property), + permission_ca, + permission_uri, + governance_uri); + + ddsrt_free(permission_ca); + ddsrt_free(permission_uri); + ddsrt_free(governance_uri); +} + +/* Initialize the participant QoS with security related properties. + * Allow NULL as property value.*/ +static void qos_init_null(DDS_Security_Qos *participant_qos, const char *certificate_filename, const char *permission_filename, const char *governance_filename) +{ + char *permission_ca = NULL; + char *permission_uri = NULL; + char *governance_uri = NULL; + + if (certificate_filename) + permission_ca = create_uri_file(certificate_filename); + if (permission_filename) + permission_uri = create_uri_file(permission_filename); + if (governance_filename) + governance_uri = create_uri_file(governance_filename); + + memset(participant_qos, 0, sizeof(*participant_qos)); + fill_property_policy(&(participant_qos->property), + permission_ca, + permission_uri, + governance_uri); + + ddsrt_free(permission_ca); + ddsrt_free(permission_uri); + ddsrt_free(governance_uri); +} + +/* Cleanup the participant QoS.*/ +static void qos_deinit(DDS_Security_Qos *participant_qos) +{ + dds_security_property_deinit(&(participant_qos->property.value)); +} + +/* Setup the testing environment by loading the plugins and + * creating a local identity.*/ +static DDS_Security_IdentityHandle test_setup(DDS_Security_Qos *participant_qos) +{ + DDS_Security_IdentityHandle local_id_hdl = DDS_SECURITY_HANDLE_NIL; + + g_plugins = load_plugins(&g_access_control /* Access Control */, + &g_auth /* Authentication */, + NULL /* Cryptograpy */); + if (g_plugins) + { + CU_ASSERT_FATAL(g_auth != NULL); + CU_ASSERT_FATAL(g_access_control != NULL); + CU_ASSERT_FATAL(g_access_control->validate_local_permissions != NULL); + CU_ASSERT_FATAL(g_access_control->return_permissions_handle != NULL); + + local_id_hdl = create_local_identity(participant_qos); + } + + return local_id_hdl; +} + +/* Teardown the testing environment by clearing the local identity + * and closing the plugins.*/ +static int test_teardown(DDS_Security_IdentityHandle local_id_hdl) +{ + clear_local_identity(local_id_hdl); + unload_plugins(g_plugins); + g_plugins = NULL; + g_access_control = NULL; + g_auth = NULL; + return 0; +} + +/* The AccessControl related properties in the participant_qos will + * have some kind of problem that should force a failure when + * checking the local permissions.*/ +static DDS_Security_long test_failure_scenario(DDS_Security_Qos *participant_qos) +{ + DDS_Security_long code = DDS_SECURITY_ERR_OK_CODE; + DDS_Security_IdentityHandle local_id_hdl = DDS_SECURITY_HANDLE_NIL; + DDS_Security_PermissionsHandle result; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Prepare testing environment. */ + local_id_hdl = test_setup(participant_qos); + CU_ASSERT_FATAL(local_id_hdl != DDS_SECURITY_HANDLE_NIL); + + /* Call the plugin with the invalid property. */ + result = g_access_control->validate_local_permissions( + g_access_control, + g_auth, + local_id_hdl, + 0, + participant_qos, + &exception); + + /* Be sure the plugin returned a failure. */ + CU_ASSERT(result == 0); + if (result == 0) + { + code = exception.code; + CU_ASSERT(exception.message != NULL); + printf("validate_local_permissions failed: (%d) %s\n", (int)exception.code, exception.message ? exception.message : "Error message missing"); + } + else + { + reset_exception(&exception); + g_access_control->return_permissions_handle(g_access_control, result, &exception); + } + reset_exception(&exception); + + /* Cleanup the testing environment. */ + test_teardown(local_id_hdl); + + return code; +} + +/* Use with invalid file link for certificate, permission or + * governance. The local permissions check should fail.*/ +static DDS_Security_long test_invalid_file_uri(const char *certificate_filename, const char *permission_filename, const char *governance_filename) +{ + DDS_Security_long code = DDS_SECURITY_ERR_OK_CODE; + DDS_Security_Qos participant_qos; + + qos_init_file(&participant_qos, + certificate_filename, + permission_filename, + governance_filename); + + code = test_failure_scenario(&participant_qos); + + qos_deinit(&participant_qos); + + return code; +} + +/* Use with invalid data for certificate, permission or governance. + * The local permissions check should fail.*/ +static DDS_Security_long test_invalid_data_uri(const char *certificate_filename, const char *permission_filename, const char *governance_filename) +{ + DDS_Security_long code = DDS_SECURITY_ERR_OK_CODE; + DDS_Security_Qos participant_qos; + + qos_init_data(&participant_qos, + certificate_filename, + permission_filename, + governance_filename); + + code = test_failure_scenario(&participant_qos); + + qos_deinit(&participant_qos); + + return code; +} + +/* Generate uri's with invalid types for certificate, permission + * or governance. The local permissions check should fail.*/ +static DDS_Security_long test_invalid_type_uri(const char *certificate_filename, const char *permission_filename, const char *governance_filename) +{ + DDS_Security_long code = DDS_SECURITY_ERR_OK_CODE; + DDS_Security_Qos participant_qos; + + qos_init_type(&participant_qos, + certificate_filename, + permission_filename, + governance_filename); + + code = test_failure_scenario(&participant_qos); + qos_deinit(&participant_qos); + return code; +} + +/* Create properties in the QoS without actual values (NULL). + * The local permissions check should fail.*/ +static DDS_Security_long test_null_uri(const char *certificate_filename, const char *permission_filename, const char *governance_filename) +{ + DDS_Security_long code = DDS_SECURITY_ERR_OK_CODE; + DDS_Security_Qos participant_qos; + + qos_init_null(&participant_qos, + certificate_filename, + permission_filename, + governance_filename); + + code = test_failure_scenario(&participant_qos); + + qos_deinit(&participant_qos); + + return code; +} + +/* Get valid documents, but corrupt the signatures. + * The local permissions check should fail.*/ +static DDS_Security_long test_corrupted_signature(bool corrupt_permissions, bool corrupt_governance) +{ + DDS_Security_long code = DDS_SECURITY_ERR_OK_CODE; + DDS_Security_Property_t *prop = NULL; + DDS_Security_Qos participant_qos; + size_t len; + + /* Get data with valid signatures. */ + qos_init_data(&participant_qos, + "Test_Permissions_ca.pem", + "Test_Permissions_full.p7s", + "Test_Governance_full.p7s"); + + /* Only allow one signature to be corrupted. */ + CU_ASSERT_FATAL(corrupt_permissions != corrupt_governance); + + /* Corrupt the signature. */ + if (corrupt_permissions) + prop = dds_security_property_find(&(participant_qos.property.value), PROPERTY_PERMISSIONS); + if (corrupt_governance) + prop = dds_security_property_find(&(participant_qos.property.value), PROPERTY_GOVERNANCE); + + /* Just some (hardcoded) sanity checks. */ + CU_ASSERT_FATAL(prop != NULL); + CU_ASSERT_FATAL(prop->value != NULL); + assert(prop && prop->value); // for Clang's static analyzer + len = strlen(prop->value); + CU_ASSERT_FATAL(len > 2250); + + /* Corrupt a byte somewhere in the signature. */ + prop->value[len - 75]--; + + code = test_failure_scenario(&participant_qos); + qos_deinit(&participant_qos); + return code; +} + +static void suite_validate_local_permissions_init(void) +{ + set_path_to_etc_dir(); +} + +static void suite_validate_local_permissions_fini(void) +{ + ddsrt_free(g_path_to_etc_dir); +} + +/* Supplying proper files should pass the local permissions check */ +CU_Test(ddssec_builtin_validate_local_permissions, valid_file, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_IdentityHandle local_id_hdl = DDS_SECURITY_HANDLE_NIL; + DDS_Security_PermissionsHandle result; + DDS_Security_Qos participant_qos; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + qos_init_file(&participant_qos, + "Test_Permissions_ca.pem", + "Test_Permissions_full.p7s", + "Test_Governance_full.p7s"); + local_id_hdl = test_setup(&participant_qos); + CU_ASSERT_FATAL(local_id_hdl != DDS_SECURITY_HANDLE_NIL); + + result = g_access_control->validate_local_permissions( + g_access_control, + g_auth, + local_id_hdl, + 0, + &participant_qos, + &exception); + + CU_ASSERT(result != 0); + if (result == 0) + { + printf("validate_local_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + else + { + g_access_control->return_permissions_handle(g_access_control, result, &exception); + } + reset_exception(&exception); + + test_teardown(local_id_hdl); + qos_deinit(&participant_qos); +} + +/* Supplying proper data should pass the local permissions check */ +CU_Test(ddssec_builtin_validate_local_permissions, valid_data, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_IdentityHandle local_id_hdl = DDS_SECURITY_HANDLE_NIL; + DDS_Security_PermissionsHandle result; + DDS_Security_Qos participant_qos; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + qos_init_data(&participant_qos, + "Test_Permissions_ca.pem", + "Test_Permissions_full.p7s", + "Test_Governance_full.p7s"); + local_id_hdl = test_setup(&participant_qos); + CU_ASSERT(local_id_hdl != DDS_SECURITY_HANDLE_NIL); + + result = g_access_control->validate_local_permissions( + g_access_control, + g_auth, + local_id_hdl, + 0, + &participant_qos, + &exception); + + CU_ASSERT(result != 0); + if (result == 0) + { + printf("validate_local_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + else + { + g_access_control->return_permissions_handle(g_access_control, result, &exception); + } + reset_exception(&exception); + + test_teardown(local_id_hdl); + qos_deinit(&participant_qos); +} + +/* Supplying no files but directories should fail the local permissions check. */ +CU_Test(ddssec_builtin_validate_local_permissions, uri_directories, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_long code; + + /* Certificate points to a valid directory.*/ + code = test_invalid_file_uri("", + "Test_Permissions_full.p7s", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE); + + /* Permission points to a valid directory. */ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE); + + /* Governance points to a valid directory.*/ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_full.p7s", + ""); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE); +} + +/* Supplying empty files should fail the local permissions check. */ +CU_Test(ddssec_builtin_validate_local_permissions, uri_empty_files, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_long code; + + /* Certificate points to an empty file. */ + code = test_invalid_file_uri("Test_File_empty.txt", + "Test_Permissions_full.p7s", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE); + + /* Permission points to an empty file. */ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_File_empty.txt", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE); + + /* Governance points to an empty file. */ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_full.p7s", + "Test_File_empty.txt"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE); +} + +/* Supplying text files should fail the local permissions check. */ +CU_Test(ddssec_builtin_validate_local_permissions, uri_text_files, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_long code; + + /* Certificate points to a file with only text. */ + code = test_invalid_file_uri("Test_File_text.txt", + "Test_Permissions_full.p7s", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_CERTIFICATE_CODE); + + /* Permission points to a file with only text. */ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_File_text.txt", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_SMIME_DOCUMENT_CODE); + + /* Governance points to a file with only text. */ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_full.p7s", + "Test_File_text.txt"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_SMIME_DOCUMENT_CODE); +} + +/* Not supplying files should fail the local permissions check. */ +CU_Test(ddssec_builtin_validate_local_permissions, uri_absent_files, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_long code; + + /* Certificate points to a non-existing file.*/ + code = test_invalid_file_uri("Test_File_absent.txt", + "Test_Permissions_full.p7s", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE); + + /* Permission points to a non-existing file.*/ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_File_absent.txt", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE); + + /* Governance points to a non-existing file.*/ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_full.p7s", + "Test_File_absent.txt"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE); +} + +/* Not supplying file uris should fail the local permissions check. */ +CU_Test(ddssec_builtin_validate_local_permissions, uri_no_files, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_long code; + + /* Certificate file uri doesn't point to anything.*/ + code = test_invalid_file_uri(NULL, + "Test_Permissions_full.p7s", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE); + + /* Permission file uri doesn't point to anything.*/ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + NULL, + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE); + + /* Governance file uri doesn't point to anything.*/ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_full.p7s", + NULL); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_FILE_PATH_CODE); +} + +/* Supplying empty data should fail the local permissions check. */ +CU_Test(ddssec_builtin_validate_local_permissions, uri_empty_data, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_long code; + + /* Certificate is empty data.*/ + code = test_invalid_data_uri(NULL, + "Test_Permissions_full.p7s", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_CERTIFICATE_CODE); + + /* Permission is empty data.*/ + code = test_invalid_data_uri("Test_Permissions_ca.pem", + NULL, + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_PERMISSION_DOCUMENT_PROPERTY_CODE); + + /* Governance is empty data.*/ + code = test_invalid_data_uri("Test_Permissions_ca.pem", + "Test_Permissions_full.p7s", + NULL); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_GOVERNANCE_DOCUMENT_PROPERTY_CODE); +} + +/* Supplying uris with invalid types should fail the local permissions check. */ +CU_Test(ddssec_builtin_validate_local_permissions, uri_invalid_types, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_long code; + + /* Certificate doesn't point to anything: results in invalid type.*/ + code = test_invalid_type_uri(NULL, + "Test_Permissions_full.p7s", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_CERTIFICATE_TYPE_NOT_SUPPORTED_CODE); + + /* Permission doesn't point to anything: results in invalid type.*/ + code = test_invalid_type_uri("Test_Permissions_ca.pem", + NULL, + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_URI_TYPE_NOT_SUPPORTED_CODE); + + /* Governance doesn't point to anything: results in invalid type*/ + code = test_invalid_type_uri("Test_Permissions_ca.pem", + "Test_Permissions_full.p7s", + NULL); + CU_ASSERT(code == DDS_SECURITY_ERR_URI_TYPE_NOT_SUPPORTED_CODE); +} + +/* Not supplying actual uris should fail the local permissions check. */ +CU_Test(ddssec_builtin_validate_local_permissions, uri_null, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_long code; + + /* Certificate doesn't point to anything.*/ + code = test_null_uri(NULL, + "Test_Permissions_full.p7s", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_MISSING_PROPERTY_CODE); + + /* Permission doesn't point to anything.*/ + code = test_null_uri("Test_Permissions_ca.pem", + NULL, + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_MISSING_PROPERTY_CODE); + + /* Governance doesn't point to anything.*/ + code = test_null_uri("Test_Permissions_ca.pem", + "Test_Permissions_full.p7s", + NULL); + CU_ASSERT(code == DDS_SECURITY_ERR_MISSING_PROPERTY_CODE); +} + +/* Corrupted signatures should fail the local permissions check. */ +CU_Test(ddssec_builtin_validate_local_permissions, corrupted_signatures, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_long code; + + /* Corrupt permission signature.*/ + code = test_corrupted_signature(true /* Corrupt permissions? Yes. */, + false /* Corrupt governance? No. */); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_SMIME_DOCUMENT_CODE); + + /* Corrupt governance signature.*/ + code = test_corrupted_signature(false /* Corrupt permissions? No. */, + true /* Corrupt governance? Yes. */); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_SMIME_DOCUMENT_CODE); +} + +/* Unknown signatures should fail the local permissions check. */ +CU_Test(ddssec_builtin_validate_local_permissions, unknown_ca, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_long code; + + /* Permission with unknown CA.*/ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_unknown_ca.p7s", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_SMIME_DOCUMENT_CODE); + + /* Governance with unknown CA.*/ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_full.p7s", + "Test_Governance_unknown_ca.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_SMIME_DOCUMENT_CODE); +} + +/* Un-available signatures should fail the local permissions check. */ +CU_Test(ddssec_builtin_validate_local_permissions, not_signed, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_long code; + + /* Permission not signed.*/ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_not_signed.p7s", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_SMIME_DOCUMENT_CODE); + + /* Governance not signed.*/ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_full.p7s", + "Test_Governance_not_signed.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_SMIME_DOCUMENT_CODE); +} + +/* Permissions outside the validity data should fail the local */ +CU_Test(ddssec_builtin_validate_local_permissions, validity, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_long code; + + /* Permission already expired.*/ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_expired.p7s", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_CODE); + + /* Permission not yet valid.*/ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_notyet.p7s", + "Test_Governance_full.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_VALIDITY_PERIOD_NOT_STARTED_CODE); +} + +/* Permissions document does not contain a proper subject_name, + * which should fail the local permissions check. */ +CU_Test(ddssec_builtin_validate_local_permissions, subject_name, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_long code; + + /* Permission document with unknown subject. */ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_unknown_subject.p7s", + "Test_Governance_check_create_participant.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_INVALID_SUBJECT_NAME_CODE); +} + +/* Documents with invalid xml should fail the local permissions check. */ +CU_Test(ddssec_builtin_validate_local_permissions, xml_invalid, .init = suite_validate_local_permissions_init, .fini = suite_validate_local_permissions_fini) +{ + DDS_Security_long code; + + /* Permission XML contains invalid domain id. */ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_invalid_data.p7s", + "Test_Governance_ok.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_CODE); + + /* Permission XML contains invalid domain id. */ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_invalid_element.p7s", + "Test_Governance_ok.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_CODE); + + /* Permission XML is missing the 'not before' validity tag.*/ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_lack_of_not_before.p7s", + "Test_Governance_ok.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_CODE); + + /* Permission XML is missing the 'not after' validity tag.*/ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_lack_of_not_after.p7s", + "Test_Governance_ok.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_CODE); + + /* Governance XML contains invalid encryption kind.*/ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_ok.p7s", + "Test_Governance_invalid_data.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_CAN_NOT_PARSE_GOVERNANCE_CODE); + + /* Governance XML contains unknown element.*/ + code = test_invalid_file_uri("Test_Permissions_ca.pem", + "Test_Permissions_ok.p7s", + "Test_Governance_invalid_element.p7s"); + CU_ASSERT(code == DDS_SECURITY_ERR_CAN_NOT_PARSE_GOVERNANCE_CODE); +} diff --git a/src/security/builtin_plugins/tests/validate_remote_identity/src/validate_remote_identity_utests.c b/src/security/builtin_plugins/tests/validate_remote_identity/src/validate_remote_identity_utests.c new file mode 100644 index 0000000..6cbb267 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_identity/src/validate_remote_identity_utests.c @@ -0,0 +1,1140 @@ + +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/dds_security_api.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include +#include +#include "dds/ddsrt/environ.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "assert.h" + + +/* Test helper includes. */ +#include "common/src/loader.h" + +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" + +static const char * AUTH_PROTOCOL_CLASS_ID = "DDS:Auth:PKI-DH:1.0"; + +static const char * PROPERTY_IDENTITY_CA = "dds.sec.auth.identity_ca"; +static const char * PROPERTY_PRIVATE_KEY = "dds.sec.auth.private_key"; +static const char * PROPERTY_IDENTITY_CERT = "dds.sec.auth.identity_certificate"; + +static const char * PROPERTY_CERT_SUBJECT_NAME = "dds.cert.sn"; +static const char * PROPERTY_CERT_ALGORITHM = "dds.cert.algo"; +static const char * PROPERTY_CA_SUBJECT_NAME = "dds.ca.sn"; +static const char * PROPERTY_CA_ALGORITHM = "dds.ca.aglo"; + +static const char * SUBJECT_NAME_IDENTITY_CERT = "CN=CHAM-574 client,O=Some Company,ST=Some-State,C=NL"; +static const char * SUBJECT_NAME_IDENTITY_CA = "CN=CHAM-574 authority,O=Some Company,ST=Some-State,C=NL"; + +static const char * SUBJECT_NAME_IDENTITY_CERT_2 = "CN=CHAM-574_1 client,O=Some Company,ST=Some-State,C=NL"; +static const char * SUBJECT_NAME_IDENTITY_CA_2 = "CN=CHAM-574_1 authority,O=Some Company,ST=Some-State,C=NL"; + + +static const char * RSA_2048_ALGORITHM_NAME = "RSA-2048"; +//static const char * EC_PRIME256V1_ALGORITHM_NAME = "EC-prime256v1"; + +static const char * AUTH_REQUEST_TOKEN_CLASS_ID = "DDS:Auth:PKI-DH:1.0+AuthReq"; +static const char * AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME = "future_challenge"; + +static const char *identity_certificate = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEQTCCAymgAwIBAgIINpuaAAnrQZIwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE3MDIy\n" + "MjIyMjIwMFoYDzIyMjIwMjIyMjIyMjAwWjBcMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRUwEwYDVQQDEwxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n" + "ggEKAoIBAQDCpVhivH/wBIyu74rvQncnSZqKyspN6CvD1pmV9wft5PHhVt9jV79v\n" + "gSub5LADoRHAgFdv9duYgBr17Ob6uRrIY4B18CcrCjhQcC4gjx8y2jl9PeYm+qYD\n" + "3o44FYBrBq0QCnrQgKsb/qX9Z+Mw/VUiw65x68W876LEHQQoEgT4kxSuagwBoVRk\n" + "ePD6fYAKmT4XS3x+O0v+rHESTcsKF6yMadgp7h3eH1b8kJTzSx8JV9Zzq++mxjox\n" + "qhbBVP5nDze2hhSIeCkCvSrx7efkgKS4AQXa5/Z44GiAu1TfXXUqdic9rxwD0edn\n" + "ajNElnZe7sjok/0yuqvH+2hSqpNva/zpAgMBAAGjggEAMIH9MAwGA1UdDwQFAwMH\n" + "/4AwgewGA1UdJQSB5DCB4QYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYI\n" + "KwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3AgEVBgorBgEEAYI3AgEWBgorBgEE\n" + "AYI3CgMBBgorBgEEAYI3CgMDBgorBgEEAYI3CgMEBglghkgBhvhCBAEGCysGAQQB\n" + "gjcKAwQBBggrBgEFBQcDBQYIKwYBBQUHAwYGCCsGAQUFBwMHBggrBgEFBQgCAgYK\n" + "KwYBBAGCNxQCAgYIKwYBBQUHAwkGCCsGAQUFBwMNBggrBgEFBQcDDgYHKwYBBQID\n" + "BTANBgkqhkiG9w0BAQsFAAOCAQEAawdHy0Xw7nTK2ltp91Ion6fJ7hqYuj///zr7\n" + "Adt6uonpDh/xl3esuwcFimIJrJrHujnGkL0nLddRCikmnzuBMNDWS6yq0/Ckl/YG\n" + "yjNr44dlX24wo+MVAgkj3/8CyWDZ3a8kBg9QT3bs2SqbjmhTrXN1DRyf9S5vJysE\n" + "I7V1gTN66BeKL64hOrAlRVrEu8Ds6TWL6Q/YH+61ViZkoLTeSaPjH4nknaFr4C35\n" + "iji0JhkyfRHRRVPHFnaj25AkxOrSV64qVKoTMjDl5fji5iMGtjm6iJ7q05ml/qDl\n" + "nLotHXemZNvYhbwUmRzbt4Dls9EMH4VRbP85I94nM5TAvtHVNA==\n" + "-----END CERTIFICATE-----\n"; + + +static const char *identity_ca = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEmTCCA4GgAwIBAgIIZ5gEIUFhO5wwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDIx\n" + "MjE1MDUwMFoYDzIyMjIwMjIyMjIyMjAwWjBfMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRgwFgYDVQQDEw9DSEFNNTAwIHJvb3QgY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" + "DwAwggEKAoIBAQC6Fa3TheL+UrdZCp9GhU/2WbneP2t/avUa3muwDttPxeI2XU9k\n" + "ZjBR95mAXme4SPXHk5+YDN319AqIje3oKhzky/ngvKH2GkoJKYxWnuDBfMEHdViz\n" + "2Q9/xso2ZvH50ukwWa0pfx2/EVV1wRxeQcRd/UVfq3KTJizG0M88mOYvGEAw3LFf\n" + "zef7k1aCuOofQmBvLukUudcYpMzfyHFp7lQqU4CcrrR5RtmfiUfrWfdGLea2iPDB\n" + "pJgN8ESOMwEHtOTEBDclYnH9L4t7CHQz+fXXS5IWFsDK9fCMQjnxDsDVeNrNzTYL\n" + "FaZrMg9S6IUQCEsQWsnq5weS8omOpVLUm9klAgMBAAGjggFVMIIBUTAMBgNVHRME\n" + "BTADAQH/MB0GA1UdDgQWBBQg2FZB/j8uWDVnJhjwXkX278znSTAfBgNVHSMEGDAW\n" + "gBQg2FZB/j8uWDVnJhjwXkX278znSTAPBgNVHQ8BAf8EBQMDB/+AMIHvBgNVHSUB\n" + "Af8EgeQwgeEGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwME\n" + "BggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK\n" + "KwYBBAGCNwoDAwYKKwYBBAGCNwoDBAYJYIZIAYb4QgQBBgsrBgEEAYI3CgMEAQYI\n" + "KwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUIAgIGCisGAQQBgjcU\n" + "AgIGCCsGAQUFBwMJBggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZI\n" + "hvcNAQELBQADggEBAKHmwejWRwGE1wf1k2rG8SNRV/neGsZ6Qfqf6co3TpR/Wi1s\n" + "iZDvSeT/rbqNBS7z34xnG88NIUwu00y78e8Mfon31ZZbK4Uo7fla9/D3ukdJqPQC\n" + "LKdbKJjR2kH+KCukY/1rghjJ8/X+t2egBit0LCOdsFCl07Sfksb9kpGUIZSFcYYm\n" + "geqhjhoNwxazzHiw+QWHC5HG9248JIizBmy1aymNWuMnPudhjHAnPcsIlqMVNq3t\n" + "Rv9ap7S8JeCxHVRPJvJeCwXWvW3dW/v3xH52Yn/fqRblN1w9Fxz5NhopKx0gj/Jd\n" + "sw2N4Fk4gaOWEolFpa0bwNw8nAx7moehZpowzfw=\n" + "-----END CERTIFICATE-----\n"; + + +static const char *private_key = + "data:,-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEogIBAAKCAQEAwqVYYrx/8ASMru+K70J3J0maisrKTegrw9aZlfcH7eTx4Vbf\n" + "Y1e/b4Erm+SwA6ERwIBXb/XbmIAa9ezm+rkayGOAdfAnKwo4UHAuII8fMto5fT3m\n" + "JvqmA96OOBWAawatEAp60ICrG/6l/WfjMP1VIsOucevFvO+ixB0EKBIE+JMUrmoM\n" + "AaFUZHjw+n2ACpk+F0t8fjtL/qxxEk3LChesjGnYKe4d3h9W/JCU80sfCVfWc6vv\n" + "psY6MaoWwVT+Zw83toYUiHgpAr0q8e3n5ICkuAEF2uf2eOBogLtU3111KnYnPa8c\n" + "A9HnZ2ozRJZ2Xu7I6JP9Mrqrx/toUqqTb2v86QIDAQABAoIBAC1q32DKkx+yMBFx\n" + "m32QiLUGG6VfBC2BixS7MkMnzRXZYgcuehl4FBc0kLRjfB6cqsO8LqrVN1QyMBhK\n" + "GutN3c38SbE7RChqzhEW2+yE+Mao3Nk4ZEecHLiyaYT0n25ZtHAVwep823BAzwJ+\n" + "BykbM45VEpNKbG1VjSktjBa9faNyZiZAEJEjVyla+6R8N4kHV52LbZcLjvJv3IQ2\n" + "iPYRrmMyI5C23qTni0vy7yJbAXBo3CqgSlwie9FARBWT7Puu7F4mF1O1c/SnTysw\n" + "Tm3e5FzgfHipQbnRVn0w4rDprPMKmPxMnvf/Wkw0zVgNadp1Tc1I6Yj525DEQ07i\n" + "2gIn/gECgYEA4jNnY1u2Eu7x3pAQF3dRO0x35boVtuq9iwQk7q+uaZaK4RJRr+0Y\n" + "T68S3bPnfer6SHvcxtST89Bvs/j/Ky4SOaX037UYjFh6T7OIzPl+MzO1yb+VOBT6\n" + "D6FVGEJGp8ZAITU1OfJPeTYViUeEC8tHFGoKUCk50FbB6jOf1oKtv/ECgYEA3EnB\n" + "Y7kSbJJaUuj9ciFUL/pAno86Cim3VjegK1wKgEiyDb610bhoMErovPwfVJbtcttG\n" + "eKJNuwizkRcVbj+vpjDvqqaP5eMxLl6/Nd4haPMJYzGo88Z8NJpwFRNF2KEWjOpQ\n" + "2NEvoCeRtVulCJyka2Tpljzw8cOXkxhPOe2UhHkCgYBo3entj0QO7QXm56T+LAvV\n" + "0PK45xdQEO3EuCwjGAFk5C0IgUSrqeCeeIzniZMltj1IQ1wsNbtNynEu3530t8wt\n" + "O7oVyFBUKGSz9IjUdkpClJOPr6kPMfJoMqRPtdIpz+hFPPSrI6IikKdVWHloOlp+\n" + "pVaYqTQrWT1XRY2xli3VEQKBgGySmZN6Cx+h/oywswIGdUT0VdcQhq2to+QFpJba\n" + "VX6m1cM6hMip2Ag9U3qZ1SNPBBdBBfm9HQybHE3dj713/C2wHuAAGhpXIM1W+20k\n" + "X1knuC/AsSH9aQhQOf/ZMOq1crTfZBuI9q0782/sjGmzMsKPySU4QhUWruVb7OiD\n" + "NVkZAoGAEvihW7G+8/iOE40vGHyBqUeopAAWLciTAUIEwM/Oi3BYfNWNTWF/FWNc\n" + "nMvCZPYigY8C1vO+1iT2Frtd3CIU+f01Q3fJNJoRLlEiKLNZUJRF48OKUqjKSmsi\n" + "w6pucFO40z05YW7utApj4L82rZnOS0pd1tUI1yexqvj0i4ThJfk=\n" + "-----END RSA PRIVATE KEY-----\n"; + + + + + +static struct plugins_hdl *plugins = NULL; +static dds_security_authentication *auth = NULL; +static DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_GUID_t local_participant_guid; + +static void +dds_security_property_init( + DDS_Security_PropertySeq *seq, + DDS_Security_unsigned_long size) +{ + seq->_length = size; + seq->_maximum = size; + seq->_buffer = ddsrt_malloc(size * sizeof(DDS_Security_Property_t)); + memset(seq->_buffer, 0, size * sizeof(DDS_Security_Property_t)); +} + +static void +dds_security_property_deinit( + DDS_Security_PropertySeq *seq) +{ + uint32_t i; + + for (i = 0; i < seq->_length; i++) { + ddsrt_free(seq->_buffer[i].name); + ddsrt_free(seq->_buffer[i].value); + } + ddsrt_free(seq->_buffer); +} + +static void +reset_exception( + DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void +initialize_identity_token( + DDS_Security_IdentityToken *token, + const char *certAlgo, + const char *caAlgo) +{ + memset(token, 0, sizeof(*token)); + + token->class_id = ddsrt_strdup(AUTH_PROTOCOL_CLASS_ID); + token->properties._maximum = 4; + token->properties._length = 4; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(4); + + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_CERT_SUBJECT_NAME); + token->properties._buffer[0].value = ddsrt_strdup(SUBJECT_NAME_IDENTITY_CERT); + token->properties._buffer[0].propagate = true; + + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_CERT_ALGORITHM); + token->properties._buffer[1].value = ddsrt_strdup(certAlgo); + token->properties._buffer[1].propagate = true; + + token->properties._buffer[2].name = ddsrt_strdup(PROPERTY_CA_SUBJECT_NAME); + token->properties._buffer[2].value = ddsrt_strdup(SUBJECT_NAME_IDENTITY_CA); + token->properties._buffer[2].propagate = true; + + token->properties._buffer[3].name = ddsrt_strdup(PROPERTY_CA_ALGORITHM); + token->properties._buffer[3].value = ddsrt_strdup(caAlgo); + token->properties._buffer[3].propagate = true; +} + +static void +initialize_identity_token_w_sn( + DDS_Security_IdentityToken *token, + const char *certSubjName, + const char *certAlgo, + const char *caSubjName, + const char *caAlgo) +{ + memset(token, 0, sizeof(*token)); + + token->class_id = ddsrt_strdup(AUTH_PROTOCOL_CLASS_ID); + token->properties._maximum = 4; + token->properties._length = 4; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(4); + + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_CERT_SUBJECT_NAME); + token->properties._buffer[0].value = ddsrt_strdup(certSubjName); + token->properties._buffer[0].propagate = true; + + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_CERT_ALGORITHM); + token->properties._buffer[1].value = ddsrt_strdup(certAlgo); + token->properties._buffer[1].propagate = true; + + token->properties._buffer[2].name = ddsrt_strdup(PROPERTY_CA_SUBJECT_NAME); + token->properties._buffer[2].value = ddsrt_strdup(caSubjName); + token->properties._buffer[2].propagate = true; + + token->properties._buffer[3].name = ddsrt_strdup(PROPERTY_CA_ALGORITHM); + token->properties._buffer[3].value = ddsrt_strdup(caAlgo); + token->properties._buffer[3].propagate = true; +} + +static void +deinitialize_identity_token( + DDS_Security_IdentityToken *token) +{ + DDS_Security_DataHolder_deinit(token); +} + + +static int +create_local_identity(void) +{ + int res = 0; + DDS_Security_ValidationResult_t result; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb}; + DDS_Security_EntityId_t entityId = {{0xb0,0xb1,0xb2},0x1}; + + memset(&local_participant_guid, 0, sizeof(local_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + memset(&participant_qos, 0, sizeof(participant_qos)); + dds_security_property_init(&participant_qos.property.value, 3); + participant_qos.property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + participant_qos.property.value._buffer[0].value = ddsrt_strdup(identity_certificate); + participant_qos.property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + participant_qos.property.value._buffer[1].value = ddsrt_strdup(identity_ca); + participant_qos.property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + participant_qos.property.value._buffer[2].value = ddsrt_strdup(private_key); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &local_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) { + res = -1; + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + dds_security_property_deinit(&participant_qos.property.value); + reset_exception(&exception); + + return res; +} + +static void +clear_local_identity(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (local_identity_handle != DDS_SECURITY_HANDLE_NIL) { + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } +} + +static int +check_auth_request_token( + DDS_Security_AuthRequestMessageToken *token, + int notNil) +{ + if (notNil) { + if (!token->class_id || + (strcmp(token->class_id, AUTH_REQUEST_TOKEN_CLASS_ID) != 0)) { + printf("AuthRequestMessageToken has invalid class_id\n"); + return 0; + } + + if (token->binary_properties._length != 1 || + token->binary_properties._buffer == NULL) { + printf("AuthRequestMessageToken has binary_properties\n"); + return 0; + } + + if (!token->binary_properties._buffer[0].name || + (strcmp(token->binary_properties._buffer[0].name, AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME) != 0)) { + printf("AuthRequestMessageToken has invalid property name\n"); + return 0; + } + + if (token->binary_properties._buffer[0].value._length != 32 || + token->binary_properties._buffer[0].value._buffer == NULL) { + printf("AuthRequestMessageToken has invalid property value\n"); + return 0; + } + } else { + if ((strlen(token->class_id) != 0) || + (token->properties._length != 0) || + (token->properties._maximum != 0) || + (token->binary_properties._buffer != NULL) || + (token->binary_properties._length != 0) || + (token->binary_properties._maximum != 0) || + (token->binary_properties._buffer != NULL) ) { + printf("AuthRequestMessageToken is not a TokenNil\n"); + return 0; + } + } + return 1; +} + +static void +fill_auth_request_token( + DDS_Security_AuthRequestMessageToken *token) +{ + uint32_t i; + uint32_t len = 32; + unsigned char *challenge; + + challenge = ddsrt_malloc(len); + + for (i = 0; i < len; i++) { + challenge[i] = (unsigned char)(0xFF - i); + } + + memset(token, 0, sizeof(*token)); + + token->class_id = ddsrt_strdup(AUTH_REQUEST_TOKEN_CLASS_ID); + token->binary_properties._maximum = 1; + token->binary_properties._length = 1; + token->binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(1); + token->binary_properties._buffer->name = ddsrt_strdup(AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + + token->binary_properties._buffer->value._maximum = len; + token->binary_properties._buffer->value._length = len; + token->binary_properties._buffer->value._buffer = challenge; +} + + +static void +set_remote_participant_guid( + DDS_Security_GUID_t *guid, + int higher) +{ + int i; + + memcpy(guid, &local_participant_guid, sizeof(*guid)); + + for (i = 0; i < 12; i++) { + int index = (i + 4) % 12; + if (higher) { + if (guid->prefix[index] < 0xFF) { + guid->prefix[index]++; + /*NOTE: It was giving warning ("unsigned char from ‘int’ may alter its value") with below + guid->prefix[index] += 1; + */ + break; + } + } else { + if (guid->prefix[index] > 0) { + guid->prefix[index]--; + /*NOTE: It was giving warning ("unsigned char from ‘int’ may alter its value") with below + guid->prefix[index] -= 1; + */ + break; + } + } + } +} + + +CU_Init(ddssec_builtin_validate_remote_identity) +{ + int res = 0; + + /* Only need the authentication plugin. */ + plugins = load_plugins(NULL /* Access Control */, + &auth /* Authentication */, + NULL /* Cryptograpy */); + if (plugins) { + res = create_local_identity(); + } else { + res = -1; + } + return res; +} + +CU_Clean(ddssec_builtin_validate_remote_identity) +{ + clear_local_identity(); + unload_plugins(plugins); + return 0; +} + +CU_Test(ddssec_builtin_validate_remote_identity,happy_day_nil_auth_req ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle remote_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_AuthRequestMessageToken local_auth_request_token = DDS_SECURITY_TOKEN_INIT; + DDS_Security_IdentityToken remote_identity_token; + DDS_Security_GUID_t remote_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have validate_local_identity function. */ + CU_ASSERT (auth != NULL); + CU_ASSERT (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT (auth->validate_remote_identity != NULL); + + if (local_identity_handle == DDS_SECURITY_HANDLE_NIL) { + return; + } + + initialize_identity_token(&remote_identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + set_remote_participant_guid(&remote_participant_guid, 1); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + NULL, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST); + if (result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST) { + CU_ASSERT (remote_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT (check_auth_request_token(&local_auth_request_token, 1)); + } + + reset_exception(&exception); + deinitialize_identity_token(&remote_identity_token); + DDS_Security_DataHolder_deinit(&local_auth_request_token); + + if ((result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST) || + (result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE)) { + DDS_Security_boolean success = auth->return_identity_handle(auth, remote_identity_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); + } +} + +CU_Test(ddssec_builtin_validate_remote_identity,happy_day_with_auth_req ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle remote_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_AuthRequestMessageToken local_auth_request_token = DDS_SECURITY_TOKEN_INIT; + DDS_Security_AuthRequestMessageToken remote_auth_request_token; + DDS_Security_IdentityToken remote_identity_token; + DDS_Security_GUID_t remote_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + /* Check if we actually have validate_local_identity function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->validate_remote_identity != NULL); + + initialize_identity_token(&remote_identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + fill_auth_request_token(&remote_auth_request_token); + set_remote_participant_guid(&remote_participant_guid, 0); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL (result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + CU_ASSERT (remote_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT (check_auth_request_token(&local_auth_request_token, 0)); + + reset_exception(&exception); + deinitialize_identity_token(&remote_identity_token); + DDS_Security_DataHolder_deinit(&remote_auth_request_token); + DDS_Security_DataHolder_deinit(&local_auth_request_token); + + success = auth->return_identity_handle(auth, remote_identity_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); +} + + +CU_Test(ddssec_builtin_validate_remote_identity,invalid_parameters ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle remote_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_AuthRequestMessageToken local_auth_request_token; + DDS_Security_AuthRequestMessageToken remote_auth_request_token; + DDS_Security_IdentityToken remote_identity_token; + DDS_Security_GUID_t remote_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have validate_local_identity function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->validate_remote_identity != NULL); + + initialize_identity_token(&remote_identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + fill_auth_request_token(&remote_auth_request_token); + set_remote_participant_guid(&remote_participant_guid, 1); + + result = auth->validate_remote_identity( + NULL, &remote_identity_handle, &local_auth_request_token, &remote_auth_request_token, + local_identity_handle, &remote_identity_token, &remote_participant_guid, &exception); + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->validate_remote_identity( + auth, NULL, &local_auth_request_token, &remote_auth_request_token, + local_identity_handle, &remote_identity_token, &remote_participant_guid, &exception); + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->validate_remote_identity( + auth, &remote_identity_handle, NULL, &remote_auth_request_token, + local_identity_handle, &remote_identity_token, &remote_participant_guid, &exception); + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->validate_remote_identity( + auth, &remote_identity_handle, &local_auth_request_token, &remote_auth_request_token, + local_identity_handle, NULL, &remote_participant_guid, &exception); + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + result = auth->validate_remote_identity( + auth, &remote_identity_handle, &local_auth_request_token, &remote_auth_request_token, + local_identity_handle, &remote_identity_token, NULL, &exception); + if (result != DDS_SECURITY_VALIDATION_OK) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + reset_exception(&exception); + + DDS_Security_DataHolder_deinit(&remote_auth_request_token); + deinitialize_identity_token(&remote_identity_token); +} + +CU_Test(ddssec_builtin_validate_remote_identity,unknown_local_identity ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle unknown_identity_handle = 0x56; + DDS_Security_IdentityHandle remote_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_AuthRequestMessageToken local_auth_request_token; + DDS_Security_AuthRequestMessageToken remote_auth_request_token; + DDS_Security_IdentityToken remote_identity_token; + DDS_Security_GUID_t remote_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have validate_local_identity function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->validate_remote_identity != NULL); + + initialize_identity_token(&remote_identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + fill_auth_request_token(&remote_auth_request_token); + set_remote_participant_guid(&remote_participant_guid, 0); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + &remote_auth_request_token, + unknown_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_remote_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + deinitialize_identity_token(&remote_identity_token); + DDS_Security_DataHolder_deinit(&remote_auth_request_token); +} + + +CU_Test(ddssec_builtin_validate_remote_identity,invalid_remote_identity_token ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle remote_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_AuthRequestMessageToken local_auth_request_token; + DDS_Security_AuthRequestMessageToken remote_auth_request_token; + DDS_Security_IdentityToken remote_identity_token; + DDS_Security_GUID_t remote_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have validate_local_identity function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->validate_remote_identity != NULL); + + initialize_identity_token(&remote_identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + fill_auth_request_token(&remote_auth_request_token); + set_remote_participant_guid(&remote_participant_guid, 0); + + ddsrt_free(remote_identity_token.class_id); + remote_identity_token.class_id = ddsrt_strdup("DDS:Auth:PKI-PH:1.0"); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + ddsrt_free(remote_identity_token.class_id); + remote_identity_token.class_id = ddsrt_strdup("DDS:Auth:PKI-DH:2.0"); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + deinitialize_identity_token(&remote_identity_token); + DDS_Security_DataHolder_deinit(&remote_auth_request_token); +} + + +CU_Test(ddssec_builtin_validate_remote_identity,invalid_auth_req_token ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle remote_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_AuthRequestMessageToken local_auth_request_token; + DDS_Security_AuthRequestMessageToken remote_auth_request_token; + DDS_Security_IdentityToken remote_identity_token; + DDS_Security_GUID_t remote_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + unsigned char *futureChallenge; + + /* Check if we actually have validate_local_identity function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->validate_remote_identity != NULL); + + initialize_identity_token(&remote_identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + fill_auth_request_token(&remote_auth_request_token); + set_remote_participant_guid(&remote_participant_guid, 0); + + /* check invalid class_id (empty) string for class_id */ + ddsrt_free(remote_auth_request_token.class_id); + remote_auth_request_token.class_id = ddsrt_strdup(""); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + /* check invalid class_id (NULL) string for class_id */ + ddsrt_free(remote_auth_request_token.class_id); + remote_auth_request_token.class_id = NULL; + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + /* check invalid class_id string for class_id */ + remote_auth_request_token.class_id = ddsrt_strdup("DDS:Auth:PKI-DH:2.0+AuthReq"); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + /* check invalid property name (empty) for future_challenge */ + ddsrt_free(remote_auth_request_token.class_id); + remote_auth_request_token.class_id = ddsrt_strdup(AUTH_REQUEST_TOKEN_CLASS_ID); + ddsrt_free(remote_auth_request_token.binary_properties._buffer[0].name); + remote_auth_request_token.binary_properties._buffer[0].name = ddsrt_strdup(""); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + /* check invalid property name (NULL) for future_challenge */ + ddsrt_free(remote_auth_request_token.binary_properties._buffer[0].name); + remote_auth_request_token.binary_properties._buffer[0].name = NULL; + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + /* check invalid property name for future_challenge */ + ddsrt_free(remote_auth_request_token.binary_properties._buffer[0].name); + remote_auth_request_token.binary_properties._buffer[0].name = ddsrt_strdup("challenge"); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + /* check missing future_challenge property*/ + ddsrt_free(remote_auth_request_token.binary_properties._buffer[0].name); + remote_auth_request_token.binary_properties._buffer[0].name = ddsrt_strdup(AUTH_REQUEST_TOKEN_FUTURE_PROP_NAME); + futureChallenge = remote_auth_request_token.binary_properties._buffer[0].value._buffer; + remote_auth_request_token.binary_properties._buffer[0].value._buffer = NULL; + remote_auth_request_token.binary_properties._buffer[0].value._length = 0; + remote_auth_request_token.binary_properties._buffer[0].value._maximum = 0; + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + /* check incorrect future_challenge property, too small */ + remote_auth_request_token.binary_properties._buffer[0].value._buffer = futureChallenge; + remote_auth_request_token.binary_properties._buffer[0].value._length = 16; + remote_auth_request_token.binary_properties._buffer[0].value._maximum = 32; + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + /* check incorrect future_challenge property: value is NULL */ + remote_auth_request_token.binary_properties._buffer[0].value._buffer = NULL; + remote_auth_request_token.binary_properties._buffer[0].value._length = 32; + remote_auth_request_token.binary_properties._buffer[0].value._maximum = 32; + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + remote_auth_request_token.binary_properties._buffer[0].value._buffer = futureChallenge; + + deinitialize_identity_token(&remote_identity_token); + DDS_Security_DataHolder_deinit(&remote_auth_request_token); +} + +CU_Test(ddssec_builtin_validate_remote_identity,already_validated_same_token ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle remote_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_IdentityHandle remote_identity_handle2 = DDS_SECURITY_HANDLE_NIL; + DDS_Security_AuthRequestMessageToken local_auth_request_token = DDS_SECURITY_TOKEN_INIT; + DDS_Security_AuthRequestMessageToken remote_auth_request_token; + DDS_Security_IdentityToken remote_identity_token; + DDS_Security_GUID_t remote_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + /* Check if we actually have validate_local_identity function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->validate_remote_identity != NULL); + + initialize_identity_token(&remote_identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + fill_auth_request_token(&remote_auth_request_token); + set_remote_participant_guid(&remote_participant_guid, 0); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL (result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + CU_ASSERT (remote_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT (check_auth_request_token(&local_auth_request_token, 0)); + + reset_exception(&exception); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle2, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL (result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + CU_ASSERT (remote_identity_handle == remote_identity_handle2); + CU_ASSERT (check_auth_request_token(&local_auth_request_token, 0)); + + reset_exception(&exception); + + deinitialize_identity_token(&remote_identity_token); + DDS_Security_DataHolder_deinit(&remote_auth_request_token); + DDS_Security_DataHolder_deinit(&local_auth_request_token); + + success = auth->return_identity_handle(auth, remote_identity_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); +} + + +CU_Test(ddssec_builtin_validate_remote_identity,already_validated_different_token ) +{ + DDS_Security_ValidationResult_t result; + DDS_Security_IdentityHandle remote_identity_handle = DDS_SECURITY_HANDLE_NIL; + DDS_Security_IdentityHandle remote_identity_handle2 = DDS_SECURITY_HANDLE_NIL; + DDS_Security_AuthRequestMessageToken local_auth_request_token = DDS_SECURITY_TOKEN_INIT; + DDS_Security_AuthRequestMessageToken remote_auth_request_token; + DDS_Security_IdentityToken remote_identity_token; + DDS_Security_IdentityToken remote_identity_token2; + DDS_Security_GUID_t remote_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + /* Check if we actually have validate_local_identity function. */ + CU_ASSERT_FATAL (auth != NULL); + CU_ASSERT_FATAL (local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL (auth->validate_remote_identity != NULL); + + initialize_identity_token(&remote_identity_token, RSA_2048_ALGORITHM_NAME, RSA_2048_ALGORITHM_NAME); + fill_auth_request_token(&remote_auth_request_token); + set_remote_participant_guid(&remote_participant_guid, 0); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT_FATAL (result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE); + CU_ASSERT_FATAL (remote_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT (check_auth_request_token(&local_auth_request_token, 0)); + + reset_exception(&exception); + + initialize_identity_token_w_sn( + &remote_identity_token2, + SUBJECT_NAME_IDENTITY_CERT_2, RSA_2048_ALGORITHM_NAME, + SUBJECT_NAME_IDENTITY_CA_2, RSA_2048_ALGORITHM_NAME); + + result = auth->validate_remote_identity( + auth, + &remote_identity_handle2, + &local_auth_request_token, + &remote_auth_request_token, + local_identity_handle, + &remote_identity_token2, + &remote_participant_guid, + &exception); + + if (result == DDS_SECURITY_VALIDATION_FAILED) { + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT (result == DDS_SECURITY_VALIDATION_FAILED); + CU_ASSERT (exception.minor_code != 0); + CU_ASSERT (exception.message != NULL); + + reset_exception(&exception); + + deinitialize_identity_token(&remote_identity_token); + deinitialize_identity_token(&remote_identity_token2); + DDS_Security_DataHolder_deinit(&remote_auth_request_token); + DDS_Security_DataHolder_deinit(&local_auth_request_token); + + success = auth->return_identity_handle(auth, remote_identity_handle, &exception); + CU_ASSERT_TRUE (success); + + if (!success) { + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + reset_exception(&exception); +} + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Governance_ok.p7s b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Governance_ok.p7s new file mode 100644 index 0000000..c39903f --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Governance_ok.p7s @@ -0,0 +1,114 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----DB94A190D9780A24156FB0E8F1E76B5F" + +This is an S/MIME signed message + +------DB94A190D9780A24156FB0E8F1E76B5F +Content-Type: text/plain + + + + + + + + + 0 + 230 + + + + + false + + + true + + + ENCRYPT + + + ENCRYPT + + + NONE + + + + + * + + + true + + + true + + + false + + + false + + + ENCRYPT + + + ENCRYPT + + + + + + +------DB94A190D9780A24156FB0E8F1E76B5F +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGSAYJKoZIhvcNAQcCoIIGOTCCBjUCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCAnswggJ3AgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggeQwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTgwOTEzMDczOTUwWjAvBgkqhkiG9w0BCQQxIgQgXv8DkvlwebXMwHDbNc0/Pc30 +gyG3xWCnwet49TRMWFsweQYJKoZIhvcNAQkPMWwwajALBglghkgBZQMEASowCwYJ +YIZIAWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG9w0DAgIC +AIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwDQYJKoZI +hvcNAQEBBQAEggEANy8t0EFmv5j1n0+mMn2ut3Chu8PSJceC8gd34IiKq79uC1O3 +PbL9xgiJ2vz7QiTEEeNL2q+CG77cXOcHGUWa4nvbggr/9CqLfHEKGQxDfyXlJZfM +8l550xIXRRBOQ7ilOGLD4QJFfbf9XA4rMuRe8WEYN3FleAaYBJag1tMPg1SS6tgA +BBDM9b1kXHU319zYOk6kZFjlbwHv6XO22SEVRUpXrKudAI8hrGvwksF/+W0S/jS5 +NmYtj/1oMGlCGIaA5rs27H9CkgwrzoMQ3MsR98JlwEUSa4PEe8CClsIziOulQxsp +MicBlMWL0rzpBPVfPTE4gZ/kP7hGBDEQlRzVTA== + +------DB94A190D9780A24156FB0E8F1E76B5F-- + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_different_subject_representation.p7s b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_different_subject_representation.p7s new file mode 100644 index 0000000..13273ba --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_different_subject_representation.p7s @@ -0,0 +1,96 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----57B71E0E17C33E9E1569D11B98DA1D03" + +This is an S/MIME signed message + +------57B71E0E17C33E9E1569D11B98DA1D03 +Content-Type: text/plain + + + + + + /O=Internet Widgits Pty Ltd/ST=Some-State/C=NL/CN=CHAM500 cert + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + + + ALLOW + + + + +------57B71E0E17C33E9E1569D11B98DA1D03 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgocQS4FLDqU6X3kzlYhW9GLLt +ItKIWQ9ghIL29OEyHPcwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBADPtNnKmzgMNaoeAiyxH +0oO3D9qsLWlon9eG+ri3e4O4IBGAwPtwN92ah3OmqXeB7xqBlZwnR4jQIxwVl8eL +Zs2y7lJ6LxPYHJj6qERlYbRjS55X7Wnjcwy81w+yQelSLFcKvdmrV5HIuLbeskWw +WiJxu3Sxtett3NnJxV5za6C27pxGXmv+xdspUe1Zeoz7WjAA0ljOazSUXAyCriQH +LXSGjTM8Lgn/P8xJTVzGgxmLmGm9fAhhYk+25G9Fspomigvnj+B6HobEf4xKA/Mm +WPaLsNkLtbi954g5+EM9AOjpCR/2Ii1NB4lWeKGZLtbEm71dEUe2VDePy2ju+oOB +9ec= + +------57B71E0E17C33E9E1569D11B98DA1D03-- + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_different_subject_representation.xml b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_different_subject_representation.xml new file mode 100644 index 0000000..585030e --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_different_subject_representation.xml @@ -0,0 +1,44 @@ + + + + + /O=Internet Widgits Pty Ltd/ST=Some-State/C=NL/CN=CHAM500 cert + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + + + ALLOW + + + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_expired.p7s b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_expired.p7s new file mode 100644 index 0000000..bf35bf7 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_expired.p7s @@ -0,0 +1,243 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----11798C99B4C31493D0479BB8A2064C72" + +This is an S/MIME signed message + +------11798C99B4C31493D0479BB8A2064C72 +Content-Type: text/plain + + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2016-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=Spare cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + ALLOW + + + + +------11798C99B4C31493D0479BB8A2064C72 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgXPEkUvQgZwRMdZgxT8k/mrsJ +delB0E3RjpayHUkKYzowgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAA/TNULF62fO5mfjXm1L +Yk4Dg/5ZxAF/grDAjamo5v2fxGn6B1rrkj8YtyB1FEA0moM/cL31kNXNMqLvFdhY +lHCmX8x5PHkKzLihTIMx6diSCupBvvqUACeA7Ir1A3tMqW5tYYMg6sZ/YolgLLFG +8XmhttpEibtZm90MN3Xpsa4TiW5PlEWHC5ai3tyeyd/RCVoeQJVA0pAytmjdf2Mw +C3W/28tUxVCAjdlqXYap6jWZlNv/43P5HED837bF5iqoa1dTvDirca6WPanNjp28 +GQDi4bnD1kAk8wAKIm14qwS+fzxM3SKxJtdQuUCx+s/tPma4bLCqt843ok35SoWo +QKM= + +------11798C99B4C31493D0479BB8A2064C72-- + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_expired.xml b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_expired.xml new file mode 100644 index 0000000..f408942 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_expired.xml @@ -0,0 +1,191 @@ + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2016-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=Spare cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + ALLOW + + + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_invalid_data.p7s b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_invalid_data.p7s new file mode 100644 index 0000000..b3b969e --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_invalid_data.p7s @@ -0,0 +1,219 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----62BE4CE8CF1FCB0420A2F2884B1618E6" + +This is an S/MIME signed message + +------62BE4CE8CF1FCB0420A2F2884B1618E6 +Content-Type: text/plain + + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 430 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + + +------62BE4CE8CF1FCB0420A2F2884B1618E6 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQghoicue+FOmdIHF9rpsNCfmjP ++ZyN+t9kCdmR68JCJU0wgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAI0BX2tu2DbQjvuzKG35 +myNBcOC9ZzRDqJEtmQhcY/2hAJzurlnclJVTEXFyXdpV4ywtA+lQvbtToh11AvnY +IY1QWNVm19mfO1J6m6PFu18tizd30sG7p1TZKxGB3zDeVVqmedZ+o7QJHv9/ixzz +Pyo2B9tG5Su94+ADc0LQNyGICjeMr7L6dhFDsm7fXBi8pMBKy/zEAynTA3r1ibsn +5zlizPMlad2HCaYv44x7Xksg9FSbzJwJpTiprbQbZSUPYk4WlfVz0l4plzRKu4AP +lCOsdRE6C6GQFnK5bLyndu3Ycp10niwfkfobruCDyigu+gjZtmmF/T7A8Xkk1uvx +fAM= + +------62BE4CE8CF1FCB0420A2F2884B1618E6-- + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_invalid_data.xml b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_invalid_data.xml new file mode 100644 index 0000000..5ebb397 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_invalid_data.xml @@ -0,0 +1,167 @@ + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 430 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_missing_subject_component.p7s b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_missing_subject_component.p7s new file mode 100644 index 0000000..1362a86 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_missing_subject_component.p7s @@ -0,0 +1,96 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----DE8A6693E9678989859C23D21F4587AD" + +This is an S/MIME signed message + +------DE8A6693E9678989859C23D21F4587AD +Content-Type: text/plain + + + + + + /O=Internet Widgits Pty Ltd/ST=Some-State/CN=CHAM500 cert + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + + + ALLOW + + + + +------DE8A6693E9678989859C23D21F4587AD +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgrFwsV4SyJfHq+dBhrRXj6PlS +nZYIo1hJ+L29+U2Xpk0wgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAAt1pbdIgmqHNrruevrr +TUptMNDw6YzlmXpWAq3KZBGaeaiHpYbkI+WhJJee9hG7bF9NGI/SfjPhiaiTjk2X +XCgmFZJUQhY8pOWkVPSAhBxd+r4kQtRxo2Na148Z2nrxeqcLbk+SE1hxTwT2OgLh +HWHBoQofZcRFp36Z9v51fZHAZLbQ8pD45+oAe/7ElyrO80MnJc+2RUxcnLScT1J0 +ykgTsgrQxcVVZX6EFHhQxnzpqCbjGvpdGSnyojAFI4PuQ3uNiOTPTYqad4jf/vIq +YHngEXSMN8wkd8bopl1EPVdxDqKkXuwAb29Q6UvDWLQ4IDZkdHTWc/ojiKjxWsKF +wuQ= + +------DE8A6693E9678989859C23D21F4587AD-- + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_missing_subject_component.xml b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_missing_subject_component.xml new file mode 100644 index 0000000..de70a1c --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_missing_subject_component.xml @@ -0,0 +1,44 @@ + + + + + /O=Internet Widgits Pty Ltd/ST=Some-State/CN=CHAM500 cert + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + + + ALLOW + + + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_not_signed.p7s b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_not_signed.p7s new file mode 100644 index 0000000..8759d91 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_not_signed.p7s @@ -0,0 +1,33 @@ + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + + + * + + + + DENY + + + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_notyet.p7s b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_notyet.p7s new file mode 100644 index 0000000..7fd4098 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_notyet.p7s @@ -0,0 +1,243 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----F87E07CA6CCEAB50B03A143AC2354EB4" + +This is an S/MIME signed message + +------F87E07CA6CCEAB50B03A143AC2354EB4 +Content-Type: text/plain + + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2035-09-15T01:00:00 + 2046-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=Spare cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + ALLOW + + + + +------F87E07CA6CCEAB50B03A143AC2354EB4 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQg0GGu1gWhHWhfWnmg55AIr4tv +zMK0kIxNfJYQbb7LpJ8wgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBALsPI2+b0w+iUPJGJeMd +VdrY7s/GZYm6M8qOA5fmh3144bY1rZRjdHjXtLdaNDNN1Z5buRCiQcklAilf6O14 +7u6a5HR12N4LTbg3OYQplwz4ed/wBsL726htmkAK3JogGk5OVLqmmdrz3UOD8IaZ +wAfx2tpj3VJOVuW0XsqOrzQpnOjGWcPeOw6NAxRH1gLsxBP9HDz5+wrsKXjV/zG8 +dFTaZ0bKnBXTp5ccc9jB4qbcllC9nlJkJszGqvwOP7zWBAOXeU+joUGM4Bt+8Pmt +pKsVAmEqMpc368RMayDBWtTqUWpUKvDh4HSkuOGD4Hj5ViAoLFjisROhIK2d98XI +cRQ= + +------F87E07CA6CCEAB50B03A143AC2354EB4-- + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_notyet.xml b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_notyet.xml new file mode 100644 index 0000000..99fec50 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_notyet.xml @@ -0,0 +1,191 @@ + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2035-09-15T01:00:00 + 2046-09-15T01:00:00 + + + + + 0 + 230 + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 230 + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + DENY + + + CN=Spare cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 20 + 30 + + 0 + 23 + + + 100 + 120 + + 200 + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + K* + *OldMessage + OldMessanger + NewMessage + + + Apart + Bpa?t* + + + + + + + 0 + 23 + + + 100 + 120 + + 200 + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + P* + *WrongMessage + FakeMessanger + ChangedMessage + + + Apart + Bpa?t* + + + + aTagName1 + aTagValue1 + + + + + + ALLOW + + + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_ok.p7s b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_ok.p7s new file mode 100644 index 0000000..052075b --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_ok.p7s @@ -0,0 +1,85 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----6B91005B007BBA8EDE10CD1CE487DB27" + +This is an S/MIME signed message + +------6B91005B007BBA8EDE10CD1CE487DB27 +Content-Type: text/plain + + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + + + * + + + + DENY + + + + +------6B91005B007BBA8EDE10CD1CE487DB27 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQgl3LfUhn9L0vG/3QRPVYptcYw +/NH5HMN99aMe9JAT+LAwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAHe9vakfXPvbpgMeqlhG +SW6Z3uVA3Yri9bgQDpJ9daIUsM0/TLBSQVs85twTMXvqUSntKbfSGehxDQ9F+yje +mOEPMIwxOqcVyc2jpqoYsUWqpwiiZyk49DHUFrOfWJUx+rKdBftZWkxD05Wkovhk +2d4hGS/65Haoho4Z0AZwcyH+F52FZMiqw7I9FKrPlhxvJfQXmhIjOKtnvWnQ+Ar7 +YYiSrBEHMCy82LF1aKzz0nkL1SYWQHuQX475qoU4LMYY1J8WsD3rSBeq4GYZrl2K +X/JcOquMYqjfJLMYZY4fsc3FgEBkKNqJz1tDZ3ir24VMl+WsbEjVK8oXe/wt4V0U +aNQ= + +------6B91005B007BBA8EDE10CD1CE487DB27-- + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_ok.xml b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_ok.xml new file mode 100644 index 0000000..8759d91 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_ok.xml @@ -0,0 +1,33 @@ + + + + + CN=CHAM500 cert,O=Internet Widgits Pty Ltd,ST=Some-State,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + + + * + + + + DENY + + + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_unknown_ca.p7s b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_unknown_ca.p7s new file mode 100644 index 0000000..6a2905a --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_unknown_ca.p7s @@ -0,0 +1,87 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----7FBACED8776E5A4CF7612C83F9C33E17" + +This is an S/MIME signed message + +------7FBACED8776E5A4CF7612C83F9C33E17 +Content-Type: text/plain + + + + + + /C=NL/ST=Some-State/O=ADLINK Technolocy Inc./CN=adlinktech.com + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + + + * + + + + DENY + + + + +------7FBACED8776E5A4CF7612C83F9C33E17 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGywYJKoZIhvcNAQcCoIIGvDCCBrgCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggPKMIIDxjCCAq4CCQCBuTktP0h8BDANBgkqhkiG9w0BAQsFADCB +pDEWMBQGA1UEBwwNTG9jYWxpdHkgTmFtZTEhMB8GA1UECwwYT3JnYW5pemF0aW9u +YWwgVW5pdCBOYW1lMRwwGgYJKoZIhvcNAQkBFg1FbWFpbCBBZGRyZXNzMQswCQYD +VQQGEwJVUzELMAkGA1UECAwCTkoxGjAYBgNVBAoMEUV4YW1wbGUgU2lnbmVyIENB +MRMwEQYDVQQDDApFeGFtcGxlIENBMB4XDTE4MDgxNTA4NTE0MVoXDTQzMDgwOTA4 +NTE0MVowgaQxFjAUBgNVBAcMDUxvY2FsaXR5IE5hbWUxITAfBgNVBAsMGE9yZ2Fu +aXphdGlvbmFsIFVuaXQgTmFtZTEcMBoGCSqGSIb3DQEJARYNRW1haWwgQWRkcmVz +czELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5KMRowGAYDVQQKDBFFeGFtcGxlIFNp +Z25lciBDQTETMBEGA1UEAwwKRXhhbXBsZSBDQTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALStAQ0yjM2qAWwsOXdX3hiyoZ6DDHWOTNI5LoCZGaN9rUZe +MY0waSxWNQ0ruURgZISeOFkdQTAE81Em+UaZI+MZvfYcEcSlVtF6yve/WnIzRYWu +f917moMCAInktfch4E6mskr4h7n+9sEz+3GsQS8SQRtwUe+PiXzjZrqHSbLC4Kn3 +/b8Mt+Ww3a4FyjHDZQJZsGSvrScr0Gq3xeKfMwb+KYNEnmh0o4os0gEGA4KUR+/1 +YDl1NmxQnm/AIMqwJzeaezBoMn0Nsi+OlAms85imGURNj9BCEJZBWwuuNL5ECDAq +WLOM3AKUsApVgtGd8/OLWW1RwYkW8uqTtkIR87MCAwEAATANBgkqhkiG9w0BAQsF +AAOCAQEAokKC77/kvxlObLSwkT5+7+S+DeznLBRiGVEh8+9PQw1q91sjiOZWf0e3 +T3XPH7CR/NDYoQJkrsqzIwKYrj41z/1jAs+HkH45NpTFiGlUFXNs5iwNh4RUqgf4 +e78Mge4q7pHMFzWTEwEn4DJMGcDDjLW1kN8GobGwHR7O0MpAJKrqcBSo+SPomnQv +TgiEMQ+Vlz0EJx6JPsq8c7HrxlSdeDAAWIOww/wcGyzlpYEoyz6voSSfdhMt5iy5 +k5BvhBJnTiJTasCHy9KRuis/6qpTZKEj0d7J7LAqpGh8oRIphMwCbFYQT0QBgV6p +gM8Ufss/RZ6CshMNxz7KtIYpvmxPPTGCAsUwggLBAgEBMIGyMIGkMRYwFAYDVQQH +DA1Mb2NhbGl0eSBOYW1lMSEwHwYDVQQLDBhPcmdhbml6YXRpb25hbCBVbml0IE5h +bWUxHDAaBgkqhkiG9w0BCQEWDUVtYWlsIEFkZHJlc3MxCzAJBgNVBAYTAlVTMQsw +CQYDVQQIDAJOSjEaMBgGA1UECgwRRXhhbXBsZSBTaWduZXIgQ0ExEzARBgNVBAMM +CkV4YW1wbGUgQ0ECCQCBuTktP0h8BDANBglghkgBZQMEAgEFAKCB5DAYBgkqhkiG +9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xODA5MTMwOTIzMDNa +MC8GCSqGSIb3DQEJBDEiBCCvP08gFBO7651mPPDFQ2suhL+eprGCGuRLXmiBmdvx +ITB5BgkqhkiG9w0BCQ8xbDBqMAsGCWCGSAFlAwQBKjALBglghkgBZQMEARYwCwYJ +YIZIAWUDBAECMAoGCCqGSIb3DQMHMA4GCCqGSIb3DQMCAgIAgDANBggqhkiG9w0D +AgIBQDAHBgUrDgMCBzANBggqhkiG9w0DAgIBKDANBgkqhkiG9w0BAQEFAASCAQB/ +4EQel+0LsmiNFCUjWM68u4ZvPtFBpeDe456DJuG6QR0LIzW42U7N4P2ZTIqjpGZx +YekBCNdkiVy6ER5IA4WfcKd6zXZEuXVxkMrGpJlqGdd+IdZpTsrBygGZJS4vMUfD +/6ty6OycET88RmJIu4V/TM3yLVKzHuj6TxCXb4OIYx8g3mdXUwUrp6DGgqggRSPJ +tatbpnqGZGcvty8MusXVnjnEwUWnJ/jojypY3MyL4MTbjufjv0K6NKQ3RzoLssot +SLq0YDLwvX/s9sLXDCedAwFXBS/6Qv56v0M2x4o8e3Eul7gGTMuCd/dJ0BhF8CW+ +IGxR5I3xXssh/AuWRRtV + +------7FBACED8776E5A4CF7612C83F9C33E17-- + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_unknown_subject.p7s b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_unknown_subject.p7s new file mode 100644 index 0000000..fb488c7 --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_unknown_subject.p7s @@ -0,0 +1,85 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----7B161F9203F175A7F82A389A3E044741" + +This is an S/MIME signed message + +------7B161F9203F175A7F82A389A3E044741 +Content-Type: text/plain + + + + + + gibberish + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + + + * + + + + DENY + + + + +------7B161F9203F175A7F82A389A3E044741 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIGXgYJKoZIhvcNAQcCoIIGTzCCBksCAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggORMIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEB +CwUAMFwxCzAJBgNVBAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQK +DBZBRExJTksgVGVjaG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNv +bTAgFw0xODA3MzAxMjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMC +TkwxEzARBgNVBAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9s +b2N5IEluYy4xFzAVBgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blID +ehV6XCxrnGXusTCDuFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9w +icp3BGSpZZax/TcONjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLs +DFFC+a0qn2RFh37rcWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074 +BRDXVivx+wVD951LFNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiy +SogRWAmKhysLQudukHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNV +HQ4EFgQURWMbWvBKZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJv +RV1/tyc1R82k0+gwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ +ysVtvHnk2hpu9yNDLCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9X +Vh0rGoR/6nHzo3TIeiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9 +yghhKHHqNDvSsAL0KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbt +lLX3QnwVOmaRyzylPiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42 ++OyLqcH1rKT6XhcshjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb +6SDB340BFmtgDHbFHTGCApEwggKNAgEBMGkwXDELMAkGA1UEBhMCTkwxEzARBgNV +BAgMClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4x +FzAVBgNVBAMMDmFkbGlua3RlY2guY29tAgkA2yveybQ2vKkwDQYJYIZIAWUDBAIB +BQCggfowGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcN +MTkwMzI5MTMwODAzWjAvBgkqhkiG9w0BCQQxIgQg44QSCYJrKGm9hdPbOKQjrnQ8 +LXMSbo0mve1cRKvrm3gwgY4GCSqGSIb3DQEJDzGBgDB+MAsGCWCGSAFlAwQBKjAI +BgYqhQMCAgkwCAYGKoUDAgIVMAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYI +KoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIH +MA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIBAH/fJ90OwloC73faPAGC +VRZrhW/gSsy/1VnprvWdDAU1ZZK+srIISFZAy19LcApTis0Vy9yz2PG8pue49R+y +UF6mCDSuN/l9SRBdUN+CXQdQ8sGq5SHXNhGzSX/nbR20ol4cSUMpKlEGx66E0KUW +tkk8HzYw7aHMiwK2E2Y0sbm/M/rdmAbgEoywYfvc25V4FHP66TstfCLBjN9Hz3bH +WcrCZuPjZo6vBd/rIJQSlgH81aCWn5RfCIccbc3iogwzIhYxAr6d+4do3LNa6H80 +W6CMgl0AnWFfa4QwnXFUzb1/W2rFjHp453w1Cbqk4Ll4ZlVJr4fzIuyuJMQlMrmK +1P0= + +------7B161F9203F175A7F82A389A3E044741-- + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_unknown_subject.xml b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_unknown_subject.xml new file mode 100644 index 0000000..8a55faf --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/etc/Test_Permissions_unknown_subject.xml @@ -0,0 +1,33 @@ + + + + + gibberish + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + + + * + + + + DENY + + + diff --git a/src/security/builtin_plugins/tests/validate_remote_permissions/src/validate_remote_permissions_utests.c b/src/security/builtin_plugins/tests/validate_remote_permissions/src/validate_remote_permissions_utests.c new file mode 100644 index 0000000..700a38a --- /dev/null +++ b/src/security/builtin_plugins/tests/validate_remote_permissions/src/validate_remote_permissions_utests.c @@ -0,0 +1,1067 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/io.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/types.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/openssl_support.h" +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "common/src/loader.h" +#include "config_env.h" + +static const char *ACCESS_PERMISSIONS_TOKEN_ID = "DDS:Access:Permissions:1.0"; +static const char *AUTH_PROTOCOL_CLASS_ID = "DDS:Auth:PKI-DH:1.0"; + +static const char *PROPERTY_IDENTITY_CA = "dds.sec.auth.identity_ca"; +static const char *PROPERTY_PRIVATE_KEY = "dds.sec.auth.private_key"; +static const char *PROPERTY_IDENTITY_CERT = "dds.sec.auth.identity_certificate"; +static const char *PROPERTY_PERMISSIONS_CA = "dds.sec.access.permissions_ca"; +static const char *PROPERTY_PERMISSIONS = "dds.sec.access.permissions"; +static const char *PROPERTY_GOVERNANCE = "dds.sec.access.governance"; + +static const char *PROPERTY_PERMISSIONS_CA_SN = "dds.perm_ca.sn"; +static const char *PROPERTY_PERMISSIONS_CA_ALGO = "dds.perm_ca.algo"; +static const char *PROPERTY_C_ID = "c.id"; +static const char *PROPERTY_C_PERM = "c.perm"; + +static const char *SUBJECT_NAME_PERMISSIONS_CA = "C=NL, ST=Some-State, O=ADLINK Technolocy Inc., CN=adlinktech.com"; +static const char *RSA_2048_ALGORITHM_NAME = "RSA-2048"; + +static const char *RELATIVE_PATH_TO_ETC_DIR = "/validate_remote_permissions/etc/"; + +static const char *identity_certificate = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEQTCCAymgAwIBAgIINpuaAAnrQZIwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE3MDIy\n" + "MjIyMjIwMFoYDzIyMjIwMjIyMjIyMjAwWjBcMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRUwEwYDVQQDEwxDSEFNNTAwIGNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n" + "ggEKAoIBAQDCpVhivH/wBIyu74rvQncnSZqKyspN6CvD1pmV9wft5PHhVt9jV79v\n" + "gSub5LADoRHAgFdv9duYgBr17Ob6uRrIY4B18CcrCjhQcC4gjx8y2jl9PeYm+qYD\n" + "3o44FYBrBq0QCnrQgKsb/qX9Z+Mw/VUiw65x68W876LEHQQoEgT4kxSuagwBoVRk\n" + "ePD6fYAKmT4XS3x+O0v+rHESTcsKF6yMadgp7h3eH1b8kJTzSx8JV9Zzq++mxjox\n" + "qhbBVP5nDze2hhSIeCkCvSrx7efkgKS4AQXa5/Z44GiAu1TfXXUqdic9rxwD0edn\n" + "ajNElnZe7sjok/0yuqvH+2hSqpNva/zpAgMBAAGjggEAMIH9MAwGA1UdDwQFAwMH\n" + "/4AwgewGA1UdJQSB5DCB4QYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAwYI\n" + "KwYBBQUHAwQGCCsGAQUFBwMIBgorBgEEAYI3AgEVBgorBgEEAYI3AgEWBgorBgEE\n" + "AYI3CgMBBgorBgEEAYI3CgMDBgorBgEEAYI3CgMEBglghkgBhvhCBAEGCysGAQQB\n" + "gjcKAwQBBggrBgEFBQcDBQYIKwYBBQUHAwYGCCsGAQUFBwMHBggrBgEFBQgCAgYK\n" + "KwYBBAGCNxQCAgYIKwYBBQUHAwkGCCsGAQUFBwMNBggrBgEFBQcDDgYHKwYBBQID\n" + "BTANBgkqhkiG9w0BAQsFAAOCAQEAawdHy0Xw7nTK2ltp91Ion6fJ7hqYuj///zr7\n" + "Adt6uonpDh/xl3esuwcFimIJrJrHujnGkL0nLddRCikmnzuBMNDWS6yq0/Ckl/YG\n" + "yjNr44dlX24wo+MVAgkj3/8CyWDZ3a8kBg9QT3bs2SqbjmhTrXN1DRyf9S5vJysE\n" + "I7V1gTN66BeKL64hOrAlRVrEu8Ds6TWL6Q/YH+61ViZkoLTeSaPjH4nknaFr4C35\n" + "iji0JhkyfRHRRVPHFnaj25AkxOrSV64qVKoTMjDl5fji5iMGtjm6iJ7q05ml/qDl\n" + "nLotHXemZNvYhbwUmRzbt4Dls9EMH4VRbP85I94nM5TAvtHVNA==\n" + "-----END CERTIFICATE-----\n"; + +static const char *identity_ca = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIEmTCCA4GgAwIBAgIIZ5gEIUFhO5wwDQYJKoZIhvcNAQELBQAwXzELMAkGA1UE\n" + "BhMCTkwxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp\n" + "ZGdpdHMgUHR5IEx0ZDEYMBYGA1UEAxMPQ0hBTTUwMCByb290IGNhMCAXDTE4MDIx\n" + "MjE1MDUwMFoYDzIyMjIwMjIyMjIyMjAwWjBfMQswCQYDVQQGEwJOTDETMBEGA1UE\n" + "CBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRk\n" + "MRgwFgYDVQQDEw9DSEFNNTAwIHJvb3QgY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" + "DwAwggEKAoIBAQC6Fa3TheL+UrdZCp9GhU/2WbneP2t/avUa3muwDttPxeI2XU9k\n" + "ZjBR95mAXme4SPXHk5+YDN319AqIje3oKhzky/ngvKH2GkoJKYxWnuDBfMEHdViz\n" + "2Q9/xso2ZvH50ukwWa0pfx2/EVV1wRxeQcRd/UVfq3KTJizG0M88mOYvGEAw3LFf\n" + "zef7k1aCuOofQmBvLukUudcYpMzfyHFp7lQqU4CcrrR5RtmfiUfrWfdGLea2iPDB\n" + "pJgN8ESOMwEHtOTEBDclYnH9L4t7CHQz+fXXS5IWFsDK9fCMQjnxDsDVeNrNzTYL\n" + "FaZrMg9S6IUQCEsQWsnq5weS8omOpVLUm9klAgMBAAGjggFVMIIBUTAMBgNVHRME\n" + "BTADAQH/MB0GA1UdDgQWBBQg2FZB/j8uWDVnJhjwXkX278znSTAfBgNVHSMEGDAW\n" + "gBQg2FZB/j8uWDVnJhjwXkX278znSTAPBgNVHQ8BAf8EBQMDB/+AMIHvBgNVHSUB\n" + "Af8EgeQwgeEGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwME\n" + "BggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK\n" + "KwYBBAGCNwoDAwYKKwYBBAGCNwoDBAYJYIZIAYb4QgQBBgsrBgEEAYI3CgMEAQYI\n" + "KwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUIAgIGCisGAQQBgjcU\n" + "AgIGCCsGAQUFBwMJBggrBgEFBQcDDQYIKwYBBQUHAw4GBysGAQUCAwUwDQYJKoZI\n" + "hvcNAQELBQADggEBAKHmwejWRwGE1wf1k2rG8SNRV/neGsZ6Qfqf6co3TpR/Wi1s\n" + "iZDvSeT/rbqNBS7z34xnG88NIUwu00y78e8Mfon31ZZbK4Uo7fla9/D3ukdJqPQC\n" + "LKdbKJjR2kH+KCukY/1rghjJ8/X+t2egBit0LCOdsFCl07Sfksb9kpGUIZSFcYYm\n" + "geqhjhoNwxazzHiw+QWHC5HG9248JIizBmy1aymNWuMnPudhjHAnPcsIlqMVNq3t\n" + "Rv9ap7S8JeCxHVRPJvJeCwXWvW3dW/v3xH52Yn/fqRblN1w9Fxz5NhopKx0gj/Jd\n" + "sw2N4Fk4gaOWEolFpa0bwNw8nAx7moehZpowzfw=\n" + "-----END CERTIFICATE-----\n"; + +static const char *private_key = + "data:,-----BEGIN RSA PRIVATE KEY-----\n" + "MIIEogIBAAKCAQEAwqVYYrx/8ASMru+K70J3J0maisrKTegrw9aZlfcH7eTx4Vbf\n" + "Y1e/b4Erm+SwA6ERwIBXb/XbmIAa9ezm+rkayGOAdfAnKwo4UHAuII8fMto5fT3m\n" + "JvqmA96OOBWAawatEAp60ICrG/6l/WfjMP1VIsOucevFvO+ixB0EKBIE+JMUrmoM\n" + "AaFUZHjw+n2ACpk+F0t8fjtL/qxxEk3LChesjGnYKe4d3h9W/JCU80sfCVfWc6vv\n" + "psY6MaoWwVT+Zw83toYUiHgpAr0q8e3n5ICkuAEF2uf2eOBogLtU3111KnYnPa8c\n" + "A9HnZ2ozRJZ2Xu7I6JP9Mrqrx/toUqqTb2v86QIDAQABAoIBAC1q32DKkx+yMBFx\n" + "m32QiLUGG6VfBC2BixS7MkMnzRXZYgcuehl4FBc0kLRjfB6cqsO8LqrVN1QyMBhK\n" + "GutN3c38SbE7RChqzhEW2+yE+Mao3Nk4ZEecHLiyaYT0n25ZtHAVwep823BAzwJ+\n" + "BykbM45VEpNKbG1VjSktjBa9faNyZiZAEJEjVyla+6R8N4kHV52LbZcLjvJv3IQ2\n" + "iPYRrmMyI5C23qTni0vy7yJbAXBo3CqgSlwie9FARBWT7Puu7F4mF1O1c/SnTysw\n" + "Tm3e5FzgfHipQbnRVn0w4rDprPMKmPxMnvf/Wkw0zVgNadp1Tc1I6Yj525DEQ07i\n" + "2gIn/gECgYEA4jNnY1u2Eu7x3pAQF3dRO0x35boVtuq9iwQk7q+uaZaK4RJRr+0Y\n" + "T68S3bPnfer6SHvcxtST89Bvs/j/Ky4SOaX037UYjFh6T7OIzPl+MzO1yb+VOBT6\n" + "D6FVGEJGp8ZAITU1OfJPeTYViUeEC8tHFGoKUCk50FbB6jOf1oKtv/ECgYEA3EnB\n" + "Y7kSbJJaUuj9ciFUL/pAno86Cim3VjegK1wKgEiyDb610bhoMErovPwfVJbtcttG\n" + "eKJNuwizkRcVbj+vpjDvqqaP5eMxLl6/Nd4haPMJYzGo88Z8NJpwFRNF2KEWjOpQ\n" + "2NEvoCeRtVulCJyka2Tpljzw8cOXkxhPOe2UhHkCgYBo3entj0QO7QXm56T+LAvV\n" + "0PK45xdQEO3EuCwjGAFk5C0IgUSrqeCeeIzniZMltj1IQ1wsNbtNynEu3530t8wt\n" + "O7oVyFBUKGSz9IjUdkpClJOPr6kPMfJoMqRPtdIpz+hFPPSrI6IikKdVWHloOlp+\n" + "pVaYqTQrWT1XRY2xli3VEQKBgGySmZN6Cx+h/oywswIGdUT0VdcQhq2to+QFpJba\n" + "VX6m1cM6hMip2Ag9U3qZ1SNPBBdBBfm9HQybHE3dj713/C2wHuAAGhpXIM1W+20k\n" + "X1knuC/AsSH9aQhQOf/ZMOq1crTfZBuI9q0782/sjGmzMsKPySU4QhUWruVb7OiD\n" + "NVkZAoGAEvihW7G+8/iOE40vGHyBqUeopAAWLciTAUIEwM/Oi3BYfNWNTWF/FWNc\n" + "nMvCZPYigY8C1vO+1iT2Frtd3CIU+f01Q3fJNJoRLlEiKLNZUJRF48OKUqjKSmsi\n" + "w6pucFO40z05YW7utApj4L82rZnOS0pd1tUI1yexqvj0i4ThJfk=\n" + "-----END RSA PRIVATE KEY-----\n"; + +static const char *permissions_ca = + "data:,-----BEGIN CERTIFICATE-----\n" + "MIIDjTCCAnWgAwIBAgIJANsr3sm0NrypMA0GCSqGSIb3DQEBCwUAMFwxCzAJBgNV\n" + "BAYTAk5MMRMwEQYDVQQIDApTb21lLVN0YXRlMR8wHQYDVQQKDBZBRExJTksgVGVj\n" + "aG5vbG9jeSBJbmMuMRcwFQYDVQQDDA5hZGxpbmt0ZWNoLmNvbTAgFw0xODA3MzAx\n" + "MjQ1NTVaGA8yMTE4MDcwNjEyNDU1NVowXDELMAkGA1UEBhMCTkwxEzARBgNVBAgM\n" + "ClNvbWUtU3RhdGUxHzAdBgNVBAoMFkFETElOSyBUZWNobm9sb2N5IEluYy4xFzAV\n" + "BgNVBAMMDmFkbGlua3RlY2guY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" + "CgKCAQEAu7jfnJ0wYVuXgG+PgNawdN38+dRpa8jceqi+blIDehV6XCxrnGXusTCD\n" + "uFmo7HMOBVMVNDXlcBWgoGd+u5EultnOEiIeGTgtHc1O6V9wicp3BGSpZZax/TcO\n" + "NjMVORaqHCADbQ2J8wsz1FHxuKDwX6BJElYOlK77lb/x3yLsDFFC+a0qn2RFh37r\n" + "cWBRAHy8VEASXKZElT9ZmfKd+KUq34KojhNJ4DepKStTq074BRDXVivx+wVD951L\n" + "FNPiQXq+mgHcLj1k37KlZflTFhdP5oEMtATNsXNJPHlEymiySogRWAmKhysLQudu\n" + "kHfNKN+r0FEQMk/hzpYcFeZSOvbfNQIDAQABo1AwTjAdBgNVHQ4EFgQURWMbWvBK\n" + "ZwJvRV1/tyc1R82k0+gwHwYDVR0jBBgwFoAURWMbWvBKZwJvRV1/tyc1R82k0+gw\n" + "DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkPF+ysVtvHnk2hpu9yND\n" + "LCJ96ZzIoKOyY7uRj4ovzlAHFdpNOJQdcJihTmN8i7Trht9XVh0rGoR/6nHzo3TI\n" + "eiogRC80RlDtuA3PF2dDQBMVDStlZMTZPb693hfjdAjhyyw9yghhKHHqNDvSsAL0\n" + "KfBqjG4yGfGpJylYXIT5fWuKlo/ln/yyPa5s54T5XDo+CMbtlLX3QnwVOmaRyzyl\n" + "PiTcPCDIkdLBdXmlfyJcmW6fWa6kPx+35MOxPsXZbujCo+42+OyLqcH1rKT6Xhcs\n" + "hjXBEf+kdgUfSClrM1pNRWsw2ChIYim0F+nry5JFy0Y+8Hbb6SDB340BFmtgDHbF\n" + "HQ==\n" + "-----END CERTIFICATE-----\n"; + +static struct plugins_hdl *plugins = NULL; +static dds_security_authentication *auth = NULL; +static dds_security_access_control *access_control = NULL; +static DDS_Security_IdentityHandle local_identity_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_IdentityHandle remote_identity_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_PermissionsHandle local_permissions_handle = DDS_SECURITY_HANDLE_NIL; +static DDS_Security_GUID_t local_participant_guid; +static char *g_path_to_etc_dir = NULL; + +static void dds_security_property_init(DDS_Security_PropertySeq *seq, DDS_Security_unsigned_long size) +{ + seq->_length = size; + seq->_maximum = size; + seq->_buffer = ddsrt_malloc(size * sizeof(DDS_Security_Property_t)); + memset(seq->_buffer, 0, size * sizeof(DDS_Security_Property_t)); +} + +static void dds_security_property_deinit(DDS_Security_PropertySeq *seq) +{ + uint32_t i; + + for (i = 0; i < seq->_length; i++) + { + ddsrt_free(seq->_buffer[i].name); + ddsrt_free(seq->_buffer[i].value); + } + ddsrt_free(seq->_buffer); +} + +static void reset_exception(DDS_Security_SecurityException *ex) +{ + ex->code = 0; + ex->minor_code = 0; + ddsrt_free(ex->message); + ex->message = NULL; +} + +static void fill_participant_qos(DDS_Security_Qos *qos, const char *permission_filename, const char *governance_filename) +{ + char *permission_uri; + char *governance_uri; + + ddsrt_asprintf(&permission_uri, "file:%s%s", g_path_to_etc_dir, permission_filename); + ddsrt_asprintf(&governance_uri, "file:%s%s", g_path_to_etc_dir, governance_filename); + + memset(qos, 0, sizeof(*qos)); + dds_security_property_init(&qos->property.value, 6); + qos->property.value._buffer[0].name = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + qos->property.value._buffer[0].value = ddsrt_strdup(identity_certificate); + qos->property.value._buffer[1].name = ddsrt_strdup(PROPERTY_IDENTITY_CA); + qos->property.value._buffer[1].value = ddsrt_strdup(identity_ca); + qos->property.value._buffer[2].name = ddsrt_strdup(PROPERTY_PRIVATE_KEY); + qos->property.value._buffer[2].value = ddsrt_strdup(private_key); + qos->property.value._buffer[3].name = ddsrt_strdup(PROPERTY_PERMISSIONS_CA); + qos->property.value._buffer[3].value = ddsrt_strdup(permissions_ca); + qos->property.value._buffer[4].name = ddsrt_strdup(PROPERTY_PERMISSIONS); + qos->property.value._buffer[4].value = ddsrt_strdup(permission_uri); + qos->property.value._buffer[5].name = ddsrt_strdup(PROPERTY_GOVERNANCE); + qos->property.value._buffer[5].value = ddsrt_strdup(governance_uri); + + ddsrt_free(permission_uri); + ddsrt_free(governance_uri); +} + +static void fill_permissions_token(DDS_Security_PermissionsToken *token) +{ + memset(token, 0, sizeof(DDS_Security_PermissionsToken)); + + token->class_id = ddsrt_strdup(ACCESS_PERMISSIONS_TOKEN_ID); + token->properties._length = token->properties._maximum = 2; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(2); + + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_PERMISSIONS_CA_SN); + token->properties._buffer[0].value = ddsrt_strdup(SUBJECT_NAME_PERMISSIONS_CA); + + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_PERMISSIONS_CA_ALGO); + token->properties._buffer[1].value = ddsrt_strdup(RSA_2048_ALGORITHM_NAME); +} + +static int fill_peer_credential_token(DDS_Security_AuthenticatedPeerCredentialToken *token, const char *permission_filename) +{ + int result = 1; + char *permission_uri; + char *permission_data; + + memset(token, 0, sizeof(DDS_Security_AuthenticatedPeerCredentialToken)); + + ddsrt_asprintf(&permission_uri, "%s%s", g_path_to_etc_dir, permission_filename); + + permission_data = load_file_contents(permission_uri); + + if (permission_data) + { + token->class_id = ddsrt_strdup(AUTH_PROTOCOL_CLASS_ID); + token->properties._length = token->properties._maximum = 2; + token->properties._buffer = DDS_Security_PropertySeq_allocbuf(2); + + token->properties._buffer[0].name = ddsrt_strdup(PROPERTY_C_ID); + token->properties._buffer[0].value = ddsrt_strdup(&identity_certificate[6]); + + token->properties._buffer[1].name = ddsrt_strdup(PROPERTY_C_PERM); + token->properties._buffer[1].value = permission_data; + } + else + { + ddsrt_free(permission_data); + result = 0; + } + ddsrt_free(permission_uri); + + return result; +} + +static void corrupt_permission_signature(DDS_Security_AuthenticatedPeerCredentialToken *token) +{ + DDS_Security_string permissions; + size_t len; + + /* It is expected that the permissions are available in a fixed location. */ + CU_ASSERT_FATAL(token != NULL); + CU_ASSERT_FATAL(token->properties._buffer != NULL); + assert(token->properties._buffer != NULL); // for Clang's static analyzer + CU_ASSERT_FATAL(token->properties._length == 2); + CU_ASSERT_FATAL(token->properties._buffer[1].name != NULL); + CU_ASSERT_FATAL(token->properties._buffer[1].value != NULL); + CU_ASSERT_FATAL(strcmp(token->properties._buffer[1].name, PROPERTY_C_PERM) == 0); + + /* Corrupt a byte somewhere in the signature. */ + permissions = token->properties._buffer[1].value; + CU_ASSERT_FATAL(permissions != NULL); + assert(permissions != NULL); // for Clang's static analyzer + len = strlen(permissions); + CU_ASSERT_FATAL(len > 100); + permissions[len - 75]--; +} + +static int validate_local_identity_and_permissions(void) +{ + int res = 0; + DDS_Security_ValidationResult_t result; + DDS_Security_DomainId domain_id = 0; + DDS_Security_Qos participant_qos; + DDS_Security_GUID_t candidate_participant_guid; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_GuidPrefix_t prefix = {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb}; + DDS_Security_EntityId_t entityId = {{0xb0, 0xb1, 0xb2}, 0x1}; + + memset(&local_participant_guid, 0, sizeof(local_participant_guid)); + memcpy(&candidate_participant_guid.prefix, &prefix, sizeof(prefix)); + memcpy(&candidate_participant_guid.entityId, &entityId, sizeof(entityId)); + + fill_participant_qos(&participant_qos, "Test_Permissions_ok.p7s", "Test_Governance_ok.p7s"); + + /* Now call the function. */ + result = auth->validate_local_identity( + auth, + &local_identity_handle, + &local_participant_guid, + domain_id, + &participant_qos, + &candidate_participant_guid, + &exception); + + if (result != DDS_SECURITY_VALIDATION_OK) + { + res = -1; + printf("validate_local_identity_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + reset_exception(&exception); + + if (res == 0) + { + local_permissions_handle = access_control->validate_local_permissions( + access_control, + auth, + local_identity_handle, + 0, + &participant_qos, + &exception); + + if (local_permissions_handle == DDS_SECURITY_HANDLE_NIL) + { + res = -1; + printf("validate_local_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + } + + dds_security_property_deinit(&participant_qos.property.value); + + return res; +} + +static void clear_local_identity_and_permissions(void) +{ + DDS_Security_SecurityException exception = {NULL, 0, 0}; + DDS_Security_boolean success; + + if (local_permissions_handle != DDS_SECURITY_HANDLE_NIL) + { + success = access_control->return_permissions_handle(access_control, local_permissions_handle, &exception); + if (!success) + printf("return_permission_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + reset_exception(&exception); + } + + if (local_identity_handle != DDS_SECURITY_HANDLE_NIL) + { + success = auth->return_identity_handle(auth, local_identity_handle, &exception); + if (!success) + printf("return_identity_handle failed: %s\n", exception.message ? exception.message : "Error message missing"); + reset_exception(&exception); + } +} + +static void set_path_to_etc_dir(void) +{ + ddsrt_asprintf(&g_path_to_etc_dir, "%s%s", CONFIG_ENV_TESTS_DIR, RELATIVE_PATH_TO_ETC_DIR); +} + +static void suite_validate_remote_permissions_init(void) +{ + plugins = load_plugins(&access_control, &auth, NULL /* Cryptograpy */); + CU_ASSERT_FATAL(plugins != NULL); + set_path_to_etc_dir(); + validate_local_identity_and_permissions(); +} + +static void suite_validate_remote_permissions_fini(void) +{ + clear_local_identity_and_permissions(); + unload_plugins(plugins); + ddsrt_free(g_path_to_etc_dir); +} + +CU_Test(ddssec_builtin_validate_remote_permissions, valid_permissions, .init = suite_validate_remote_permissions_init, .fini = suite_validate_remote_permissions_fini) +{ + DDS_Security_PermissionsHandle result; + DDS_Security_PermissionsToken permissions_token; + DDS_Security_AuthenticatedPeerCredentialToken credential_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + int r; + + /* Check if we actually have validate_remote_permissions function. */ + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL(access_control->validate_remote_permissions != NULL); + CU_ASSERT_FATAL(access_control->return_permissions_handle != NULL); + + fill_permissions_token(&permissions_token); + r = fill_peer_credential_token(&credential_token, "Test_Permissions_ok.p7s"); + CU_ASSERT_FATAL(r); + + remote_identity_handle++; + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + if (result == 0) + printf("validate_remote_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + reset_exception(&exception); + CU_ASSERT_FATAL(result != 0); + access_control->return_permissions_handle(access_control, result, &exception); + reset_exception(&exception); + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&permissions_token); + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&credential_token); +} + +CU_Test(ddssec_builtin_validate_remote_permissions, permissions_unknown_ca, .init = suite_validate_remote_permissions_init, .fini = suite_validate_remote_permissions_fini) +{ + DDS_Security_PermissionsHandle result; + DDS_Security_PermissionsToken permissions_token; + DDS_Security_AuthenticatedPeerCredentialToken credential_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + int r; + + /* Check if we actually have validate_remote_permissions function. */ + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL(access_control->validate_remote_permissions != NULL); + CU_ASSERT_FATAL(access_control->return_permissions_handle != NULL); + + fill_permissions_token(&permissions_token); + r = fill_peer_credential_token(&credential_token, "Test_Permissions_unknown_ca.p7s"); + CU_ASSERT_FATAL(r); + + remote_identity_handle++; + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + if (result == 0) + { + printf("validate_remote_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(result == 0); + if (result == 0) + { + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + } + else + { + reset_exception(&exception); + access_control->return_permissions_handle(access_control, result, &exception); + } + + reset_exception(&exception); + + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&permissions_token); + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&credential_token); +} + +CU_Test(ddssec_builtin_validate_remote_permissions, permissions_not_signed, .init = suite_validate_remote_permissions_init, .fini = suite_validate_remote_permissions_fini) +{ + DDS_Security_PermissionsHandle result; + DDS_Security_PermissionsToken permissions_token; + DDS_Security_AuthenticatedPeerCredentialToken credential_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + int r; + + /* Check if we actually have validate_remote_permissions function. */ + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL(access_control->validate_remote_permissions != NULL); + CU_ASSERT_FATAL(access_control->return_permissions_handle != NULL); + + fill_permissions_token(&permissions_token); + r = fill_peer_credential_token(&credential_token, "Test_Permissions_not_signed.p7s"); + CU_ASSERT_FATAL(r); + + remote_identity_handle++; + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + if (result == 0) + { + printf("validate_remote_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(result == 0); + if (result == 0) + { + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + } + else + { + reset_exception(&exception); + access_control->return_permissions_handle(access_control, result, &exception); + } + + reset_exception(&exception); + + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&permissions_token); + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&credential_token); +} + +CU_Test(ddssec_builtin_validate_remote_permissions, invalid_credential_token, .init = suite_validate_remote_permissions_init, .fini = suite_validate_remote_permissions_fini) +{ + DDS_Security_PermissionsHandle result; + DDS_Security_PermissionsToken permissions_token; + DDS_Security_AuthenticatedPeerCredentialToken credential_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + + /* Check if we actually have validate_remote_permissions function. */ + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL(access_control->validate_remote_permissions != NULL); + CU_ASSERT_FATAL(access_control->return_permissions_handle != NULL); + + remote_identity_handle++; + + fill_permissions_token(&permissions_token); + + /* empty peer credential token */ + memset(&credential_token, 0, sizeof(credential_token)); + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + if (result == 0) + { + printf("validate_remote_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(result == 0); + if (result == 0) + { + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + } + else + { + reset_exception(&exception); + access_control->return_permissions_handle(access_control, result, &exception); + } + + reset_exception(&exception); + + /* peer credential token with invalid class id */ + credential_token.class_id = "UNKNOWN"; + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + if (result == 0) + { + printf("validate_remote_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(result == 0); + if (result == 0) + { + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + } + else + { + reset_exception(&exception); + access_control->return_permissions_handle(access_control, result, &exception); + } + + reset_exception(&exception); + + /* peer credential token with no properties */ + credential_token.class_id = ddsrt_strdup(AUTH_PROTOCOL_CLASS_ID); + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + if (result == 0) + { + printf("validate_remote_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(result == 0); + if (result == 0) + { + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + } + else + { + reset_exception(&exception); + access_control->return_permissions_handle(access_control, result, &exception); + } + + reset_exception(&exception); + + /* peer credential token with empty properties */ + credential_token.properties._length = credential_token.properties._maximum = 2; + credential_token.properties._buffer = DDS_Security_PropertySeq_allocbuf(2); + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + if (result == 0) + { + printf("validate_remote_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(result == 0); + if (result == 0) + { + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + } + else + { + reset_exception(&exception); + access_control->return_permissions_handle(access_control, result, &exception); + } + + reset_exception(&exception); + + /* peer credential token with no c.id value */ + credential_token.properties._buffer[0].name = ddsrt_strdup(PROPERTY_C_ID); + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + if (result == 0) + { + printf("validate_remote_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(result == 0); + if (result == 0) + { + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + } + else + { + reset_exception(&exception); + access_control->return_permissions_handle(access_control, result, &exception); + } + + reset_exception(&exception); + + /* peer credential token with no c.perm */ + credential_token.properties._buffer[0].value = ddsrt_strdup(PROPERTY_IDENTITY_CERT); + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + if (result == 0) + { + printf("validate_remote_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(result == 0); + if (result == 0) + { + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + } + else + { + reset_exception(&exception); + access_control->return_permissions_handle(access_control, result, &exception); + } + + reset_exception(&exception); + + /* peer credential token with no c.perm value*/ + credential_token.properties._buffer[1].name = ddsrt_strdup(PROPERTY_C_PERM); + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + if (result == 0) + { + printf("validate_remote_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(result == 0); + if (result == 0) + { + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + } + else + { + reset_exception(&exception); + access_control->return_permissions_handle(access_control, result, &exception); + } + + reset_exception(&exception); + + /* peer credential token with invalid c.perm value */ + credential_token.properties._buffer[1].value = ddsrt_strdup("Invalid value"); + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + if (result == 0) + { + printf("validate_remote_permissions_failed: %s\n", exception.message ? exception.message : "Error message missing"); + } + + CU_ASSERT(result == 0); + if (result == 0) + { + CU_ASSERT(exception.code != 0); + CU_ASSERT(exception.message != NULL); + } + else + { + reset_exception(&exception); + access_control->return_permissions_handle(access_control, result, &exception); + } + + reset_exception(&exception); + + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&permissions_token); + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&credential_token); +} + +CU_Test(ddssec_builtin_validate_remote_permissions, invalid_xml, .init = suite_validate_remote_permissions_init, .fini = suite_validate_remote_permissions_fini) +{ + DDS_Security_PermissionsHandle result; + DDS_Security_PermissionsToken permissions_token; + DDS_Security_AuthenticatedPeerCredentialToken credential_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + int r; + + /* Check if we actually have validate_remote_permissions function. */ + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL(access_control->validate_remote_permissions != NULL); + CU_ASSERT_FATAL(access_control->return_permissions_handle != NULL); + + fill_permissions_token(&permissions_token); + //permissions_token. + r = fill_peer_credential_token(&credential_token, "Test_Permissions_invalid_data.p7s"); + CU_ASSERT_FATAL(r); + + remote_identity_handle++; + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + CU_ASSERT(result == 0); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_CAN_NOT_PARSE_PERMISSIONS_CODE); + CU_ASSERT(exception.message != NULL); + if (exception.message) + { + printf("(%d) %s\n", (int)exception.code, exception.message); + } + reset_exception(&exception); + + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&permissions_token); + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&credential_token); +} + +CU_Test(ddssec_builtin_validate_remote_permissions, permissions_expired, .init = suite_validate_remote_permissions_init, .fini = suite_validate_remote_permissions_fini) +{ + DDS_Security_PermissionsHandle result; + DDS_Security_PermissionsToken permissions_token; + DDS_Security_AuthenticatedPeerCredentialToken credential_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + int r; + + /* Check if we actually have validate_remote_permissions function. */ + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL(access_control->validate_remote_permissions != NULL); + CU_ASSERT_FATAL(access_control->return_permissions_handle != NULL); + + fill_permissions_token(&permissions_token); + r = fill_peer_credential_token(&credential_token, "Test_Permissions_expired.p7s"); + CU_ASSERT_FATAL(r); + + remote_identity_handle++; + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + CU_ASSERT_FATAL(result == 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_CODE); + CU_ASSERT_NSTRING_EQUAL_FATAL(DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_MESSAGE, exception.message, strlen(DDS_SECURITY_ERR_VALIDITY_PERIOD_EXPIRED_MESSAGE) - 16); + reset_exception(&exception); + + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&permissions_token); + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&credential_token); +} + +CU_Test(ddssec_builtin_validate_remote_permissions, permissions_not_yet, .init = suite_validate_remote_permissions_init, .fini = suite_validate_remote_permissions_fini) +{ + DDS_Security_PermissionsHandle result; + DDS_Security_PermissionsToken permissions_token; + DDS_Security_AuthenticatedPeerCredentialToken credential_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + int r; + + /* Check if we actually have validate_remote_permissions function. */ + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL(access_control->validate_remote_permissions != NULL); + CU_ASSERT_FATAL(access_control->return_permissions_handle != NULL); + + fill_permissions_token(&permissions_token); + r = fill_peer_credential_token(&credential_token, "Test_Permissions_notyet.p7s"); + CU_ASSERT_FATAL(r); + + remote_identity_handle++; + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + CU_ASSERT_FATAL(result == 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_VALIDITY_PERIOD_NOT_STARTED_CODE); + CU_ASSERT_NSTRING_EQUAL_FATAL(DDS_SECURITY_ERR_VALIDITY_PERIOD_NOT_STARTED_MESSAGE, exception.message, strlen(DDS_SECURITY_ERR_VALIDITY_PERIOD_NOT_STARTED_MESSAGE) - 14); + reset_exception(&exception); + + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&permissions_token); + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&credential_token); +} + +CU_Test(ddssec_builtin_validate_remote_permissions, permissions_unknown_subject_name, .init = suite_validate_remote_permissions_init, .fini = suite_validate_remote_permissions_fini) +{ + DDS_Security_PermissionsHandle result; + DDS_Security_PermissionsToken permissions_token; + DDS_Security_AuthenticatedPeerCredentialToken credential_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + int r; + + /* Check if we actually have validate_remote_permissions function. */ + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL(access_control->validate_remote_permissions != NULL); + CU_ASSERT_FATAL(access_control->return_permissions_handle != NULL); + + fill_permissions_token(&permissions_token); + r = fill_peer_credential_token(&credential_token, "Test_Permissions_unknown_subject.p7s"); + CU_ASSERT_FATAL(r); + + remote_identity_handle++; + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + CU_ASSERT_FATAL(result == 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_SUBJECT_NAME_CODE); + CU_ASSERT_STRING_EQUAL_FATAL(DDS_SECURITY_ERR_INVALID_SUBJECT_NAME_MESSAGE, exception.message); + reset_exception(&exception); + + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&permissions_token); + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&credential_token); + + /* missing subject name component */ + + fill_permissions_token(&permissions_token); + r = fill_peer_credential_token(&credential_token, "Test_Permissions_missing_subject_component.p7s"); + CU_ASSERT_FATAL(r); + + remote_identity_handle++; + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + CU_ASSERT_FATAL(result == 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_INVALID_SUBJECT_NAME_CODE); + CU_ASSERT_STRING_EQUAL_FATAL(DDS_SECURITY_ERR_INVALID_SUBJECT_NAME_MESSAGE, exception.message); + reset_exception(&exception); + + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&permissions_token); + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&credential_token); +} + +CU_Test(ddssec_builtin_validate_remote_permissions, permissions_different_subject, .init = suite_validate_remote_permissions_init, .fini = suite_validate_remote_permissions_fini) +{ + DDS_Security_PermissionsHandle result; + DDS_Security_PermissionsToken permissions_token; + DDS_Security_AuthenticatedPeerCredentialToken credential_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + int r; + + /* Check if we actually have validate_remote_permissions function. */ + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL(access_control->validate_remote_permissions != NULL); + CU_ASSERT_FATAL(access_control->return_permissions_handle != NULL); + + fill_permissions_token(&permissions_token); + r = fill_peer_credential_token(&credential_token, "Test_Permissions_different_subject_representation.p7s"); + CU_ASSERT_FATAL(r); + + remote_identity_handle++; + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + CU_ASSERT_FATAL(result != 0); + CU_ASSERT_FATAL(exception.code == DDS_SECURITY_ERR_OK_CODE); + + reset_exception(&exception); + + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&permissions_token); + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&credential_token); +} + +CU_Test(ddssec_builtin_validate_remote_permissions, corrupted_signature, .init = suite_validate_remote_permissions_init, .fini = suite_validate_remote_permissions_fini) +{ + DDS_Security_PermissionsHandle result; + DDS_Security_PermissionsToken permissions_token; + DDS_Security_AuthenticatedPeerCredentialToken credential_token; + DDS_Security_SecurityException exception = {NULL, 0, 0}; + int r; + + /* Check if we actually have validate_remote_permissions function. */ + CU_ASSERT_FATAL(access_control != NULL); + CU_ASSERT_FATAL(local_identity_handle != DDS_SECURITY_HANDLE_NIL); + CU_ASSERT_FATAL(access_control->validate_remote_permissions != NULL); + CU_ASSERT_FATAL(access_control->return_permissions_handle != NULL); + + fill_permissions_token(&permissions_token); + //permissions_token. + r = fill_peer_credential_token(&credential_token, "Test_Permissions_ok.p7s"); + CU_ASSERT_FATAL(r); + + corrupt_permission_signature(&credential_token); + + remote_identity_handle++; + + result = access_control->validate_remote_permissions( + access_control, + auth, + local_identity_handle, + remote_identity_handle, + &permissions_token, + &credential_token, + &exception); + + CU_ASSERT(result == 0); + CU_ASSERT(exception.code == DDS_SECURITY_ERR_INVALID_SMIME_DOCUMENT_CODE); + CU_ASSERT(exception.message != NULL); + if (exception.message) + { + printf("(%d) %s\n", (int)exception.code, exception.message); + } + reset_exception(&exception); + + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&permissions_token); + DDS_Security_DataHolder_deinit((DDS_Security_DataHolder *)&credential_token); +} diff --git a/src/security/core/CMakeLists.txt b/src/security/core/CMakeLists.txt new file mode 100644 index 0000000..7765227 --- /dev/null +++ b/src/security/core/CMakeLists.txt @@ -0,0 +1,55 @@ +# +# 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 +# +PREPEND(srcs_security_core "${CMAKE_CURRENT_LIST_DIR}/src" + dds_security_serialize.c + dds_security_utils.c + dds_security_plugins.c + shared_secret.c + dds_security_fsm.c + dds_security_timed_cb.c +) + +PREPEND(hdrs_public_security_core "${CMAKE_CURRENT_LIST_DIR}/include/security/core" + dds_security_serialize.h + dds_security_types.h + dds_security_utils.h + dds_security_plugins.h + dds_security_fsm.h + shared_secret.h + dds_security_timed_cb.h +) + +if(NOT WIN32) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC" ) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC" ) +endif() + +add_library(security_core INTERFACE) + +target_sources(security_core INTERFACE ${srcs_security_core}) + +target_include_directories(security_core + INTERFACE + "$" + "$" + "$>" + "$>" +) + +if(BUILD_TESTING AND BUILD_IDLC) + add_subdirectory(tests) +endif() + +install( + DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/include/dds/security/core/" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/dds/security/core/" + COMPONENT dev) diff --git a/src/security/core/include/dds/security/core/dds_security_fsm.h b/src/security/core/include/dds/security/core/dds_security_fsm.h new file mode 100644 index 0000000..96f24d9 --- /dev/null +++ b/src/security/core/include/dds/security/core/dds_security_fsm.h @@ -0,0 +1,230 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef DDS_SECURITY_FSM_H +#define DDS_SECURITY_FSM_H + +#include "dds/ddsrt/time.h" +#include "dds/ddsi/ddsi_domaingv.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +#define DDS_SECURITY_FSM_EVENT_AUTO (-1) +#define DDS_SECURITY_FSM_EVENT_TIMEOUT (-2) +#define DDS_SECURITY_FSM_EVENT_DELETE (-3) + +struct dds_security_fsm; +struct dds_security_fsm_control; + +typedef enum { + DDS_SECURITY_FSM_DEBUG_ACT_DISPATCH, + DDS_SECURITY_FSM_DEBUG_ACT_DISPATCH_DIRECT, + DDS_SECURITY_FSM_DEBUG_ACT_HANDLING +} DDS_SECURITY_FSM_DEBUG_ACT; + +/** + * Template for user-defined state methods. + * It is allowed to call dds_security_fsm_dispatch() from within a dispatch function. + */ +typedef void (*dds_security_fsm_action)(struct dds_security_fsm *fsm, void *arg); + +/** + * State struct + * + * - func : optional user defined function, invoked by when reaching this state + * - timeout : optional timeout which is controlled by the fsm + */ +typedef struct dds_security_fsm_state { + const dds_security_fsm_action func; + dds_duration_t timeout; +} dds_security_fsm_state; + +/** + * Template for user-defined debug methods. + * It'll be called for every dispatched event, regardless of which state it + * is in (which is also provided). + * This can be used to get extra information about the behaviour of the + * state machine. + * It is not allowed to call any fsm API functions from within this + * debug callback. + */ +typedef void (*dds_security_fsm_debug)(struct dds_security_fsm *fsm, DDS_SECURITY_FSM_DEBUG_ACT act, const dds_security_fsm_state *current, int event_id, void *arg); + +/** + * Transition definitions + * + * begin : start state (to transition from) + * event_id : indicate the event responsible for the transition + * func : user defined function, invoked during transition + * end : end state (to transition to) + */ +typedef struct dds_security_fsm_transition { + const dds_security_fsm_state *begin; + const int event_id; + const dds_security_fsm_action func; + const dds_security_fsm_state *end; +} dds_security_fsm_transition; + + +/** + * Create a new fsm + * Initializes a new fsm. Fsm does not start. + * + * @param transitions array of transitions which the defines the functioning of the state machine + * @param size number of transitions + * @param arg Extra data to pass to the fsm. Will be passed to all user defined callback + * methods. + * + * @return Returns the new created state machine on success. Null on failure. + */ +DDS_EXPORT struct dds_security_fsm * +dds_security_fsm_create(struct dds_security_fsm_control *control, const dds_security_fsm_transition *transitions, uint32_t size, void *arg); + + +/** + * Start a fsm + * Starts the fsm, start with the firs transition + * + * @param fsm fsm to start. + */ +DDS_EXPORT void +dds_security_fsm_start(struct dds_security_fsm *fsm); + +/** + * Set an overall timeout for the given state machine + * Will be monitoring the overall timeout of the given state machine, + * invoking a user defined callback when the given timeout expires. + * Timeout will be aborted upon a cleanup of the state machine. + * + * @param fsm fsm to set the overall timeout for + * @param func user defined function which is called when the + * overall timeout expires. + * @param timeout indicates the overall timeout + */ +DDS_EXPORT void +dds_security_fsm_set_timeout(struct dds_security_fsm *fsm, dds_security_fsm_action func, dds_time_t timeout); + +/** + * Set an debug callback for the given state machine. + * + * @param fsm fsm to set the overall timeout for + * @param func user defined function which is called for every + * event, whether being dispatched or actually + * handled. + */ +DDS_EXPORT void +dds_security_fsm_set_debug(struct dds_security_fsm *fsm, dds_security_fsm_debug func); + +/** + * Dispatches the next event + * Assignment for the state machine to transisiton to the next state. + * + * @param fsm The state machine + * @param event_id Indicate where to transisition to (outcome of current state) + * @param prio Indicates if the event has to be scheduled with priority. + */ +DDS_EXPORT void +dds_security_fsm_dispatch(struct dds_security_fsm *fsm, int32_t event_id, bool prio); + +/** + * Retrieve the current state of a given state machine + * + * @param fsm The state machine + * + * @return The current state of the given state machine + */ +DDS_EXPORT const dds_security_fsm_state* +dds_security_fsm_current_state(struct dds_security_fsm *fsm); + +/** + * Stops the state machine. + * Stops all running timeouts and events and cleaning all memory + * related to this machine. + * + * When calling this from another thread, then it may block until + * a possible concurrent event has finished. After this call, the + * fsm may not be used anymore. + * + * When in the fsm action callback function context, this will + * not block. It will garbage collect when the event has been + * handled. + * + * @param fsm The state machine to b stopped + */ +DDS_EXPORT void +dds_security_fsm_stop(struct dds_security_fsm *fsm); + +/** + * Free the state machine. + * Stops all running timeouts and events and cleaning all memory + * related to this machine. + * + * When calling this from another thread, then it may block until + * a possible concurrent event has finished. After this call, the + * fsm may not be used anymore. + * + * When in the fsm action callback function context, this will + * not block. It will garbage collect when the event has been + * handled. + * + * @param fsm The state machine to be removed + */ +DDS_EXPORT void +dds_security_fsm_free(struct dds_security_fsm *fsm); + +/** + * Create a new fsm control context, + * The fsm control context manages the global state of the fsm's created within + * this context. The fsm control a thread to control the state machined allocated + * to this control. + * + * @param gv The global settings. + * + * @return Returns the new fsm control on success. Null on failure. + */ +DDS_EXPORT struct dds_security_fsm_control * +dds_security_fsm_control_create (struct ddsi_domaingv *gv); + +/** + * Frees the fsm control and the allocated fsm's. + * A precondition is that the fsm control is stopped. + * + * @param control The fsm control to be freed. + */ +DDS_EXPORT void +dds_security_fsm_control_free(struct dds_security_fsm_control *control); + +/** + * Starts the thread that handles the events and timeouts associated + * with the fsm that are managed by this fsm control. + * + * @param control The fsm control to be started. + */ +DDS_EXPORT dds_return_t +dds_security_fsm_control_start (struct dds_security_fsm_control *control, const char *name); + +/** + * Stops the thread that handles the events and timeouts. + * + * @param control The fsm control to be started. + */ +DDS_EXPORT void +dds_security_fsm_control_stop(struct dds_security_fsm_control *control); + + +#if defined (__cplusplus) +} +#endif + +#endif /* DDS_SECURITY_FSM_H */ diff --git a/src/security/core/include/dds/security/core/dds_security_plugins.h b/src/security/core/include/dds/security/core/dds_security_plugins.h new file mode 100644 index 0000000..ffc48f5 --- /dev/null +++ b/src/security/core/include/dds/security/core/dds_security_plugins.h @@ -0,0 +1,61 @@ +/* + * 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 SECURITY_CORE_PLUGINS_H_ +#define SECURITY_CORE_PLUGINS_H_ + +#include +#include "dds/export.h" +#include "dds/ddsrt/retcode.h" +#include "dds/ddsrt/dynlib.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/security/dds_security_api.h" + +struct ddsrt_log_cfg; + +typedef struct dds_security_plugin { + ddsrt_dynlib_t lib_handle; + plugin_init func_init; + plugin_finalize func_finalize; + char *name; +} dds_security_plugin; + +/* we are using our own security plugin configuration (not certificates etc) + * because we do not want to depend on DDSI configuration data types. + * + * A configuration data type is needed because there are traverses to properties several times + */ + +typedef struct dds_security_plugin_config { + char *library_path; + char *library_init; + char *library_finalize; +} dds_security_plugin_config; + +typedef struct dds_security_plugin_suite_config{ + dds_security_plugin_config authentication; + dds_security_plugin_config cryptography; + dds_security_plugin_config access_control; +} dds_security_plugin_suite_config; + +DDS_EXPORT dds_return_t dds_security_plugin_release(const dds_security_plugin *security_plugin, void *context); +DDS_EXPORT dds_return_t dds_security_check_plugin_configuration(const dds_security_plugin_suite_config *security_suite_config, struct ddsi_domaingv *gv); +DDS_EXPORT dds_return_t dds_security_load_security_library(const dds_security_plugin_config *plugin_config, dds_security_plugin *security_plugin, + void **security_plugin_context, struct ddsi_domaingv *gv); +DDS_EXPORT dds_return_t dds_security_verify_plugin_functions( + dds_security_authentication *authentication_context, dds_security_plugin *auth_plugin, + dds_security_cryptography *crypto_context, dds_security_plugin *crypto_plugin, + dds_security_access_control *access_control_context, dds_security_plugin *ac_plugin, + struct ddsi_domaingv *gv); + +#endif /* SECURITY_CORE_PLUGINS_H_ */ diff --git a/src/security/core/include/dds/security/core/dds_security_serialize.h b/src/security/core/include/dds/security/core/dds_security_serialize.h new file mode 100644 index 0000000..f6a0251 --- /dev/null +++ b/src/security/core/include/dds/security/core/dds_security_serialize.h @@ -0,0 +1,106 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef DDS_SECURITY_CDR_SER_H +#define DDS_SECURITY_CDR_SER_H + +#include "dds/export.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_types.h" +#include "stddef.h" + +#if defined (__cplusplus) +extern "C" { +#endif + + + +typedef struct DDS_Security_Serializer *DDS_Security_Serializer; +typedef struct DDS_Security_Deserializer *DDS_Security_Deserializer; + + +DDS_EXPORT DDS_Security_Serializer +DDS_Security_Serializer_new( + size_t size, + size_t increment); + +DDS_EXPORT void +DDS_Security_Serializer_free( + DDS_Security_Serializer serializer); + +DDS_EXPORT void +DDS_Security_Serializer_buffer( + DDS_Security_Serializer ser, + unsigned char **buffer, + size_t *size); + +DDS_EXPORT void +DDS_Security_Serialize_PropertySeq( + DDS_Security_Serializer serializer, + const DDS_Security_PropertySeq *seq); + +DDS_EXPORT void +DDS_Security_Serialize_BinaryPropertyArray( + DDS_Security_Serializer serializer, + const DDS_Security_BinaryProperty_t **properties, + const uint32_t length); + +DDS_EXPORT void +DDS_Security_Serialize_BinaryPropertySeq( + DDS_Security_Serializer serializer, + const DDS_Security_BinaryPropertySeq *seq); + +DDS_EXPORT void +DDS_Security_Serialize_DataHolderSeq( + DDS_Security_Serializer serializer, + const DDS_Security_DataHolderSeq *seq); + +DDS_EXPORT void +DDS_Security_Serialize_ParticipantBuiltinTopicData( + DDS_Security_Serializer ser, + DDS_Security_ParticipantBuiltinTopicData *pdata); + +DDS_EXPORT void +DDS_Security_Serialize_KeyMaterial_AES_GCM_GMAC( + DDS_Security_Serializer ser, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *data); + +DDS_EXPORT DDS_Security_Deserializer +DDS_Security_Deserializer_new( + const unsigned char *data, + size_t size); + +DDS_EXPORT void +DDS_Security_Deserializer_free( + DDS_Security_Deserializer deserializer); + +DDS_EXPORT int +DDS_Security_Deserialize_ParticipantBuiltinTopicData( + DDS_Security_Deserializer deserializer, + DDS_Security_ParticipantBuiltinTopicData *pdata, + DDS_Security_SecurityException *ex); + +DDS_EXPORT void +DDS_Security_BuiltinTopicKeyBE( + DDS_Security_BuiltinTopicKey_t dst, + const DDS_Security_BuiltinTopicKey_t src); + +DDS_EXPORT int +DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC( + DDS_Security_Deserializer dser, + DDS_Security_KeyMaterial_AES_GCM_GMAC *data); + +#if defined (__cplusplus) +} +#endif + +#endif /* DDS_SECURITY_CDR_SER_H */ diff --git a/src/security/core/include/dds/security/core/dds_security_timed_cb.h b/src/security/core/include/dds/security/core/dds_security_timed_cb.h new file mode 100644 index 0000000..93b2eb4 --- /dev/null +++ b/src/security/core/include/dds/security/core/dds_security_timed_cb.h @@ -0,0 +1,187 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef DDS_SECURITY_TIMED_CALLBACK_H +#define DDS_SECURITY_TIMED_CALLBACK_H + +#include "dds/export.h" +#include "dds/ddsrt/time.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +/** + * The dispatcher that will trigger the timed callbacks. + */ +struct dds_security_timed_dispatcher_t; + +/** + * The timed callback structure holds a list of dispatchers and manages + * the thread that calls the dispatchers callbacks. + */ +struct dds_security_timed_cb_data; + +/** + * The callback is triggered by two causes: + * 1. The trigger timeout has been reached. + * 2. The related dispatcher is being deleted. + */ +typedef enum { + DDS_SECURITY_TIMED_CB_KIND_TIMEOUT, + DDS_SECURITY_TIMED_CB_KIND_DELETE +} dds_security_timed_cb_kind; + + + +/** + * Template for the timed callback functions. + * It is NOT allowed to call any t_timed_cb API functions from within this + * callback context. + * + * This will be called when the trigger time of the added callback is reached, + * or if the related dispatcher is deleted. The latter can be used to clean up + * possible callback resources. + * + * @param d Related dispatcher. + * @param kind Triggered by cb timeout or dispatcher deletion. + * @param listener Listener that was provided when enabling the related + * dispatcher (NULL with a deletion trigger). + * @param arg User data, provided when adding a callback to the + * related dispatcher. + */ +typedef void +(*dds_security_timed_cb_t) ( + struct dds_security_timed_dispatcher_t *d, + dds_security_timed_cb_kind kind, + void *listener, + void *arg); + +DDS_EXPORT struct dds_security_timed_cb_data* +dds_security_timed_cb_new(void); + +DDS_EXPORT void +dds_security_timed_cb_free( + struct dds_security_timed_cb_data *dl); + +/** + * Create a new dispatcher for timed callbacks. + * The dispatcher is not enabled (see dds_security_timed_dispatcher_enable). + * + * @return New (disabled) timed callbacks dispatcher. + */ +DDS_EXPORT struct dds_security_timed_dispatcher_t* +dds_security_timed_dispatcher_new( + struct dds_security_timed_cb_data *tcb); + +/** + * Frees the given dispatcher. + * If the dispatcher contains timed callbacks, then these will be + * triggered with DDS_SECURITY_TIMED_CB_KIND_DELETE and then removed. This + * is done whether the dispatcher is enabled or not. + * + * @param d The dispatcher to free. + * + */ +DDS_EXPORT void +dds_security_timed_dispatcher_free( + struct dds_security_timed_cb_data *tcb, + struct dds_security_timed_dispatcher_t *d); + + + +/** + * Enables a dispatcher for timed callbacks. + * + * Until a dispatcher is enabled, no DDS_SECURITY_TIMED_CB_KIND_TIMEOUT callbacks will + * be triggered. + * As soon as it is enabled, possible stored timed callbacks that are in the + * past will be triggered at that moment. + * Also, from this point on, possible future callbacks will also be triggered + * when the appropriate time has been reached. + * + * A listener argument can be supplied that is returned when the callback + * is triggered. The dispatcher doesn't do anything more with it, so it may + * be NULL. + * + * DDS_SECURITY_TIMED_CB_KIND_DELETE callbacks will always be triggered despite the + * dispatcher being possibly disabled. + * + * @param d The dispatcher to enable. + * @param listener An object that is returned with the callback. + * + */ +DDS_EXPORT void +dds_security_timed_dispatcher_enable( + struct dds_security_timed_cb_data *tcb, + struct dds_security_timed_dispatcher_t *d, + void *listener); + + + +/** + * Disables a dispatcher for timed callbacks. + * + * When a dispatcher is disabled (default after creation), it will not + * trigger any related callbacks. It will still store them, however, so + * that they can be triggered after a (re)enabling. + * + * This is when the callback is actually triggered by a timeout and thus + * its kind is DDS_SECURITY_TIMED_CB_KIND_TIMEOUT. DDS_SECURITY_TIMED_CB_KIND_DELETE callbacks + * will always be triggered despite the dispatcher being possibly disabled. + * + * @param d The dispatcher to disable. + * + */ +DDS_EXPORT void +dds_security_timed_dispatcher_disable( + struct dds_security_timed_cb_data *tcb, + struct dds_security_timed_dispatcher_t *d); + + + +/** + * Adds a timed callback to a dispatcher. + * + * The given callback will be triggered with DDS_SECURITY_TIMED_CB_KIND_TIMEOUT when: + * 1. The dispatcher is enabled and + * 2. The trigger_time has been reached. + * + * If the trigger_time lays in the past, then the callback is still added. + * When the dispatcher is already enabled, it will trigger this 'past' + * callback immediately. Otherwise, the 'past' callback will be triggered + * at the moment that the dispatcher is enabled. + * + * The given callback will be triggered with DDS_SECURITY_TIMED_CB_KIND_DELETE when: + * 1. The related dispatcher is deleted (ignoring enable/disable). + * + * This is done so that possible related callback resources can be freed. + * + * @param d The dispatcher to add the callback to. + * @param cb The actual callback function. + * @param trigger_time A wall-clock time of when to trigger the callback. + * @param arg User data that is provided with the callback. + * + */ +DDS_EXPORT void +dds_security_timed_dispatcher_add( + struct dds_security_timed_cb_data *tcb, + struct dds_security_timed_dispatcher_t *d, + dds_security_timed_cb_t cb, + dds_time_t trigger_time, + void *arg); + +#if defined (__cplusplus) +} +#endif + +#endif /* DDS_SECURITY_TIMED_CALLBACK_H */ diff --git a/src/security/core/include/dds/security/core/dds_security_types.h b/src/security/core/include/dds/security/core/dds_security_types.h new file mode 100644 index 0000000..953220f --- /dev/null +++ b/src/security/core/include/dds/security/core/dds_security_types.h @@ -0,0 +1,69 @@ +/* + * 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 DSS_SECURITY_PLUGIN_TYPES_H_ +#define DSS_SECURITY_PLUGIN_TYPES_H_ + +#include "dds/security/dds_security_api_types.h" + +typedef DDS_Security_octet DDS_Security_CryptoTransformKind[4]; +typedef DDS_Security_octet DDS_Security_CryptoTransformKeyId[4]; + +/* enumeration for CryptoTransformKind. + * ds_security_assign_CryptoTransformKind function should be used for assigning to CryptoTransformKind + */ +typedef enum +{ +/* No encryption, no authentication tag */ + CRYPTO_TRANSFORMATION_KIND_NONE = 0, + /* No encryption. + One AES128-GMAC authentication tag using the sender_key + Zero or more AES128-GMAC auth. tags with receiver specfic keys */ + CRYPTO_TRANSFORMATION_KIND_AES128_GMAC = 1, + /* Authenticated Encryption using AES-128 in Galois Counter Mode + (GCM) using the sender key. + The authentication tag using the sender_key obtained from GCM + Zero or more AES128-GMAC auth. tags with receiver specfic keys */ + CRYPTO_TRANSFORMATION_KIND_AES128_GCM = 2, + /* No encryption. + One AES256-GMAC authentication tag using the sender_key + Zero or more AES256-GMAC auth. tags with receiver specfic keys */ + CRYPTO_TRANSFORMATION_KIND_AES256_GMAC = 3, + /* Authenticated Encryption using AES-256 in Galois Counter Mode + (GCM) using the sender key. + The authentication tag using the sender_key obtained from GCM + Zero or more AES256-GMAC auth. tags with receiver specfic keys */ + CRYPTO_TRANSFORMATION_KIND_AES256_GCM = 4, + + /* INVALID ENUM*/ + CRYPTO_TRANSFORMATION_KIND_INVALID = 127, +} DDS_Security_CryptoTransformKind_Enum; + +typedef struct DDS_Security_KeyMaterial_AES_GCM_GMAC { + DDS_Security_CryptoTransformKind transformation_kind; + DDS_Security_OctetSeq master_salt; /*size shall be 16 or 32*/ + DDS_Security_CryptoTransformKeyId sender_key_id; + DDS_Security_OctetSeq master_sender_key; /*size shall be 16 or 32*/ + DDS_Security_CryptoTransformKeyId receiver_specific_key_id; + DDS_Security_OctetSeq master_receiver_specific_key; /*size shall be 0, 16 or 32*/ +} DDS_Security_KeyMaterial_AES_GCM_GMAC; + +struct CryptoTransformIdentifier { + DDS_Security_CryptoTransformKind transformation_kind; + DDS_Security_CryptoTransformKeyId transformation_key_id; +}; + +/** temporary address decleration until it is ready in ddsrt */ +typedef uintptr_t ddsrt_address; /* word length of the platform */ + + +#endif /* DSS_SECURITY_PLUGIN_TYPES_H_ */ 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 new file mode 100644 index 0000000..e56a5f9 --- /dev/null +++ b/src/security/core/include/dds/security/core/dds_security_utils.h @@ -0,0 +1,396 @@ +/* + * 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 DSCMN_SECURITY_UTILS_H_ +#define DSCMN_SECURITY_UTILS_H_ + +#include +#include +#include +#include + +#include "dds/export.h" +#include "dds/ddsrt/strtol.h" +#include "dds/ddsrt/time.h" +#include "dds/security/core/dds_security_types.h" +#include "dds/security/dds_security_api.h" + +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_EXCEPTION_INIT {NULL, 0, 0} + +typedef enum { + DDS_SECURITY_CONFIG_ITEM_PREFIX_UNKNOWN, + DDS_SECURITY_CONFIG_ITEM_PREFIX_FILE, + DDS_SECURITY_CONFIG_ITEM_PREFIX_DATA, + DDS_SECURITY_CONFIG_ITEM_PREFIX_PKCS11 +} DDS_Security_config_item_prefix_t; + + +DDS_EXPORT DDS_Security_BinaryProperty_t * +DDS_Security_BinaryProperty_alloc( + void); + +DDS_EXPORT void +DDS_Security_BinaryProperty_deinit( + DDS_Security_BinaryProperty_t *p); + +DDS_EXPORT void +DDS_Security_BinaryProperty_free( + DDS_Security_BinaryProperty_t *p); + +DDS_EXPORT void +DDS_Security_BinaryProperty_copy( + DDS_Security_BinaryProperty_t *dst, + const DDS_Security_BinaryProperty_t *src); + +DDS_EXPORT bool +DDS_Security_BinaryProperty_equal( + const DDS_Security_BinaryProperty_t *pa, + const DDS_Security_BinaryProperty_t *pb); + +DDS_EXPORT void +DDS_Security_BinaryProperty_set_by_value( + DDS_Security_BinaryProperty_t *bp, + const char *name, + const unsigned char *data, + uint32_t length); + +DDS_EXPORT void +DDS_Security_BinaryProperty_set_by_string( + DDS_Security_BinaryProperty_t *bp, + const char *name, + const char *data); + +DDS_EXPORT void +DDS_Security_BinaryProperty_set_by_ref( + DDS_Security_BinaryProperty_t *bp, + const char *name, + unsigned char *data, + uint32_t length); + +DDS_EXPORT DDS_Security_BinaryPropertySeq * +DDS_Security_BinaryPropertySeq_alloc( + void); + +DDS_EXPORT DDS_Security_BinaryProperty_t * +DDS_Security_BinaryPropertySeq_allocbuf( + DDS_Security_unsigned_long len); + +DDS_EXPORT void +DDS_Security_BinaryPropertySeq_deinit( + DDS_Security_BinaryPropertySeq *seq); + +DDS_EXPORT void +DDS_Security_BinaryPropertySeq_free( + DDS_Security_BinaryPropertySeq *seq); + +DDS_EXPORT DDS_Security_Property_t * +DDS_Security_Property_alloc( + void); + +DDS_EXPORT void +DDS_Security_Property_free( + DDS_Security_Property_t *p); + +DDS_EXPORT void +DDS_Security_Property_deinit( + DDS_Security_Property_t *p); + +DDS_EXPORT void +DDS_Security_Property_copy( + DDS_Security_Property_t *dst, + const DDS_Security_Property_t *src); + +DDS_EXPORT bool +DDS_Security_Property_equal( + const DDS_Security_Property_t *pa, + const DDS_Security_Property_t *pb); + +DDS_EXPORT char * +DDS_Security_Property_get_value( + const DDS_Security_PropertySeq *properties, + const char *name); + +DDS_EXPORT DDS_Security_PropertySeq * +DDS_Security_PropertySeq_alloc( + void); + +DDS_EXPORT DDS_Security_Property_t * +DDS_Security_PropertySeq_allocbuf( + DDS_Security_unsigned_long len); + +DDS_EXPORT void +DDS_Security_PropertySeq_freebuf( + DDS_Security_PropertySeq *seq); + +DDS_EXPORT void +DDS_Security_PropertySeq_free( + DDS_Security_PropertySeq *seq); + +DDS_EXPORT void +DDS_Security_PropertySeq_deinit( + DDS_Security_PropertySeq *seq); + +DDS_EXPORT const DDS_Security_Property_t * +DDS_Security_PropertySeq_find_property ( + const DDS_Security_PropertySeq *property_seq, + const char *name ); + +DDS_EXPORT DDS_Security_DataHolder * +DDS_Security_DataHolder_alloc( + void); + +DDS_EXPORT void +DDS_Security_DataHolder_free( + DDS_Security_DataHolder *holder); + +DDS_EXPORT void +DDS_Security_DataHolder_deinit( + DDS_Security_DataHolder *holder); + +DDS_EXPORT void +DDS_Security_DataHolder_copy( + DDS_Security_DataHolder *dst, + const DDS_Security_DataHolder *src); + +DDS_EXPORT bool +DDS_Security_DataHolder_equal( + const DDS_Security_DataHolder *psa, + const DDS_Security_DataHolder *psb); + +DDS_EXPORT const DDS_Security_Property_t * +DDS_Security_DataHolder_find_property( + const DDS_Security_DataHolder *holder, + const char *name); + +DDS_EXPORT const DDS_Security_BinaryProperty_t * +DDS_Security_DataHolder_find_binary_property( + const DDS_Security_DataHolder *holder, + const char *name); + +DDS_EXPORT DDS_Security_DataHolderSeq * +DDS_Security_DataHolderSeq_alloc( + void); + +DDS_EXPORT DDS_Security_DataHolder * +DDS_Security_DataHolderSeq_allocbuf( + DDS_Security_unsigned_long len); + +DDS_EXPORT void +DDS_Security_DataHolderSeq_freebuf( + DDS_Security_DataHolderSeq *seq); + +DDS_EXPORT void +DDS_Security_DataHolderSeq_free( + DDS_Security_DataHolderSeq *seq); + +DDS_EXPORT void +DDS_Security_DataHolderSeq_deinit( + DDS_Security_DataHolderSeq *seq); + +DDS_EXPORT void +DDS_Security_DataHolderSeq_copy( + DDS_Security_DataHolderSeq *dst, + const DDS_Security_DataHolderSeq *src); + +DDS_EXPORT DDS_Security_ParticipantBuiltinTopicData * +DDS_Security_ParticipantBuiltinTopicData_alloc( + void); + +DDS_EXPORT void +DDS_Security_ParticipantBuiltinTopicData_free( + DDS_Security_ParticipantBuiltinTopicData *data); + +DDS_EXPORT void +DDS_Security_ParticipantBuiltinTopicData_deinit( + DDS_Security_ParticipantBuiltinTopicData *data); + +DDS_EXPORT DDS_Security_OctetSeq * +DDS_Security_OctetSeq_alloc( + void); + +DDS_EXPORT DDS_Security_octet * +DDS_Security_OctetSeq_allocbuf( + DDS_Security_unsigned_long len); + +DDS_EXPORT void +DDS_Security_OctetSeq_freebuf( + DDS_Security_OctetSeq *seq); + +DDS_EXPORT void +DDS_Security_OctetSeq_free( + DDS_Security_OctetSeq *seq); + +DDS_EXPORT void +DDS_Security_OctetSeq_deinit( + DDS_Security_OctetSeq *seq); + +DDS_EXPORT void +DDS_Security_OctetSeq_copy( + DDS_Security_OctetSeq *dst, + const DDS_Security_OctetSeq *src); + +DDS_EXPORT DDS_Security_HandleSeq * +DDS_Security_HandleSeq_alloc( + void); + +DDS_EXPORT DDS_Security_long_long * +DDS_Security_HandleSeq_allocbuf( + DDS_Security_unsigned_long length); + +DDS_EXPORT void +DDS_Security_HandleSeq_freebuf( + DDS_Security_HandleSeq *seq); + +DDS_EXPORT void +DDS_Security_HandleSeq_free( + DDS_Security_HandleSeq *seq); + +DDS_EXPORT void +DDS_Security_HandleSeq_deinit( + DDS_Security_HandleSeq *seq); + +DDS_EXPORT void +DDS_Security_Exception_vset( + DDS_Security_SecurityException *ex, + const char *context, + int code, + int minor_code, + const char *fmt, + va_list ap); + +DDS_EXPORT void +DDS_Security_Exception_set( + DDS_Security_SecurityException *ex, + const char *context, + int code, + int minor_code, + const char *fmt, + ...); + +DDS_EXPORT void +DDS_Security_Exception_reset( + DDS_Security_SecurityException *ex); + +DDS_EXPORT void +DDS_Security_Exception_clean( + DDS_Security_SecurityException *ex); + +DDS_EXPORT void +DDS_Security_PropertyQosPolicy_deinit( + DDS_Security_PropertyQosPolicy *policy); + +DDS_EXPORT void +DDS_Security_PropertyQosPolicy_free( + DDS_Security_PropertyQosPolicy *policy); + +DDS_EXPORT void +DDS_Security_set_token_nil( + DDS_Security_DataHolder *token); + +DDS_EXPORT void +DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit( + DDS_Security_KeyMaterial_AES_GCM_GMAC *key_material); + +DDS_EXPORT DDS_Security_CryptoTransformKind_Enum +DDS_Security_basicprotectionkind2transformationkind( + const DDS_Security_PropertySeq *properties, + DDS_Security_BasicProtectionKind protection); + +DDS_EXPORT DDS_Security_CryptoTransformKind_Enum +DDS_Security_protectionkind2transformationkind( + const DDS_Security_PropertySeq *properties, + DDS_Security_ProtectionKind protection); + +DDS_EXPORT DDS_Security_config_item_prefix_t +DDS_Security_get_conf_item_type( + const char *str, + char **data); + +DDS_EXPORT char * +DDS_Security_normalize_file( + const char *filepath); + +/** + * \brief Find first occurrence of character in null terminated string + * + * @param str String to search for given characters + * @param chrs Characters to search for in string + * @param inc true to find first character included in given characters, + * false to find first character not included. + * @return Pointer to first occurrence of character in string, or NULL + */ + +DDS_EXPORT char * +ddssec_strchrs ( + const char *str, + const char *chrs, + bool inc); + +DDS_EXPORT dds_time_t +DDS_Security_parse_xml_date( + char *buf); + + +#define DDS_Security_ParticipantCryptoTokenSeq_alloc() \ + DDS_Security_DataHolderSeq_alloc()) +#define DDS_Security_ParticipantCryptoTokenSeq_freebuf(s) \ + DDS_Security_DataHolderSeq_freebuf(s) +#define DDS_Security_ParticipantCryptoTokenSeq_free(s) \ + DDS_Security_DataHolderSeq_free(s) +#define DDS_Security_ParticipantCryptoTokenSeq_deinit(s) \ + DDS_Security_DataHolderSeq_deinit(s) +#define DDS_Security_ParticipantCryptoTokenSeq_copy(d,s) \ + DDS_Security_DataHolderSeq_copy((d), (s)) + + +#define DDS_Security_ParticipantCryptoHandleSeq_alloc() DDS_Security_HandleSeq_alloc() +#define DDS_Security_ParticipantCryptoHandleSeq_allocbuf(l) DDS_Security_HandleSeq_allocbuf(l) +#define DDS_Security_ParticipantCryptoHandleSeq_freebuf(s) DDS_Security_HandleSeq_freebuf(s) +#define DDS_Security_ParticipantCryptoHandleSeq_free(s) DDS_Security_HandleSeq_free(s) +#define DDS_Security_ParticipantCryptoHandleSeq_deinit(s) DDS_Security_HandleSeq_deinit(s) + +#define DDS_Security_DatawriterCryptoHandleSeq_alloc() DDS_Security_HandleSeq_alloc() +#define DDS_Security_DatawriterCryptoHandleSeq_allocbuf(l) DDS_Security_HandleSeq_allocbuf(l) +#define DDS_Security_DatawriterCryptoHandleSeq_freebuf(s) DDS_Security_HandleSeq_freebuf(s) +#define DDS_Security_DatawriterCryptoHandleSeq_free(s) DDS_Security_HandleSeq_free(s) +#define DDS_Security_DatawriterCryptoHandleSeq_deinit(s) DDS_Security_HandleSeq_deinit(s) + +#define DDS_Security_DatareaderCryptoHandleSeq_alloc() DDS_Security_HandleSeq_alloc() +#define DDS_Security_DatareaderCryptoHandleSeq_allocbuf(l) DDS_Security_HandleSeq_allocbuf(l) +#define DDS_Security_DatareaderCryptoHandleSeq_freebuf(s) DDS_Security_HandleSeq_freebuf(s) +#define DDS_Security_DatareaderCryptoHandleSeq_free(s) DDS_Security_HandleSeq_free(s) +#define DDS_Security_DatareaderCryptoHandleSeq_deinit(s) DDS_Security_HandleSeq_deinit(s) + +#define DDS_Security_CryptoTokenSeq_alloc() DDS_Security_DataHolderSeq_alloc() +#define DDS_Security_CryptoTokenSeq_allocbuf(l) DDS_Security_DataHolderSeq_allocbuf(l) +#define DDS_Security_CryptoTokenSeq_freebuf(s) DDS_Security_DataHolderSeq_freebuf(s) +#define DDS_Security_CryptoTokenSeq_free(s) DDS_Security_DataHolderSeq_free(s) + + +/* for DEBUG purposes */ +DDS_EXPORT void +print_binary_debug( + char* name, + unsigned char *value, + uint32_t size); + +DDS_EXPORT void +print_binary_properties_debug( + const DDS_Security_DataHolder *token); + + +#endif /* DSCMN_SECURITY_UTILS_H_ */ diff --git a/src/security/core/include/dds/security/core/shared_secret.h b/src/security/core/include/dds/security/core/shared_secret.h new file mode 100644 index 0000000..e0302e9 --- /dev/null +++ b/src/security/core/include/dds/security/core/shared_secret.h @@ -0,0 +1,33 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef SRC_SECURITY_CORE_INCLUDE_SHARED_SECRET_HANDLE_H_ +#define SRC_SECURITY_CORE_INCLUDE_SHARED_SECRET_HANDLE_H_ + +#include +#include + +#include "dds/export.h" +#include "dds/security/dds_security_api.h" + +typedef struct DDS_Security_SharedSecretHandleImpl { + DDS_Security_octet* shared_secret; + DDS_Security_long shared_secret_size; + DDS_Security_octet challenge1[DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE]; + DDS_Security_octet challenge2[DDS_SECURITY_AUTHENTICATION_CHALLENGE_SIZE]; +} DDS_Security_SharedSecretHandleImpl; + +DDS_EXPORT const DDS_Security_octet* get_challenge1_from_secret_handle (DDS_Security_SharedSecretHandle handle); +DDS_EXPORT const DDS_Security_octet* get_challenge2_from_secret_handle (DDS_Security_SharedSecretHandle handle); +DDS_EXPORT const DDS_Security_octet* get_secret_from_secret_handle (DDS_Security_SharedSecretHandle handle); +DDS_EXPORT size_t get_secret_size_from_secret_handle (DDS_Security_SharedSecretHandle handle); + +#endif /* SRC_SECURITY_CORE_INCLUDE_SHARED_SECRET_H_ */ diff --git a/src/security/core/src/dds_security_fsm.c b/src/security/core/src/dds_security_fsm.c new file mode 100644 index 0000000..e2b9436 --- /dev/null +++ b/src/security/core/src/dds_security_fsm.c @@ -0,0 +1,576 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include + +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/retcode.h" +#include "dds/ddsrt/time.h" +#include "dds/ddsrt/timeconv.h" +#include "dds/ddsrt/fibheap.h" +#include "dds/ddsi/q_thread.h" +#include "dds/security/core/dds_security_fsm.h" + + +struct fsm_event +{ + struct dds_security_fsm *fsm; + int event_id; + struct fsm_event *next; + struct fsm_event *prev; +}; + +typedef enum fsm_timeout_kind { + FSM_TIMEOUT_STATE, + FSM_TIMEOUT_OVERALL +} fsm_timeout_kind_t; + +struct fsm_timer_event +{ + ddsrt_fibheap_node_t heapnode; + struct dds_security_fsm *fsm; + fsm_timeout_kind_t kind; + dds_time_t endtime; +}; + +struct dds_security_fsm +{ + struct dds_security_fsm *next_fsm; + struct dds_security_fsm *prev_fsm; + bool deleting; + struct dds_security_fsm_control *control; + const dds_security_fsm_transition *transitions; + uint32_t size; + void *arg; + const dds_security_fsm_state *current; + struct fsm_timer_event state_timeout_event; + struct fsm_timer_event overall_timeout_event; + dds_security_fsm_action overall_timeout_action; + dds_security_fsm_debug debug_func; +}; + +struct dds_security_fsm_control +{ + ddsrt_mutex_t lock; + ddsrt_cond_t cond; + struct thread_state1 *ts; + struct ddsi_domaingv *gv; + struct dds_security_fsm *first_fsm; + struct dds_security_fsm *last_fsm; + struct fsm_event *first_event; + struct fsm_event *last_event; + ddsrt_fibheap_t timers; + bool running; +}; + +static int compare_timer_event (const void *va, const void *vb); +static void fsm_delete (struct dds_security_fsm_control *control, struct dds_security_fsm *fsm); + +const ddsrt_fibheap_def_t timer_events_fhdef = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (struct fsm_timer_event, heapnode), compare_timer_event); + +static int compare_timer_event (const void *va, const void *vb) +{ + const struct fsm_timer_event *a = va; + const struct fsm_timer_event *b = 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; + struct fsm_event *event; + + if (fsm->debug_func) { + fsm->debug_func(fsm, + lifo ? DDS_SECURITY_FSM_DEBUG_ACT_DISPATCH_DIRECT : DDS_SECURITY_FSM_DEBUG_ACT_DISPATCH, + fsm->current, event_id, fsm->arg); + } + + event = ddsrt_malloc (sizeof(struct fsm_event)); + event->fsm = fsm; + event->event_id = event_id; + event->next = NULL; + event->prev = NULL; + + if (lifo) + insert_event(control, event); + else + append_event(control, event); +} + +static void set_state_timer (struct dds_security_fsm *fsm) +{ + struct dds_security_fsm_control *control = fsm->control; + + if (fsm->current && fsm->current->timeout > 0 && fsm->current->timeout != DDS_NEVER) + { + fsm->state_timeout_event.endtime = ddsrt_time_add_duration (dds_time(), fsm->current->timeout); + ddsrt_fibheap_insert (&timer_events_fhdef, &control->timers, &fsm->state_timeout_event); + } + else + fsm->state_timeout_event.endtime = DDS_NEVER; +} + +static void clear_state_timer (struct dds_security_fsm *fsm) +{ + struct dds_security_fsm_control *control = fsm->control; + + 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->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) +{ + struct fsm_timer_event *min; + if ((min = ddsrt_fibheap_min (&timer_events_fhdef, &control->timers)) != NULL) + return min->endtime; + return DDS_NEVER; +} + +static void fsm_check_auto_state_change (struct dds_security_fsm *fsm) +{ + if (fsm->current) + { + uint32_t i; + + for (i = 0; i < fsm->size; i++) + { + if (fsm->transitions[i].begin == fsm->current && fsm->transitions[i].event_id == DDS_SECURITY_FSM_EVENT_AUTO) + { + fsm_dispatch (fsm, DDS_SECURITY_FSM_EVENT_AUTO, true); + break; + } + } + } +} + +static void fsm_state_change (struct dds_security_fsm_control *control, struct fsm_event *event) +{ + struct dds_security_fsm *fsm = event->fsm; + int event_id = event->event_id; + uint32_t 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)) + { + clear_state_timer (fsm); + fsm->current = fsm->transitions[i].end; + set_state_timer (fsm); + + ddsrt_mutex_unlock (&control->lock); + + if (fsm->transitions[i].func) + fsm->transitions[i].func (fsm, fsm->arg); + if (fsm->current && fsm->current->func) + fsm->current->func (fsm, fsm->arg); + + ddsrt_mutex_lock (&control->lock); + if (!fsm->deleting) + fsm_check_auto_state_change (fsm); + else + ddsrt_cond_broadcast(&control->cond); + break; + } + } +} + +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; + + 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); + if (fsm->deleting) + ddsrt_cond_broadcast(&control->cond); + break; + } + + /* mark timer event as being processed */ + timer_event->endtime = DDS_NEVER; +} + +static uint32_t handle_events (struct dds_security_fsm_control *control) +{ + struct thread_state1 * const ts1 = lookup_thread_state (); + struct fsm_event *event; + + thread_state_awake (ts1, control->gv); + ddsrt_mutex_lock (&control->lock); + while (control->running) + { + if ((event = get_event(control)) != NULL) + { + fsm_state_change (control, event); + ddsrt_free (event); + } + else + { + dds_time_t timeout = first_timeout (control); + + if (timeout > dds_time ()) + { + thread_state_asleep (ts1); + (void)ddsrt_cond_waituntil (&control->cond, &control->lock, timeout); + thread_state_awake (ts1, control->gv); + } + else + { + struct fsm_timer_event *timer_event = ddsrt_fibheap_extract_min (&timer_events_fhdef, &control->timers); + fsm_handle_timeout (control, timer_event); + } + } + } + ddsrt_mutex_unlock (&control->lock); + thread_state_asleep (ts1); + return 0; +} + +void dds_security_fsm_set_timeout (struct dds_security_fsm *fsm, dds_security_fsm_action action, dds_duration_t timeout) +{ + assert(fsm); + assert(fsm->control); + assert(timeout > 0); + + ddsrt_mutex_lock (&fsm->control->lock); + if (!fsm->deleting) + { + if (timeout != DDS_NEVER) + { + clear_overall_timer(fsm); + fsm->overall_timeout_action = action; + 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_broadcast (&fsm->control->cond); + } + else + clear_overall_timer (fsm); + } + ddsrt_mutex_unlock (&fsm->control->lock); +} + +void dds_security_fsm_dispatch (struct dds_security_fsm *fsm, int32_t event_id, bool prio) +{ + assert(fsm); + assert(fsm->control); + + ddsrt_mutex_lock (&fsm->control->lock); + if (!fsm->deleting) + { + fsm_dispatch (fsm, event_id, prio); + ddsrt_cond_broadcast (&fsm->control->cond); + } + ddsrt_mutex_unlock (&fsm->control->lock); +} + +const dds_security_fsm_state * dds_security_fsm_current_state (struct dds_security_fsm *fsm) +{ + const dds_security_fsm_state *state; + + assert(fsm); + + ddsrt_mutex_lock (&fsm->control->lock); + state = fsm->current; + ddsrt_mutex_unlock (&fsm->control->lock); + + return state; +} + +void dds_security_fsm_set_debug (struct dds_security_fsm *fsm, dds_security_fsm_debug func) +{ + assert(fsm); + + ddsrt_mutex_lock (&fsm->control->lock); + fsm->debug_func = func; + ddsrt_mutex_unlock (&fsm->control->lock); +} + +static bool fsm_validate (const dds_security_fsm_transition *transitions, uint32_t size) +{ + uint32_t i; + + for (i = 0; i < size; i++) + { + /* It needs to have a start. */ + if (transitions[i].begin && transitions[i].event_id == DDS_SECURITY_FSM_EVENT_AUTO) + return true; + } + return true; +} + +static void add_fsm_to_list (struct dds_security_fsm_control *control, struct dds_security_fsm *fsm) +{ + fsm->next_fsm = NULL; + fsm->prev_fsm = control->last_fsm; + if (control->last_fsm) + { + assert(control->first_fsm != NULL); + control->last_fsm->next_fsm = fsm; + } + else + { + assert(control->first_fsm == NULL); + control->first_fsm = fsm; + } + control->last_fsm = fsm; +} + +static void remove_fsm_from_list (struct dds_security_fsm_control *control, struct dds_security_fsm *fsm) +{ + if (fsm->prev_fsm) + fsm->prev_fsm->next_fsm = fsm->next_fsm; + else + control->first_fsm = fsm->next_fsm; + + if (fsm->next_fsm) + fsm->next_fsm->prev_fsm = fsm->prev_fsm; + else + control->last_fsm = fsm->prev_fsm; +} + +struct dds_security_fsm * dds_security_fsm_create (struct dds_security_fsm_control *control, const dds_security_fsm_transition *transitions, uint32_t size, void *arg) +{ + struct dds_security_fsm *fsm = NULL; + + assert(control); + assert(transitions); + + if (fsm_validate (transitions, size)) + { + fsm = ddsrt_malloc (sizeof(struct dds_security_fsm)); + fsm->transitions = transitions; + fsm->size = size; + fsm->arg = arg; + fsm->current = NULL; + fsm->debug_func = NULL; + fsm->overall_timeout_action = NULL; + fsm->state_timeout_event.kind = FSM_TIMEOUT_STATE; + fsm->state_timeout_event.endtime = DDS_NEVER; + fsm->state_timeout_event.fsm = fsm; + fsm->overall_timeout_event.kind = FSM_TIMEOUT_OVERALL; + fsm->overall_timeout_event.endtime = DDS_NEVER; + fsm->overall_timeout_event.fsm = fsm; + fsm->deleting = false; + fsm->next_fsm = NULL; + fsm->prev_fsm = NULL; + fsm->control = control; + + ddsrt_mutex_lock (&control->lock); + add_fsm_to_list (control, fsm); + ddsrt_mutex_unlock (&control->lock); + } + return fsm; +} + +void +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_control *control, struct dds_security_fsm *fsm) +{ + fsm->deleting = true; + remove_events(control, fsm); + clear_state_timer (fsm); + clear_overall_timer (fsm); + fsm->current = NULL; +} + +void dds_security_fsm_stop (struct dds_security_fsm *fsm) +{ + struct dds_security_fsm_control *control; + + assert(fsm); + assert(fsm->control); + + control = fsm->control; + ddsrt_mutex_lock (&control->lock); + fsm_deactivate (control, fsm); + ddsrt_mutex_unlock (&control->lock); +} + +static void fsm_delete (struct dds_security_fsm_control *control, struct dds_security_fsm *fsm) +{ + remove_fsm_from_list (control, fsm); + fsm_deactivate (control, fsm); + ddsrt_free(fsm); +} + +void dds_security_fsm_free (struct dds_security_fsm *fsm) +{ + struct dds_security_fsm_control *control; + + assert(fsm); + assert(fsm->control); + + control = fsm->control; + ddsrt_mutex_lock (&control->lock); + fsm_delete (control, fsm); + ddsrt_mutex_unlock (&control->lock); +} + +struct dds_security_fsm_control * dds_security_fsm_control_create (struct ddsi_domaingv *gv) +{ + struct dds_security_fsm_control *control; + + control = ddsrt_malloc (sizeof(*control)); + control->running = false; + control->first_event = NULL; + control->last_event = NULL; + control->first_fsm = NULL; + control->last_fsm = NULL; + control->gv = gv; + ddsrt_mutex_init (&control->lock); + ddsrt_cond_init (&control->cond); + ddsrt_fibheap_init (&timer_events_fhdef, &control->timers); + + return control; +} + +void dds_security_fsm_control_free (struct dds_security_fsm_control *control) +{ + struct dds_security_fsm *fsm; + struct fsm_event *event; + + assert(control); + assert(!control->running); + + while ((fsm = control->first_fsm) != NULL) + { + control->first_fsm = fsm->next_fsm; + fsm_delete (control, fsm); + } + while ((event = control->first_event) != NULL) + { + control->first_event = event->next; + ddsrt_free (event); + } + + ddsrt_cond_destroy (&control->cond); + ddsrt_mutex_destroy (&control->lock); + ddsrt_free (control); +} + +dds_return_t dds_security_fsm_control_start (struct dds_security_fsm_control *control, const char *name) +{ + dds_return_t rc; + const char *fsm_name = name ? name : "fsm"; + + assert(control); + + control->running = true; + rc = create_thread (&control->ts, control->gv, fsm_name, (uint32_t (*) (void *)) handle_events, control); + + return rc; +} + +void dds_security_fsm_control_stop (struct dds_security_fsm_control *control) +{ + assert(control); + assert(control->running); + + ddsrt_mutex_lock (&control->lock); + control->running = false; + ddsrt_cond_broadcast (&control->cond); + ddsrt_mutex_unlock (&control->lock); + + join_thread (control->ts); + control->ts = NULL; +} diff --git a/src/security/core/src/dds_security_plugins.c b/src/security/core/src/dds_security_plugins.c new file mode 100644 index 0000000..15c5fb5 --- /dev/null +++ b/src/security/core/src/dds_security_plugins.c @@ -0,0 +1,267 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include + +#include "dds/security/core/dds_security_plugins.h" +#include "dds/ddsrt/log.h" +#include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/dynlib.h" +#include "dds/ddsrt/io.h" + +static bool check_plugin_configuration (const dds_security_plugin_config *config, const char *name, struct ddsi_domaingv *gv) +{ + if (config->library_path == NULL || *config->library_path == 0) { + GVERROR ("%s security plugin library path is undefined or empty\n", name); + return false; + } + if (config->library_init == NULL || *config->library_init == 0) { + GVERROR ("%s security plugin init function is undefined or empty\n", name); + return false; + } + if (config->library_finalize == NULL || *config->library_finalize == 0) { + GVERROR ("%s security plugin finalize function is undefined or empty\n", name); + return false; + } + return true; +} + +dds_return_t dds_security_check_plugin_configuration (const dds_security_plugin_suite_config *security_suite_config, struct ddsi_domaingv *gv) +{ + if (check_plugin_configuration (&security_suite_config->access_control, "AccessControl", gv) && + check_plugin_configuration (&security_suite_config->authentication, "Authentication", gv) && + check_plugin_configuration (&security_suite_config->cryptography, "Cryptography", gv)) + return DDS_RETCODE_OK; + else + return DDS_RETCODE_ERROR; +} + +static bool verify_function (const void *function_ptr, dds_security_plugin *plugin, const char *function_name, struct ddsi_domaingv *gv) +{ + if (function_ptr != NULL) + return true; + else + { + GVERROR ("Could not find the function for %s: %s\n", plugin->name, function_name); + return false; + } +} + +struct verify_plugin_functions_tab { + size_t off; + const char *name; +}; + +static bool verify_plugin_functions (const void *context, dds_security_plugin *plugin, const struct verify_plugin_functions_tab *entries, size_t nentries, struct ddsi_domaingv *gv) +{ + for (size_t i = 0; i < nentries; i++) + { + const char *p = (const char *) context + entries[i].off; + if (!verify_function (*((void **) p), plugin, entries[i].name, gv)) + return false; + } + return true; +} + +dds_return_t dds_security_verify_plugin_functions( + dds_security_authentication *authentication_context, dds_security_plugin *auth_plugin, + dds_security_cryptography *crypto_context, dds_security_plugin *crypto_plugin, + dds_security_access_control *access_control_context, dds_security_plugin *ac_plugin, + struct ddsi_domaingv *gv) +{ +#define FGEN(context, name) { offsetof (context, name), #name } +#define F(name) FGEN (dds_security_authentication, name) + static const struct verify_plugin_functions_tab auth[] = { + F (validate_local_identity), + F (get_identity_token), + F (get_identity_status_token), + F (set_permissions_credential_and_token), + F (validate_remote_identity), + F (begin_handshake_request), + F (begin_handshake_reply), + F (process_handshake), + F (get_shared_secret), + F (get_authenticated_peer_credential_token), + F (set_listener), + F (return_identity_token), + F (return_identity_status_token), + F (return_authenticated_peer_credential_token), + F (return_handshake_handle), + F (return_sharedsecret_handle) + }; +#undef F +#define F(name) FGEN (dds_security_access_control, name) + static const struct verify_plugin_functions_tab ac[] = { + F (validate_local_permissions), + F (validate_remote_permissions), + F (check_create_participant), + F (check_create_datawriter), + F (check_create_datareader), + F (check_create_topic), + F (check_local_datawriter_register_instance), + F (check_local_datawriter_dispose_instance), + F (check_remote_participant), + F (check_remote_datawriter), + F (check_remote_datareader), + F (check_remote_topic), + F (check_local_datawriter_match), + F (check_local_datareader_match), + F (check_remote_datawriter_register_instance), + F (check_remote_datawriter_dispose_instance), + F (get_permissions_token), + F (get_permissions_credential_token), + F (set_listener), + F (return_permissions_token), + F (return_permissions_credential_token), + F (get_participant_sec_attributes), + F (get_topic_sec_attributes), + F (get_datawriter_sec_attributes), + F (get_datareader_sec_attributes), + F (return_participant_sec_attributes), + F (return_datawriter_sec_attributes), + F (return_datareader_sec_attributes), + F (return_permissions_handle) + }; +#undef F +#define F(name) FGEN (dds_security_crypto_key_factory, name) + static const struct verify_plugin_functions_tab cryptoF[] = { + F (register_local_participant), + F (register_matched_remote_participant), + F (register_local_datawriter), + F (register_matched_remote_datareader), + F (register_local_datareader), + F (register_matched_remote_datawriter), + F (unregister_participant), + F (unregister_datawriter), + F (unregister_datareader) + }; +#undef F +#define F(name) FGEN (dds_security_crypto_key_exchange, name) + static const struct verify_plugin_functions_tab cryptoX[] = { + F (create_local_participant_crypto_tokens), + F (set_remote_participant_crypto_tokens), + F (create_local_datawriter_crypto_tokens), + F (set_remote_datawriter_crypto_tokens), + F (create_local_datareader_crypto_tokens), + F (set_remote_datareader_crypto_tokens), + F (return_crypto_tokens) + }; +#undef F +#define F(name) FGEN (dds_security_crypto_transform, name) + static const struct verify_plugin_functions_tab cryptoT[] = { + F (encode_serialized_payload), + F (encode_datawriter_submessage), + F (encode_datareader_submessage), + F (encode_rtps_message), + F (decode_rtps_message), + F (preprocess_secure_submsg), + F (decode_datawriter_submessage), + F (decode_datareader_submessage), + F (decode_serialized_payload) + }; +#undef F +#define C(context, plugin, table) verify_plugin_functions (context, plugin, table, sizeof (table) / sizeof (table[0]), gv) + if (C (authentication_context, auth_plugin, auth) && + C (access_control_context, ac_plugin, ac) && + C (crypto_context->crypto_key_factory, crypto_plugin, cryptoF) && + C (crypto_context->crypto_key_exchange, crypto_plugin, cryptoX) && + C (crypto_context->crypto_transform, crypto_plugin, cryptoT)) + { + return DDS_RETCODE_OK; + } + else + { + return DDS_RETCODE_ERROR; + } +#undef C +} + +/** + * All fields of the library properties are supposed to be non-empty + */ +dds_return_t dds_security_load_security_library (const dds_security_plugin_config *plugin_config, dds_security_plugin *security_plugin, + void **security_plugin_context, struct ddsi_domaingv *gv) +{ + dds_return_t lib_ret; + char *init_parameters = ""; + char *library_str; + + assert (plugin_config->library_path); + assert (plugin_config->library_init); + assert (plugin_config->library_finalize); + + security_plugin->lib_handle = NULL; + if (*plugin_config->library_path == 0) + return DDS_RETCODE_ERROR; + + const size_t poff = (strncmp (plugin_config->library_path, "file://", 7) == 0) ? 7 : 0; + (void) ddsrt_asprintf (&library_str, "%s", plugin_config->library_path + poff); + lib_ret = ddsrt_dlopen (library_str, true, &security_plugin->lib_handle); + ddsrt_free (library_str); + if (lib_ret != DDS_RETCODE_OK) + { + char buffer[256]; + ddsrt_dlerror (buffer, sizeof (buffer)); + GVERROR ("Could not load %s library: %s\n", security_plugin->name, buffer); + goto load_error; + } + + void *tmp; + if (ddsrt_dlsym (security_plugin->lib_handle, plugin_config->library_init, &tmp) != DDS_RETCODE_OK) + { + GVERROR ("Could not find the function: %s\n", plugin_config->library_init); + goto library_error; + } + security_plugin->func_init = (plugin_init) tmp; + + if (ddsrt_dlsym (security_plugin->lib_handle, plugin_config->library_finalize, &tmp) != DDS_RETCODE_OK) + { + GVERROR ("Could not find the function: %s\n", plugin_config->library_finalize); + goto library_error; + } + security_plugin->func_finalize = (plugin_finalize) tmp; + + if (security_plugin->func_init != 0) + { + if (security_plugin->func_init (init_parameters, (void **) security_plugin_context, gv) != DDS_RETCODE_OK) + { + GVERROR ("Error occured while initializing %s plugin\n", security_plugin->name); + goto library_error; + } + } + return DDS_RETCODE_OK; + +library_error: + ddsrt_dlclose (security_plugin->lib_handle); + security_plugin->lib_handle = NULL; +load_error: + return DDS_RETCODE_ERROR; +} + +dds_return_t dds_security_plugin_release (const dds_security_plugin *security_plugin, void *context) +{ + dds_return_t result = DDS_RETCODE_OK; + assert (security_plugin->lib_handle); + assert (security_plugin->func_finalize); + + /* if get error from either finalize OR close, return error */ + if (security_plugin->func_finalize (context) != DDS_RETCODE_OK) + { + DDS_ERROR("Error occured while finaizing %s plugin", security_plugin->name); + result = DDS_RETCODE_ERROR; + } + if (ddsrt_dlclose (security_plugin->lib_handle) != DDS_RETCODE_OK){ + result = DDS_RETCODE_ERROR; + } + return result; +} diff --git a/src/security/core/src/dds_security_serialize.c b/src/security/core/src/dds_security_serialize.c new file mode 100644 index 0000000..7e182df --- /dev/null +++ b/src/security/core/src/dds_security_serialize.c @@ -0,0 +1,823 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + + +#include +#include +#include "dds/ddsrt/bswap.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/string.h" + +#include "dds/security/core/dds_security_serialize.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/ddsrt/endian.h" +#include "dds/ddsrt/bswap.h" + + +#define BYTE_ORDER_BIG_ENDIAN 0x02 +#define BYTE_ORDER_LITTLE_ENDIAN 0x03 + +#define PID_PAD 0x0u +#define PID_SENTINEL 0x1u +#define PID_USER_DATA 0x2cu +#define PID_TOPIC_NAME 0x5u +#define PID_TYPE_NAME 0x7u +#define PID_GROUP_DATA 0x2du +#define PID_TOPIC_DATA 0x2eu +#define PID_DURABILITY 0x1du +#define PID_DURABILITY_SERVICE 0x1eu +#define PID_DEADLINE 0x23u +#define PID_LATENCY_BUDGET 0x27u +#define PID_LIVELINESS 0x1bu +#define PID_RELIABILITY 0x1au +#define PID_LIFESPAN 0x2bu +#define PID_DESTINATION_ORDER 0x25u +#define PID_HISTORY 0x40u +#define PID_RESOURCE_LIMITS 0x41u +#define PID_OWNERSHIP 0x1fu +#define PID_OWNERSHIP_STRENGTH 0x6u +#define PID_PRESENTATION 0x21u +#define PID_PARTITION 0x29u +#define PID_TIME_BASED_FILTER 0x4u +#define PID_TRANSPORT_PRIORITY 0x49u +#define PID_PROTOCOL_VERSION 0x15u +#define PID_VENDORID 0x16u +#define PID_UNICAST_LOCATOR 0x2fu +#define PID_MULTICAST_LOCATOR 0x30u +#define PID_MULTICAST_IPADDRESS 0x11u +#define PID_DEFAULT_UNICAST_LOCATOR 0x31u +#define PID_DEFAULT_MULTICAST_LOCATOR 0x48u +#define PID_METATRAFFIC_UNICAST_LOCATOR 0x32u +#define PID_METATRAFFIC_MULTICAST_LOCATOR 0x33u +#define PID_DEFAULT_UNICAST_IPADDRESS 0xcu +#define PID_DEFAULT_UNICAST_PORT 0xeu +#define PID_METATRAFFIC_UNICAST_IPADDRESS 0x45u +#define PID_METATRAFFIC_UNICAST_PORT 0xdu +#define PID_METATRAFFIC_MULTICAST_IPADDRESS 0xbu +#define PID_METATRAFFIC_MULTICAST_PORT 0x46u +#define PID_EXPECTS_INLINE_QOS 0x43u +#define PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT 0x34u +#define PID_PARTICIPANT_BUILTIN_ENDPOINTS 0x44u +#define PID_PARTICIPANT_LEASE_DURATION 0x2u +#define PID_CONTENT_FILTER_PROPERTY 0x35u +#define PID_PARTICIPANT_GUID 0x50u +#define PID_PARTICIPANT_ENTITYID 0x51u +#define PID_GROUP_GUID 0x52u +#define PID_GROUP_ENTITYID 0x53u +#define PID_BUILTIN_ENDPOINT_SET 0x58u +#define PID_PROPERTY_LIST 0x59u +#define PID_TYPE_MAX_SIZE_SERIALIZED 0x60u +#define PID_ENTITY_NAME 0x62u +#define PID_KEYHASH 0x70u +#define PID_STATUSINFO 0x71u +#define PID_CONTENT_FILTER_INFO 0x55u +#define PID_COHERENT_SET 0x56u +#define PID_DIRECTED_WRITE 0x57u +#define PID_ORIGINAL_WRITER_INFO 0x61u +#define PID_ENDPOINT_GUID 0x5au + +/* Security related PID values. */ +#define PID_IDENTITY_TOKEN 0x1001u +#define PID_PERMISSIONS_TOKEN 0x1002u +#define PID_ENDPOINT_SECURITY_INFO 0x1004u +#define PID_PARTICIPANT_SECURITY_INFO 0x1005u +#define PID_IDENTITY_STATUS_TOKEN 0x1006u + +struct DDS_Security_Serializer { + unsigned char *buffer; + size_t size; + size_t offset; + size_t increment; + size_t marker; +}; + +struct DDS_Security_Deserializer { + const unsigned char *buffer; + const unsigned char *cursor; + size_t size; + size_t remain; +}; + + +static size_t +alignup_size ( + size_t x, + size_t a) +{ + size_t m = a-1; + return (x+m) & ~m; +} + +static size_t +alignup_ptr( + const unsigned char *ptr, + size_t a) +{ + size_t m = (a - 1); + size_t x = (size_t) ptr; + return ((x+m) & ~m) - x; +} + +DDS_Security_Serializer +DDS_Security_Serializer_new( + size_t size, + size_t increment) +{ + DDS_Security_Serializer serializer; + + serializer = ddsrt_malloc(sizeof(*serializer)); + serializer->buffer = ddsrt_malloc(size); + serializer->size = size; + serializer->increment = increment; + serializer->offset = 0; + + return serializer; +} + +void +DDS_Security_Serializer_free( + DDS_Security_Serializer ser) +{ + if (ser) { + ddsrt_free(ser->buffer); + ddsrt_free(ser); + } +} + +void +DDS_Security_Serializer_buffer( + DDS_Security_Serializer ser, + unsigned char **buffer, + size_t *size) +{ + assert(ser); + assert(buffer); + assert(size); + + *buffer = ser->buffer; + *size = ser->offset; + ser->buffer = NULL; +} + +static void +serbuffer_adjust_size( + DDS_Security_Serializer ser, + size_t needed) +{ + if (ser->size - ser->offset < needed) { + ser->buffer = ddsrt_realloc(ser->buffer, ser->size + needed + ser->increment); + ser->size += needed + ser->increment; + } +} + +static void +serbuffer_align( + DDS_Security_Serializer ser, + size_t alignment) +{ + size_t offset, i; + + offset = alignup_size(ser->offset, alignment); + serbuffer_adjust_size(ser, offset-ser->offset); + for (i = 0; i < offset - ser->offset; i++) { + ser->buffer[ser->offset+i] = 0; + } + ser->offset = offset; +} + +static void +DDS_Security_Serialize_mark_len( + DDS_Security_Serializer ser) +{ + serbuffer_align(ser, 2); + serbuffer_adjust_size(ser, 2); + ser->marker = ser->offset; + ser->offset += 2; +} + +static void +DDS_Security_Serialize_update_len( + DDS_Security_Serializer ser) +{ + unsigned short len; + + len = (unsigned short)(ser->offset - ser->marker - sizeof(len)); + *(unsigned short *)&(ser->buffer[ser->marker]) = ddsrt_toBE2u(len); +} + +static void +DDS_Security_Serialize_uint16( + DDS_Security_Serializer ser, + unsigned short value) +{ + serbuffer_align(ser, sizeof(value)); + serbuffer_adjust_size(ser, sizeof(value)); + + *(unsigned short *)&(ser->buffer[ser->offset]) = ddsrt_toBE2u(value); + ser->offset += sizeof(value); +} + +static void +DDS_Security_Serialize_uint32_t( + DDS_Security_Serializer ser, + uint32_t value) +{ + serbuffer_align(ser, sizeof(value)); + serbuffer_adjust_size(ser, sizeof(value)); + + *(uint32_t *)&(ser->buffer[ser->offset]) = ddsrt_toBE4u(value); + ser->offset += sizeof(value); +} + +static void +DDS_Security_Serialize_string( + DDS_Security_Serializer ser, + const char *str) +{ + size_t len = strlen(str) + 1; + + DDS_Security_Serialize_uint32_t(ser, (uint32_t)len); + serbuffer_adjust_size(ser, len); + + memcpy(&(ser->buffer[ser->offset]), str, len); + ser->offset += len; + serbuffer_align(ser, sizeof(uint32_t)); +} + +static void +DDS_Security_Serialize_Property( + DDS_Security_Serializer ser, + const DDS_Security_Property_t *property) +{ + DDS_Security_Serialize_string(ser, property->name); + DDS_Security_Serialize_string(ser, property->value); +} + +static void +DDS_Security_Serialize_OctetSeq( + DDS_Security_Serializer ser, + const DDS_Security_OctetSeq *seq) +{ + DDS_Security_Serialize_uint32_t(ser, seq->_length); + serbuffer_adjust_size(ser, seq->_length); + memcpy(&(ser->buffer[ser->offset]), seq->_buffer, seq->_length); + ser->offset += seq->_length; +} + +static void +DDS_Security_Serialize_BinaryProperty( + DDS_Security_Serializer ser, + const DDS_Security_BinaryProperty_t *property) +{ + DDS_Security_Serialize_string(ser, property->name); + DDS_Security_Serialize_OctetSeq(ser, &property->value); +} + +void +DDS_Security_Serialize_PropertySeq( + DDS_Security_Serializer ser, + const DDS_Security_PropertySeq *seq) +{ + uint32_t i; + + DDS_Security_Serialize_uint32_t(ser, seq->_length); + for (i = 0; i < seq->_length; i++) { + DDS_Security_Serialize_Property(ser, &seq->_buffer[i]); + } +} + +void +DDS_Security_Serialize_BinaryPropertyArray( + DDS_Security_Serializer serializer, + const DDS_Security_BinaryProperty_t **properties, + const uint32_t propertyLength) +{ + uint32_t i; + + DDS_Security_Serialize_uint32_t(serializer, propertyLength); + for (i = 0; i < propertyLength ; i++) { + DDS_Security_Serialize_BinaryProperty(serializer, properties[i]); + } +} + +void +DDS_Security_Serialize_BinaryPropertySeq( + DDS_Security_Serializer serializer, + const DDS_Security_BinaryPropertySeq *seq) +{ + uint32_t i; + + DDS_Security_Serialize_uint32_t(serializer, seq->_length); + for (i = 0; i < seq->_length; i++) { + DDS_Security_Serialize_BinaryProperty(serializer, &seq->_buffer[i]); + } +} + + +static void +DDS_Security_Serialize_DataHolder( + DDS_Security_Serializer ser, + const DDS_Security_DataHolder *holder) +{ + DDS_Security_Serialize_string(ser, holder->class_id); + DDS_Security_Serialize_PropertySeq(ser, &holder->properties); + DDS_Security_Serialize_BinaryPropertySeq(ser, &holder->binary_properties); +} + + +static void +DDS_Security_Serialize_BuiltinTopicKey( + DDS_Security_Serializer ser, + DDS_Security_BuiltinTopicKey_t key) +{ + serbuffer_align(ser, sizeof(uint32_t)); + DDS_Security_Serialize_uint16(ser, PID_PARTICIPANT_GUID); + DDS_Security_Serialize_uint16(ser, 16); + DDS_Security_Serialize_uint32_t(ser, key[0]); + DDS_Security_Serialize_uint32_t(ser, key[1]); + DDS_Security_Serialize_uint32_t(ser, key[2]); + /* 4 Bytes are expected for whatever reason (gid vs guid?). */ + DDS_Security_Serialize_uint32_t(ser, 0); +} + +static void +DDS_Security_Serialize_UserDataQosPolicy( + DDS_Security_Serializer ser, + DDS_Security_OctetSeq *seq) +{ + if (seq->_length > 0) { + serbuffer_align(ser, sizeof(uint32_t)); + DDS_Security_Serialize_uint16(ser, PID_USER_DATA); + DDS_Security_Serialize_uint16(ser, (unsigned short)seq->_length); + DDS_Security_Serialize_OctetSeq(ser, seq); + } +} + +static void +DDS_Security_Serialize_IdentityToken( + DDS_Security_Serializer ser, + DDS_Security_IdentityToken *token) +{ + serbuffer_align(ser, sizeof(uint32_t)); + DDS_Security_Serialize_uint16(ser, PID_IDENTITY_TOKEN); + DDS_Security_Serialize_mark_len(ser); + DDS_Security_Serialize_DataHolder(ser, token); + DDS_Security_Serialize_update_len(ser); +} + +static void +DDS_Security_Serialize_PermissionsToken( + DDS_Security_Serializer ser, + DDS_Security_PermissionsToken *token) +{ + serbuffer_align(ser, sizeof(uint32_t)); + DDS_Security_Serialize_uint16(ser, PID_PERMISSIONS_TOKEN); + DDS_Security_Serialize_mark_len(ser); + DDS_Security_Serialize_DataHolder(ser, token); + DDS_Security_Serialize_update_len(ser); +} + +static void +DDS_Security_Serialize_PropertyQosPolicy( + DDS_Security_Serializer ser, + DDS_Security_PropertyQosPolicy *policy) +{ + serbuffer_align(ser, sizeof(uint32_t)); + DDS_Security_Serialize_uint16(ser, PID_PROPERTY_LIST); + DDS_Security_Serialize_mark_len(ser); + DDS_Security_Serialize_PropertySeq(ser, &policy->value); + if (policy->binary_value._length > 0) + DDS_Security_Serialize_BinaryPropertySeq(ser, &policy->binary_value); + DDS_Security_Serialize_update_len(ser); +} + +static void +DDS_Security_Serialize_ParticipantSecurityInfo( + DDS_Security_Serializer ser, + DDS_Security_ParticipantSecurityInfo *info) +{ + serbuffer_align(ser, sizeof(uint32_t)); + DDS_Security_Serialize_uint16(ser, PID_PARTICIPANT_SECURITY_INFO); + DDS_Security_Serialize_uint16(ser, 8); + DDS_Security_Serialize_uint32_t(ser, info->participant_security_attributes); + DDS_Security_Serialize_uint32_t(ser, info->plugin_participant_security_attributes); +} + + +void +DDS_Security_Serialize_ParticipantBuiltinTopicData( + DDS_Security_Serializer ser, + DDS_Security_ParticipantBuiltinTopicData *pdata) +{ + DDS_Security_Serialize_BuiltinTopicKey(ser, pdata->key); + DDS_Security_Serialize_UserDataQosPolicy(ser, &pdata->user_data.value); + DDS_Security_Serialize_IdentityToken(ser, &pdata->identity_token); + DDS_Security_Serialize_PermissionsToken(ser, &pdata->permissions_token); + DDS_Security_Serialize_PropertyQosPolicy(ser, &pdata->property); + DDS_Security_Serialize_ParticipantSecurityInfo(ser, &pdata->security_info); + serbuffer_align(ser, sizeof(uint32_t)); + DDS_Security_Serialize_uint16(ser, PID_SENTINEL); + DDS_Security_Serialize_uint16(ser, 0); +} + +static void +DDS_Security_Serialize_OctetArray( + DDS_Security_Serializer ser, + const DDS_Security_octet *data, + uint32_t length) +{ + serbuffer_adjust_size(ser, length); + memcpy(&ser->buffer[ser->offset], data, length); + ser->offset += length; +} + +void +DDS_Security_Serialize_KeyMaterial_AES_GCM_GMAC( + DDS_Security_Serializer ser, + const DDS_Security_KeyMaterial_AES_GCM_GMAC *data) +{ + DDS_Security_Serialize_OctetArray(ser, data->transformation_kind, sizeof(data->transformation_kind)); + DDS_Security_Serialize_OctetSeq(ser, &data->master_salt); + DDS_Security_Serialize_OctetArray(ser, data->sender_key_id, sizeof(data->sender_key_id)); + DDS_Security_Serialize_OctetSeq(ser, &data->master_sender_key); + DDS_Security_Serialize_OctetArray(ser, data->receiver_specific_key_id, sizeof(data->receiver_specific_key_id)); + DDS_Security_Serialize_OctetSeq(ser, &data->master_receiver_specific_key); +} + + +DDS_Security_Deserializer +DDS_Security_Deserializer_new( + const unsigned char *data, + size_t size) +{ + DDS_Security_Deserializer deserializer; + + deserializer = ddsrt_malloc(sizeof(*deserializer)); + + deserializer->buffer = data; + deserializer->cursor = data; + deserializer->size = size; + deserializer->remain = size; + + return deserializer; +} + +void +DDS_Security_Deserializer_free( + DDS_Security_Deserializer dser) +{ + ddsrt_free(dser); +} + +static void +DDS_Security_Deserialize_align( + DDS_Security_Deserializer dser, + size_t size) +{ + size_t l = alignup_ptr(dser->cursor, size); + + if (dser->remain >= l) { + dser->cursor += l; + dser->remain -= l; + } else { + dser->remain = 0; + } +} + +static int +DDS_Security_Deserialize_uint16( + DDS_Security_Deserializer dser, + unsigned short *value) +{ + size_t l = sizeof(*value); + + DDS_Security_Deserialize_align(dser, l); + + if (dser->remain < l) { + return 0; + } + *value = ddsrt_fromBE2u(*(unsigned short *)dser->cursor); + dser->cursor += l; + dser->remain -= l; + + return 1; +} + +static int +DDS_Security_Deserialize_uint32_t( + DDS_Security_Deserializer dser, + uint32_t *value) +{ + size_t l = sizeof(*value); + + DDS_Security_Deserialize_align(dser, l); + + if (dser->remain < l) { + return 0; + } + *value = ddsrt_fromBE4u(*(uint32_t *)dser->cursor); + dser->cursor += l; + dser->remain -= l; + + return 1; +} + +static int +DDS_Security_Deserialize_string( + DDS_Security_Deserializer dser, + char **value) +{ + uint32_t len; + size_t sz; + + if (!DDS_Security_Deserialize_uint32_t(dser, &len)) { + return 0; + } + + sz = (size_t)len; + + if (dser->remain < sz) { + return 0; + } + + if (sz > 0 && (dser->cursor[sz-1] == 0)) { + *value = ddsrt_strdup((char *)dser->cursor); + /* Consider padding */ + sz = alignup_size(sz, sizeof(uint32_t)); + dser->cursor += sz; + dser->remain -= sz; + } else { + *value = ddsrt_strdup(""); + } + return 1; +} + +static int +DDS_Security_Deserialize_OctetArray( + DDS_Security_Deserializer dser, + unsigned char *arr, + uint32_t length) +{ + if (dser->remain < length) { + return 0; + } + memcpy(arr, dser->cursor, length); + dser->cursor += length; + dser->remain -= length; + + return 1; +} + +static int +DDS_Security_Deserialize_OctetSeq( + DDS_Security_Deserializer dser, + DDS_Security_OctetSeq *seq) +{ + if (!DDS_Security_Deserialize_uint32_t(dser, &seq->_length)) { + return 0; + } + + if (dser->remain < seq->_length) { + return 0; + } + + if (seq->_length > 0) { + /* Consider padding */ + size_t a_size = alignup_size(seq->_length, sizeof(uint32_t)); + seq->_buffer = ddsrt_malloc(seq->_length); + memcpy(seq->_buffer, dser->cursor, seq->_length); + dser->cursor += a_size; + dser->remain -= a_size; + } else { + seq->_buffer = NULL; + } + return 1; +} + +static int +DDS_Security_Deserialize_Property( + DDS_Security_Deserializer dser, + DDS_Security_Property_t *property) +{ + return DDS_Security_Deserialize_string(dser, &property->name) && + DDS_Security_Deserialize_string(dser, &property->value); +} + +static int +DDS_Security_Deserialize_BinaryProperty( + DDS_Security_Deserializer dser, + DDS_Security_BinaryProperty_t *property) +{ + return DDS_Security_Deserialize_string(dser, &property->name) && + DDS_Security_Deserialize_OctetSeq(dser, &property->value); +} + +static int +DDS_Security_Deserialize_PropertySeq( + DDS_Security_Deserializer dser, + DDS_Security_PropertySeq *seq) +{ + /* A well-formed CDR string is length + content including terminating 0, length is + 4 bytes and 4-byte aligned, so the minimum length for a non-empty property + sequence is 4+1+(3 pad)+4+1 = 13 bytes. Just use 8 because it is way faster + and just as good for checking that the length value isn't completely ridiculous. */ + const uint32_t minpropsize = (uint32_t) (2 * sizeof (uint32_t)); + int r = 1; + uint32_t i; + + if (!DDS_Security_Deserialize_uint32_t(dser, &seq->_length)) { + return 0; + } else if (seq->_length > dser->remain / minpropsize) { + seq->_length = 0; + return 0; + } else if (seq->_length > 0) { + seq->_buffer = DDS_Security_PropertySeq_allocbuf(seq->_length); + for (i = 0; i < seq->_length && r; i++) { + r = DDS_Security_Deserialize_Property(dser, &seq->_buffer[i]); + } + } + + return r; +} + +static int +DDS_Security_Deserialize_BinaryPropertySeq( + DDS_Security_Deserializer dser, + DDS_Security_BinaryPropertySeq *seq) +{ + /* A well-formed CDR string + a well-formed octet sequence: 4+1+(3 pad)+4 = 12 bytes. + Just use 8 because it is way faster and just as good for checking that the length + value isn't completely ridiculous. */ + const uint32_t minpropsize = (uint32_t) (2 * sizeof (uint32_t)); + int r = 1; + uint32_t i; + + if (!DDS_Security_Deserialize_uint32_t(dser, &seq->_length)) { + return 0; + } else if (seq->_length > dser->remain / minpropsize) { + seq->_length = 0; + return 0; + } else if (seq->_length > 0) { + seq->_buffer = DDS_Security_BinaryPropertySeq_allocbuf(seq->_length); + for (i = 0; i < seq->_length && r; i++) { + r = DDS_Security_Deserialize_BinaryProperty(dser, &seq->_buffer[i]); + } + } + + return r; +} + +static int +DDS_Security_Deserialize_DataHolder( + DDS_Security_Deserializer dser, + DDS_Security_DataHolder *holder) +{ + return DDS_Security_Deserialize_string(dser, &holder->class_id) && + DDS_Security_Deserialize_PropertySeq(dser, &holder->properties) && + DDS_Security_Deserialize_BinaryPropertySeq(dser, &holder->binary_properties); +} + + +static int +DDS_Security_Deserialize_PropertyQosPolicy( + DDS_Security_Deserializer dser, + DDS_Security_PropertyQosPolicy *policy, + size_t len) +{ + size_t sl = dser->remain; + + if (!DDS_Security_Deserialize_PropertySeq(dser, &policy->value)) + return 0; + + if (sl - dser->remain > len) + return DDS_Security_Deserialize_BinaryPropertySeq(dser, &policy->binary_value); + + return 1; +} + +static int +DDS_Security_Deserialize_BuiltinTopicKey( + DDS_Security_Deserializer dser, + DDS_Security_BuiltinTopicKey_t key) +{ + int r = DDS_Security_Deserialize_uint32_t(dser, (uint32_t *)&key[0]) && + DDS_Security_Deserialize_uint32_t(dser, (uint32_t *)&key[1]) && + DDS_Security_Deserialize_uint32_t(dser, (uint32_t *)&key[2]); + + /* guid is 16 bytes, so skip the last 4 bytes */ + dser->cursor += 4; + dser->remain -= 4; + + return r; +} + +static int +DDS_Security_Deserialize_ParticipantSecurityInfo( + DDS_Security_Deserializer dser, + DDS_Security_ParticipantSecurityInfo *info) +{ + return DDS_Security_Deserialize_uint32_t(dser, &info->participant_security_attributes) && + DDS_Security_Deserialize_uint32_t(dser, &info->plugin_participant_security_attributes); +} + +int +DDS_Security_Deserialize_ParticipantBuiltinTopicData( + DDS_Security_Deserializer dser, + DDS_Security_ParticipantBuiltinTopicData *pdata, + DDS_Security_SecurityException *ex) +{ + unsigned short len=0; + unsigned short pid=0; + int r, ready = 0; + + do { + DDS_Security_Deserialize_align(dser, 4); + r = DDS_Security_Deserialize_uint16(dser, &pid) && + DDS_Security_Deserialize_uint16(dser, &len); + + if (r && (len <= dser->remain)) { + const unsigned char *next_cursor = dser->cursor + len; + + switch (pid) { + case PID_PARTICIPANT_GUID: + r = DDS_Security_Deserialize_BuiltinTopicKey(dser, pdata->key); + break; + case PID_USER_DATA: + r = DDS_Security_Deserialize_OctetSeq(dser, &pdata->user_data.value); + break; + case PID_IDENTITY_TOKEN: + r = DDS_Security_Deserialize_DataHolder(dser, &pdata->identity_token); + break; + case PID_PERMISSIONS_TOKEN: + r = DDS_Security_Deserialize_DataHolder(dser, &pdata->permissions_token); + break; + case PID_PROPERTY_LIST: + r = DDS_Security_Deserialize_PropertyQosPolicy(dser, &pdata->property, len); + break; + case PID_PARTICIPANT_SECURITY_INFO: + r = DDS_Security_Deserialize_ParticipantSecurityInfo(dser, &pdata->security_info); + break; + case PID_SENTINEL: + ready = 1; + break; + default: + dser->cursor += len; + dser->remain -= len; + break; + } + + if (r) { + if (dser->cursor != next_cursor) { + DDS_Security_Exception_set(ex, "Deserialization", DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, + "Deserialize PID 0x%x failed: internal_size %d != external_size %d", pid, (int)len + (int)(dser->cursor - next_cursor), (int)len); + r = 0; + } + } else { + DDS_Security_Exception_set(ex, "Deserialization", DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, + "Deserialize PID 0x%x failed: parsing failed", pid); + } + } else { + if (!r) { + DDS_Security_Exception_set(ex, "Deserialization", DDS_SECURITY_ERR_UNDEFINED_CODE, DDS_SECURITY_VALIDATION_FAILED, + "Deserialize parameter header failed"); + } + } + } while (r && !ready && dser->remain > 0); + + return ready; +} + +void +DDS_Security_BuiltinTopicKeyBE( + DDS_Security_BuiltinTopicKey_t dst, + const DDS_Security_BuiltinTopicKey_t src) +{ + dst[0] = ddsrt_toBE4u(src[0]); + dst[1] = ddsrt_toBE4u(src[1]); + dst[2] = ddsrt_toBE4u(src[2]); +} + +int +DDS_Security_Deserialize_KeyMaterial_AES_GCM_GMAC( + DDS_Security_Deserializer dser, + DDS_Security_KeyMaterial_AES_GCM_GMAC *data) +{ + memset(data, 0, sizeof(*data)); + return + DDS_Security_Deserialize_OctetArray(dser, data->transformation_kind, sizeof(data->transformation_kind)) && + DDS_Security_Deserialize_OctetSeq(dser, &data->master_salt) && + DDS_Security_Deserialize_OctetArray(dser, data->sender_key_id, sizeof(data->sender_key_id)) && + DDS_Security_Deserialize_OctetSeq(dser, &data->master_sender_key) && + DDS_Security_Deserialize_OctetArray(dser, data->receiver_specific_key_id, sizeof(data->receiver_specific_key_id)) && + DDS_Security_Deserialize_OctetSeq(dser, &data->master_receiver_specific_key); +} diff --git a/src/security/core/src/dds_security_timed_cb.c b/src/security/core/src/dds_security_timed_cb.c new file mode 100644 index 0000000..a8bfb0e --- /dev/null +++ b/src/security/core/src/dds_security_timed_cb.c @@ -0,0 +1,329 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#include +#include +#include +#include + +#include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/log.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/threads.h" +#include "dds/ddsrt/time.h" +#include "dds/ddsrt/fibheap.h" + + +#include "dds/security/core/dds_security_timed_cb.h" + + +struct dds_security_timed_dispatcher_t +{ + bool active; + void *listener; + ddsrt_fibheap_t events; +}; + +struct list_dispatcher_t +{ + struct list_dispatcher_t *next; + struct dds_security_timed_dispatcher_t *dispatcher; +}; + +struct event_t +{ + ddsrt_fibheap_node_t heapnode; + dds_security_timed_cb_t callback; + dds_time_t trigger_time; + void *arg; +}; + +static int compare_timed_cb_trigger_time(const void *va, const void *vb); +static const ddsrt_fibheap_def_t timed_cb_queue_fhdef = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof(struct event_t, heapnode), compare_timed_cb_trigger_time); + +static int compare_timed_cb_trigger_time(const void *va, const void *vb) +{ + const struct event_t *a = va; + const struct event_t *b = vb; + return (a->trigger_time == b->trigger_time) ? 0 : (a->trigger_time < b->trigger_time) ? -1 : 1; +} + +struct dds_security_timed_cb_data { + ddsrt_mutex_t lock; + ddsrt_cond_t cond; + struct list_dispatcher_t *first_dispatcher_node; + ddsrt_thread_t thread; + bool terminate; +}; + + +static uint32_t timed_dispatcher_thread( + void *tcbv) +{ + struct list_dispatcher_t *dispatcher_node; + struct event_t *event; + dds_duration_t timeout; + dds_duration_t remain_time; + struct dds_security_timed_cb_data *tcb = (struct dds_security_timed_cb_data *)tcbv; + + ddsrt_mutex_lock(&tcb->lock); + do + { + remain_time = DDS_INFINITY; + for (dispatcher_node = tcb->first_dispatcher_node; dispatcher_node != NULL; dispatcher_node = dispatcher_node->next) + { + /* Just some sanity checks. */ + assert(dispatcher_node->dispatcher); + if (dispatcher_node->dispatcher->active) + { + do + { + timeout = DDS_INFINITY; + event = ddsrt_fibheap_min(&timed_cb_queue_fhdef, &dispatcher_node->dispatcher->events); + if (event) + { + /* Just some sanity checks. */ + assert(event->callback); + /* Determine the trigger timeout of this callback. */ + timeout = event->trigger_time - dds_time(); + if (timeout <= 0) + { + /* Trigger callback when related dispatcher is active. */ + event->callback(dispatcher_node->dispatcher, + DDS_SECURITY_TIMED_CB_KIND_TIMEOUT, + dispatcher_node->dispatcher->listener, + event->arg); + + /* Remove handled event from queue, continue with next. */ + ddsrt_fibheap_delete(&timed_cb_queue_fhdef, &dispatcher_node->dispatcher->events, event); + ddsrt_free(event); + } + else if (timeout < remain_time) + { + remain_time = timeout; + } + } + } + while (timeout < 0); + } + } + // tcb->cond condition may be triggered before this thread runs and causes + // this waitfor to wait infinity, hence the check of the tcb->terminate + if (((remain_time > 0) || (remain_time == DDS_INFINITY)) && !tcb->terminate) + { + /* Wait for new event, timeout or the end. */ + (void)ddsrt_cond_waitfor(&tcb->cond, &tcb->lock, remain_time); + } + + } while (!tcb->terminate); + + ddsrt_mutex_unlock(&tcb->lock); + + return 0; +} + +struct dds_security_timed_cb_data* +dds_security_timed_cb_new() +{ + struct dds_security_timed_cb_data *tcb = ddsrt_malloc(sizeof(*tcb)); + dds_return_t osres; + ddsrt_threadattr_t attr; + + ddsrt_mutex_init(&tcb->lock); + ddsrt_cond_init(&tcb->cond); + tcb->first_dispatcher_node = NULL; + tcb->terminate = false; + + ddsrt_threadattr_init(&attr); + osres = ddsrt_thread_create(&tcb->thread, "security_dispatcher", &attr, timed_dispatcher_thread, (void*)tcb); + if (osres != DDS_RETCODE_OK) + { + DDS_FATAL("Cannot create thread security_dispatcher"); + } + + return tcb; +} + +void +dds_security_timed_cb_free( + struct dds_security_timed_cb_data *tcb) +{ + ddsrt_mutex_lock(&tcb->lock); + tcb->terminate = true; + ddsrt_mutex_unlock(&tcb->lock); + ddsrt_cond_signal(&tcb->cond); + ddsrt_thread_join(tcb->thread, NULL); + + ddsrt_cond_destroy(&tcb->cond); + ddsrt_mutex_destroy(&tcb->lock); + ddsrt_free(tcb); +} + + +struct dds_security_timed_dispatcher_t* +dds_security_timed_dispatcher_new( + struct dds_security_timed_cb_data *tcb) +{ + struct dds_security_timed_dispatcher_t *d; + struct list_dispatcher_t *dispatcher_node_new; + struct list_dispatcher_t *dispatcher_node_wrk; + + /* New dispatcher. */ + d = ddsrt_malloc(sizeof(struct dds_security_timed_dispatcher_t)); + memset(d, 0, sizeof(struct dds_security_timed_dispatcher_t)); + + ddsrt_fibheap_init(&timed_cb_queue_fhdef, &d->events); + + dispatcher_node_new = ddsrt_malloc(sizeof(struct list_dispatcher_t)); + memset(dispatcher_node_new, 0, sizeof(struct list_dispatcher_t)); + dispatcher_node_new->dispatcher = d; + + ddsrt_mutex_lock(&tcb->lock); + + /* Append to list */ + if (tcb->first_dispatcher_node) { + struct list_dispatcher_t *last = NULL; + for (dispatcher_node_wrk = tcb->first_dispatcher_node; dispatcher_node_wrk != NULL; dispatcher_node_wrk = dispatcher_node_wrk->next) { + last = dispatcher_node_wrk; + } + last->next = dispatcher_node_new; + } else { + /* This new event is the first one. */ + tcb->first_dispatcher_node = dispatcher_node_new; + } + + ddsrt_mutex_unlock(&tcb->lock); + + + return d; +} + +void +dds_security_timed_dispatcher_free( + struct dds_security_timed_cb_data *tcb, + struct dds_security_timed_dispatcher_t *d) +{ + struct event_t *event; + struct list_dispatcher_t *dispatcher_node; + struct list_dispatcher_t *dispatcher_node_prev; + + assert(d); + + /* Remove related events from queue. */ + ddsrt_mutex_lock(&tcb->lock); + + while((event = ddsrt_fibheap_extract_min(&timed_cb_queue_fhdef, &d->events)) != NULL) + { + event->callback(d, DDS_SECURITY_TIMED_CB_KIND_DELETE, NULL, event->arg); + ddsrt_free(event); + } + + /* Remove dispatcher from list */ + dispatcher_node_prev = NULL; + for (dispatcher_node = tcb->first_dispatcher_node; dispatcher_node != NULL; dispatcher_node = dispatcher_node->next) + { + if (dispatcher_node->dispatcher == d) + { + /* remove element */ + if (dispatcher_node_prev != NULL) + { + dispatcher_node_prev->next = dispatcher_node->next; + } + else + { + tcb->first_dispatcher_node = dispatcher_node->next; + } + + ddsrt_free(dispatcher_node); + break; + } + dispatcher_node_prev = dispatcher_node; + } + /* Free this dispatcher. */ + ddsrt_free(d); + + ddsrt_mutex_unlock(&tcb->lock); + +} + + +void +dds_security_timed_dispatcher_enable( + struct dds_security_timed_cb_data *tcb, + struct dds_security_timed_dispatcher_t *d, + void *listener) +{ + assert(d); + assert(!(d->active)); + + ddsrt_mutex_lock(&tcb->lock); + + /* Remember possible listener and activate. */ + d->listener = listener; + d->active = true; + + /* Start thread when not running, otherwise wake it up to + * trigger callbacks that were (possibly) previously added. */ + ddsrt_cond_signal(&tcb->cond); + + ddsrt_mutex_unlock(&tcb->lock); +} + + +void +dds_security_timed_dispatcher_disable( + struct dds_security_timed_cb_data *tcb, + struct dds_security_timed_dispatcher_t *d) +{ + assert(d); + assert(d->active); + + ddsrt_mutex_lock(&tcb->lock); + + /* Forget listener and deactivate. */ + d->listener = NULL; + d->active = false; + + ddsrt_mutex_unlock(&tcb->lock); +} + + +void +dds_security_timed_dispatcher_add( + struct dds_security_timed_cb_data *tcb, + struct dds_security_timed_dispatcher_t *d, + dds_security_timed_cb_t cb, + dds_time_t trigger_time, + void *arg) +{ + struct event_t *event_new; + + assert(d); + assert(cb); + + /* Create event. */ + event_new = ddsrt_malloc(sizeof(struct event_t)); + memset(event_new, 0, sizeof(struct event_t)); + event_new->trigger_time = trigger_time; + event_new->callback = cb; + event_new->arg = arg; + + /* Insert event based on trigger_time. */ + ddsrt_mutex_lock(&tcb->lock); + ddsrt_fibheap_insert(&timed_cb_queue_fhdef, &d->events, event_new); + ddsrt_mutex_unlock(&tcb->lock); + + /* Wake up thread (if it's running). */ + ddsrt_cond_signal(&tcb->cond); +} + diff --git a/src/security/core/src/dds_security_utils.c b/src/security/core/src/dds_security_utils.c new file mode 100644 index 0000000..5bf7843 --- /dev/null +++ b/src/security/core/src/dds_security_utils.c @@ -0,0 +1,1258 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/misc.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/ddsrt/heap.h" + +DDS_Security_BinaryProperty_t * +DDS_Security_BinaryProperty_alloc (void) +{ + DDS_Security_BinaryProperty_t *property; + + property = ddsrt_malloc(sizeof(DDS_Security_BinaryProperty_t)); + memset(property, 0, sizeof(DDS_Security_BinaryProperty_t)); + return property; +} + +void +DDS_Security_BinaryProperty_deinit( + DDS_Security_BinaryProperty_t *p) +{ + if (!p) { + return; + } + + ddsrt_free(p->name); + memset (p->value._buffer, 0, p->value._length); /* because key material can be stored in binary property */ + ddsrt_free(p->value._buffer); +} + +void +DDS_Security_BinaryProperty_free( + DDS_Security_BinaryProperty_t *p) +{ + if (p) { + DDS_Security_BinaryProperty_deinit(p); + ddsrt_free(p); + } +} + +void +DDS_Security_BinaryProperty_copy( + DDS_Security_BinaryProperty_t *dst, + const DDS_Security_BinaryProperty_t *src) +{ + dst->name = src->name ? ddsrt_strdup(src->name) : NULL; + dst->propagate = src->propagate; + dst->value._length = src->value._length; + dst->value._maximum = src->value._maximum; + + if (src->value._buffer) { + dst->value._buffer = ddsrt_malloc(src->value._length); + memcpy(dst->value._buffer, src->value._buffer, src->value._length); + } else { + dst->value._buffer = NULL; + } +} + +bool +DDS_Security_BinaryProperty_equal( + const DDS_Security_BinaryProperty_t *pa, + const DDS_Security_BinaryProperty_t *pb) +{ + uint32_t i; + + if (pa->name && pb->name) { + if (strcmp(pa->name, pb->name) != 0) { + return false; + } + } else if (pa->name || pb->name) { + return false; + } + + if (pa->value._length != pb->value._length) { + return false; + } + + for (i = 0; i < pa->value._length; i++) { + if (pa->value._buffer && pb->value._buffer) { + if (memcmp(pa->value._buffer, pb->value._buffer, pa->value._length) != 0) { + return false; + } + } else { + return false; + } + } + + return true; +} + +void +DDS_Security_BinaryProperty_set_by_value( + DDS_Security_BinaryProperty_t *bp, + const char *name, + const unsigned char *data, + uint32_t length) +{ + assert(bp); + assert(name); + assert(data); + + 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); + } else { + bp->value._buffer = NULL; + } +} + +void +DDS_Security_BinaryProperty_set_by_string( + DDS_Security_BinaryProperty_t *bp, + const char *name, + const char *data) +{ + uint32_t length; + + assert(bp); + assert(name); + assert(data); + + length = (uint32_t) strlen(data) + 1; + DDS_Security_BinaryProperty_set_by_value(bp, name, (unsigned char *)data, length); +} + +void +DDS_Security_BinaryProperty_set_by_ref( + DDS_Security_BinaryProperty_t *bp, + const char *name, + unsigned char *data, + uint32_t length) +{ + assert(bp); + assert(name); + assert(data); + assert(length > 0); + + bp->name = ddsrt_strdup(name); + bp->value._length = length; + bp->value._maximum = length; + bp->value._buffer = data; + bp->propagate = true; +} + +DDS_Security_BinaryPropertySeq * +DDS_Security_BinaryPropertySeq_alloc (void) +{ + DDS_Security_BinaryPropertySeq *seq; + + seq = ddsrt_malloc(sizeof(DDS_Security_BinaryPropertySeq)); + memset(seq, 0, sizeof(DDS_Security_BinaryPropertySeq)); + return seq; +} + +DDS_Security_BinaryProperty_t * +DDS_Security_BinaryPropertySeq_allocbuf ( + DDS_Security_unsigned_long len) +{ + DDS_Security_BinaryProperty_t *buffer; + + buffer = ddsrt_malloc(len * sizeof(DDS_Security_BinaryProperty_t)); + memset(buffer, 0, len * sizeof(DDS_Security_BinaryProperty_t)); + return buffer; +} + +void +DDS_Security_BinaryPropertySeq_deinit( + DDS_Security_BinaryPropertySeq *seq) +{ + uint32_t i; + + if (!seq) { + return; + } + for (i = 0; i < seq->_length; i++) { + ddsrt_free(seq->_buffer[i].name); + DDS_Security_OctetSeq_deinit(&seq->_buffer[i].value); + } +} + +void +DDS_Security_BinaryPropertySeq_free( + DDS_Security_BinaryPropertySeq *seq) +{ + DDS_Security_BinaryPropertySeq_deinit(seq); + ddsrt_free(seq); +} + + +DDS_Security_Property_t * +DDS_Security_Property_alloc (void) +{ + DDS_Security_Property_t *property; + + property = ddsrt_malloc(sizeof(DDS_Security_Property_t)); + memset(property, 0, sizeof(DDS_Security_Property_t)); + return property; +} + +void +DDS_Security_Property_free( + DDS_Security_Property_t *p) +{ + if (p) { + DDS_Security_Property_deinit(p); + ddsrt_free(p); + } +} + +void +DDS_Security_Property_deinit( + DDS_Security_Property_t *p) +{ + if (!p) { + return; + } + + ddsrt_free(p->name); + ddsrt_free(p->value); +} + +void +DDS_Security_Property_copy( + DDS_Security_Property_t *dst, + const DDS_Security_Property_t *src) +{ + dst->name = src->name ? ddsrt_strdup(src->name) : NULL; + dst->value = src->value ? ddsrt_strdup(src->value) : NULL; + dst->propagate = src->propagate; +} + +bool +DDS_Security_Property_equal( + const DDS_Security_Property_t *pa, + const DDS_Security_Property_t *pb) +{ + if (pa->name && pb->name) { + if (strcmp(pa->name, pb->name) != 0) { + return false; + } + } else if (pa->name || pb->name) { + return false; + } + + if (pa->value && pb->value) { + if (strcmp(pa->value, pb->value) != 0) { + return false; + } + } else if (pa->value || pb->value) { + return false; + } + + return true; +} + +char * +DDS_Security_Property_get_value( + const DDS_Security_PropertySeq *properties, + const char *name) +{ + uint32_t i; + char *value = NULL; + + assert(properties); + assert(name); + + for (i = 0; !value && (i < properties->_length); i++) { + if (properties->_buffer[i].name && + (strcmp(name, properties->_buffer[i].name) == 0)) { + if (properties->_buffer[i].value) { + value = ddsrt_strdup(properties->_buffer[i].value); + } + } + } + + return value; +} + +DDS_Security_PropertySeq * +DDS_Security_PropertySeq_alloc (void) +{ + DDS_Security_PropertySeq *seq; + + seq = ddsrt_malloc(sizeof(DDS_Security_PropertySeq)); + memset(seq, 0, sizeof(DDS_Security_PropertySeq)); + return seq; +} + +DDS_Security_Property_t * +DDS_Security_PropertySeq_allocbuf ( + DDS_Security_unsigned_long len) +{ + DDS_Security_Property_t *buffer; + + buffer = ddsrt_malloc(len * sizeof(DDS_Security_Property_t)); + memset(buffer, 0, len * sizeof(DDS_Security_Property_t)); + + return buffer; +} + +void +DDS_Security_PropertySeq_freebuf( + DDS_Security_PropertySeq *seq) +{ + uint32_t i; + + if (seq) { + for (i = 0; i < seq->_length; i++) { + ddsrt_free(seq->_buffer[i].name); + ddsrt_free(seq->_buffer[i].value); + } + ddsrt_free(seq->_buffer); + seq->_length = 0; + seq->_maximum = 0; + seq->_buffer = NULL; + } +} + +void +DDS_Security_PropertySeq_free( + DDS_Security_PropertySeq *seq) +{ + DDS_Security_PropertySeq_deinit(seq); + ddsrt_free(seq); +} + +void +DDS_Security_PropertySeq_deinit( + DDS_Security_PropertySeq *seq) +{ + uint32_t i; + + if (!seq) { + return; + } + for (i = 0; i < seq->_length; i++) { + ddsrt_free(seq->_buffer[i].name); + ddsrt_free(seq->_buffer[i].value); + } + ddsrt_free(seq->_buffer); +} + +const DDS_Security_Property_t * +DDS_Security_PropertySeq_find_property ( + const DDS_Security_PropertySeq *property_seq, + const char *name ) +{ + + DDS_Security_Property_t *result = NULL; + unsigned i, len; + + assert(property_seq); + assert(name); + + len = (unsigned)strlen(name); + for (i = 0; !result && (i < property_seq->_length); i++) { + if (property_seq->_buffer[i].name && + (strncmp(name, property_seq->_buffer[i].name, len+ 1) == 0)) { + result = &property_seq->_buffer[i]; + } + } + + return result; +} + +DDS_Security_DataHolder * +DDS_Security_DataHolder_alloc(void) +{ + DDS_Security_DataHolder *holder; + holder = ddsrt_malloc(sizeof(*holder)); + memset(holder, 0, sizeof(*holder)); + return holder; +} + +void +DDS_Security_DataHolder_free( + DDS_Security_DataHolder *holder) +{ + if (!holder) { + return; + } + DDS_Security_DataHolder_deinit(holder); + ddsrt_free(holder); +} + +void +DDS_Security_DataHolder_deinit( + DDS_Security_DataHolder *holder) +{ + uint32_t i; + + if (!holder) { + return; + } + + ddsrt_free(holder->class_id); + + for (i = 0; i < holder->properties._length; i++) { + DDS_Security_Property_deinit(&holder->properties._buffer[i]); + } + ddsrt_free(holder->properties._buffer); + + for (i = 0; i < holder->binary_properties._length; i++) { + DDS_Security_BinaryProperty_deinit(&holder->binary_properties._buffer[i]); + } + ddsrt_free(holder->binary_properties._buffer); + + memset(holder, 0, sizeof(*holder)); +} + +void +DDS_Security_DataHolder_copy( + DDS_Security_DataHolder *dst, + const DDS_Security_DataHolder *src) +{ + uint32_t i; + + assert(dst); + assert(src); + + if (src->class_id) { + dst->class_id = ddsrt_strdup(src->class_id); + } else { + dst->class_id = NULL; + } + + dst->properties = src->properties; + if (src->properties._buffer) { + dst->properties._buffer = DDS_Security_PropertySeq_allocbuf(src->properties._length); + for (i = 0; i < src->properties._length; i++) { + DDS_Security_Property_copy(&dst->properties._buffer[i], &src->properties._buffer[i]); + } + } + + dst->binary_properties = src->binary_properties; + if (src->binary_properties._buffer) { + dst->binary_properties._buffer = DDS_Security_BinaryPropertySeq_allocbuf(src->binary_properties._length); + for (i = 0; i < src->binary_properties._length; i++) { + DDS_Security_BinaryProperty_copy(&dst->binary_properties._buffer[i], &src->binary_properties._buffer[i]); + } + } +} + +bool +DDS_Security_DataHolder_equal( + const DDS_Security_DataHolder *psa, + const DDS_Security_DataHolder *psb) +{ + uint32_t i; + + if (psa->class_id && psb->class_id) { + if (strcmp(psa->class_id, psb->class_id) != 0) { + return false; + } + } else if (psa->class_id || psb->class_id) { + return false; + } + + for (i = 0; i < psa->properties._length; i++) { + if (!DDS_Security_Property_equal(&psa->properties._buffer[i], &psb->properties._buffer[i])) { + return false; + } + } + + for (i = 0; i < psa->binary_properties._length; i++) { + if (!DDS_Security_BinaryProperty_equal(&psa->binary_properties._buffer[i], &psb->binary_properties._buffer[i])) { + return false; + } + } + + return true; +} + + +const DDS_Security_Property_t * +DDS_Security_DataHolder_find_property( + const DDS_Security_DataHolder *holder, + const char *name) +{ + + assert(holder); + assert(name); + + return DDS_Security_PropertySeq_find_property ( &(holder->properties), name ); +} + +const DDS_Security_BinaryProperty_t * +DDS_Security_DataHolder_find_binary_property( + const DDS_Security_DataHolder *holder, + const char *name) +{ + DDS_Security_BinaryProperty_t *result = NULL; + unsigned i, len; + + assert(holder); + assert(name); + + len = (unsigned)strlen(name); + + for (i = 0; !result && (i < holder->binary_properties._length); i++) { + if (holder->binary_properties._buffer[i].name && + (strncmp(name, holder->binary_properties._buffer[i].name, len+1) == 0)) { + result = &holder->binary_properties._buffer[i]; + } + } + + return result; +} + +DDS_Security_DataHolderSeq * +DDS_Security_DataHolderSeq_alloc (void) +{ + DDS_Security_DataHolderSeq *holder; + + holder = ddsrt_malloc(sizeof(DDS_Security_DataHolderSeq)); + memset(holder, 0, sizeof(DDS_Security_DataHolderSeq)); + return holder; +} + +DDS_Security_DataHolder * +DDS_Security_DataHolderSeq_allocbuf ( + DDS_Security_unsigned_long len) +{ + DDS_Security_DataHolder *buffer; + + buffer = ddsrt_malloc(len * sizeof(DDS_Security_DataHolder)); + memset(buffer, 0, len * sizeof(DDS_Security_DataHolder)); + return buffer; +} + +void +DDS_Security_DataHolderSeq_freebuf( + DDS_Security_DataHolderSeq *seq) +{ + uint32_t i; + + if (seq) { + for (i = 0; i < seq->_length; i++) { + DDS_Security_DataHolder_deinit(&seq->_buffer[i]); + } + ddsrt_free(seq->_buffer); + seq->_buffer = NULL; + seq->_length = 0; + seq->_maximum = 0; + } +} + +void +DDS_Security_DataHolderSeq_free( + DDS_Security_DataHolderSeq *seq) +{ + if (seq) { + DDS_Security_DataHolderSeq_freebuf(seq); + ddsrt_free(seq); + } +} + +void +DDS_Security_DataHolderSeq_deinit( + DDS_Security_DataHolderSeq *seq) +{ + if (seq) { + DDS_Security_DataHolderSeq_freebuf(seq); + } +} + +void +DDS_Security_DataHolderSeq_copy( + DDS_Security_DataHolderSeq *dst, + const DDS_Security_DataHolderSeq *src) +{ + uint32_t i; + + assert(dst); + assert(src); + + *dst = *src; + + if (src->_length) { + dst->_buffer = DDS_Security_DataHolderSeq_allocbuf(src->_length); + } + + for (i = 0; i < src->_length; i++) { + DDS_Security_DataHolder_copy(&dst->_buffer[i], &src->_buffer[i]); + } +} + +DDS_Security_ParticipantBuiltinTopicData * +DDS_Security_ParticipantBuiltinTopicData_alloc(void) +{ + DDS_Security_ParticipantBuiltinTopicData *result; + + result = ddsrt_malloc(sizeof(*result)); + memset(result, 0, sizeof(*result)); + + return result; +} + +void +DDS_Security_ParticipantBuiltinTopicData_free( + DDS_Security_ParticipantBuiltinTopicData *data) +{ + DDS_Security_ParticipantBuiltinTopicData_deinit(data); + ddsrt_free(data); +} + +void +DDS_Security_ParticipantBuiltinTopicData_deinit( + DDS_Security_ParticipantBuiltinTopicData *data) +{ + if (!data) { + return; + } + DDS_Security_DataHolder_deinit(&data->identity_token); + DDS_Security_DataHolder_deinit(&data->permissions_token); + DDS_Security_PropertyQosPolicy_deinit(&data->property); + DDS_Security_OctetSeq_deinit(&data->user_data.value); +} + +DDS_Security_OctetSeq * +DDS_Security_OctetSeq_alloc (void) +{ + return (DDS_Security_OctetSeq *)ddsrt_malloc(sizeof(DDS_Security_OctetSeq )); +} + +DDS_Security_octet * +DDS_Security_OctetSeq_allocbuf ( + DDS_Security_unsigned_long len) +{ + return (DDS_Security_octet*)ddsrt_malloc(sizeof(DDS_Security_octet)*len); +} + +void +DDS_Security_OctetSeq_freebuf( + DDS_Security_OctetSeq *seq) +{ + if (!seq) { + return; + } + ddsrt_free(seq->_buffer); + seq->_buffer = NULL; + seq->_length = 0; + seq->_maximum = 0; +} + +void +DDS_Security_OctetSeq_free( + DDS_Security_OctetSeq *seq) +{ + DDS_Security_OctetSeq_deinit(seq); + ddsrt_free(seq); +} + +void +DDS_Security_OctetSeq_deinit( + DDS_Security_OctetSeq *seq) +{ + DDS_Security_OctetSeq_freebuf(seq); +} + + +void +DDS_Security_OctetSeq_copy( + DDS_Security_OctetSeq *dst, + const DDS_Security_OctetSeq *src) +{ + if (dst->_length > 0) { + DDS_Security_OctetSeq_deinit(dst); + } + dst->_length = src->_length; + dst->_maximum = src->_maximum; + + if (src->_length) { + dst->_buffer = ddsrt_malloc(src->_length); + memcpy(dst->_buffer, src->_buffer, src->_length); + } else { + dst->_buffer = NULL; + } +} + +DDS_Security_HandleSeq * +DDS_Security_HandleSeq_alloc(void) +{ + DDS_Security_HandleSeq *seq; + + seq = ddsrt_malloc(sizeof(*seq)); + seq->_buffer = NULL; + seq->_length = 0; + seq->_maximum = 0; + + return seq; +} + +DDS_Security_long_long * +DDS_Security_HandleSeq_allocbuf( + DDS_Security_unsigned_long length) +{ + DDS_Security_long_long *buffer; + buffer = ddsrt_malloc(length * sizeof(DDS_Security_long_long)); + memset(buffer, 0, length * sizeof(DDS_Security_long_long)); + return buffer; +} + +void +DDS_Security_HandleSeq_freebuf( + DDS_Security_HandleSeq *seq) +{ + if (!seq) { + return; + } + ddsrt_free(seq->_buffer); + seq->_maximum = 0; + seq->_length = 0; +} + +void +DDS_Security_HandleSeq_free( + DDS_Security_HandleSeq *seq) +{ + if (!seq) { + return; + } + DDS_Security_HandleSeq_freebuf(seq); + ddsrt_free(seq); +} + +void +DDS_Security_HandleSeq_deinit( + DDS_Security_HandleSeq *seq) +{ + if (!seq) { + return; + } + DDS_Security_HandleSeq_freebuf(seq); +} + +void DDS_Security_Exception_vset (DDS_Security_SecurityException *ex, const char *context, int code, int minor_code, const char *fmt, va_list args1) +{ + int32_t ret; + size_t len; + char buf[1] = { '\0' }; + char *str = NULL; + va_list args2; + + assert(context); + assert(fmt); + assert(ex); + DDSRT_UNUSED_ARG( context ); + + va_copy(args2, args1); + + if ((ret = vsnprintf(buf, sizeof(buf), fmt, args1)) >= 0) { + len = (size_t)ret; /* +1 for null byte */ + if ((str = ddsrt_malloc(len + 1)) == NULL) { + assert(false); + } else if ((ret = vsnprintf(str, len + 1, fmt, args2)) >= 0) { + assert((size_t) ret == len); + } else { + ddsrt_free(str); + str = NULL; + } + } + + va_end(args1); + + ex->message = str; + ex->code = code; + ex->minor_code = minor_code; +} + +void DDS_Security_Exception_set (DDS_Security_SecurityException *ex, const char *context, int code, int minor_code, const char *fmt, ...) +{ + va_list args1; + assert(context); + assert(fmt); + assert(ex); + va_start(args1, fmt); + DDS_Security_Exception_vset (ex, context, code, minor_code, fmt, args1); + va_end(args1); +} + +void +DDS_Security_Exception_reset( + DDS_Security_SecurityException *ex) +{ + if (ex) { + if (ex->message) { + ddsrt_free(ex->message); + } + DDS_Security_Exception_clean(ex); + } +} + +void +DDS_Security_Exception_clean( + DDS_Security_SecurityException *ex) +{ + if (ex) { + ex->code = 0; + ex->minor_code = 0; + ex->message = NULL; + } +} + +void +DDS_Security_PropertyQosPolicy_deinit( + DDS_Security_PropertyQosPolicy *policy) +{ + if (!policy) { + return; + } + DDS_Security_PropertySeq_deinit(&policy->value); + DDS_Security_BinaryPropertySeq_deinit(&policy->binary_value); +} + +void +DDS_Security_PropertyQosPolicy_free( + DDS_Security_PropertyQosPolicy *policy) +{ + DDS_Security_PropertyQosPolicy_deinit(policy); + ddsrt_free(policy); +} + + +void +DDS_Security_set_token_nil( + DDS_Security_DataHolder *token) +{ + DDS_Security_DataHolder_deinit(token); + memset(token, 0, sizeof(*token)); + token->class_id = ddsrt_strdup(""); +} + +void +DDS_Security_KeyMaterial_AES_GCM_GMAC_deinit( + DDS_Security_KeyMaterial_AES_GCM_GMAC *key_material) +{ + if (key_material) { + if (key_material->master_receiver_specific_key._buffer != NULL) { + memset (key_material->master_receiver_specific_key._buffer, 0, key_material->master_receiver_specific_key._length); + ddsrt_free(key_material->master_receiver_specific_key._buffer); + } + if( key_material->master_salt._buffer != NULL){ + memset (key_material->master_salt._buffer, 0, key_material->master_salt._length); + ddsrt_free(key_material->master_salt._buffer); + } + if( key_material->master_sender_key._buffer != NULL){ + memset (key_material->master_sender_key._buffer, 0, key_material->master_sender_key._length); + ddsrt_free(key_material->master_sender_key._buffer); + } + } +} + +static uint32_t DDS_Security_getKeySize (const DDS_Security_PropertySeq *properties) +{ + const DDS_Security_Property_t *key_size_property; + if (properties != NULL) + { + key_size_property = DDS_Security_PropertySeq_find_property (properties, "dds.sec.crypto.keysize"); + if (key_size_property != NULL && !strcmp(key_size_property->value, "128")) + return 128; + } + return 256; +} + +DDS_Security_CryptoTransformKind_Enum +DDS_Security_basicprotectionkind2transformationkind( + const DDS_Security_PropertySeq *properties, + DDS_Security_BasicProtectionKind protection) +{ + uint32_t keysize = DDS_Security_getKeySize (properties); + switch (protection) { + case DDS_SECURITY_BASICPROTECTION_KIND_NONE: + return CRYPTO_TRANSFORMATION_KIND_NONE; + case DDS_SECURITY_BASICPROTECTION_KIND_SIGN: + return (keysize == 128) ? CRYPTO_TRANSFORMATION_KIND_AES128_GMAC : CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; + case DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT: + return (keysize == 128) ? CRYPTO_TRANSFORMATION_KIND_AES128_GCM : CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + default: + return CRYPTO_TRANSFORMATION_KIND_INVALID; + } +} + +DDS_Security_CryptoTransformKind_Enum +DDS_Security_protectionkind2transformationkind( + const DDS_Security_PropertySeq *properties, + DDS_Security_ProtectionKind protection) +{ + uint32_t keysize = DDS_Security_getKeySize (properties); + switch (protection) { + case DDS_SECURITY_PROTECTION_KIND_NONE: + return CRYPTO_TRANSFORMATION_KIND_NONE; + case DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION: + case DDS_SECURITY_PROTECTION_KIND_SIGN: + return (keysize == 128) ? CRYPTO_TRANSFORMATION_KIND_AES128_GMAC : CRYPTO_TRANSFORMATION_KIND_AES256_GMAC; + case DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION: + case DDS_SECURITY_PROTECTION_KIND_ENCRYPT: + return (keysize == 128) ? CRYPTO_TRANSFORMATION_KIND_AES128_GCM : CRYPTO_TRANSFORMATION_KIND_AES256_GCM; + default: + return CRYPTO_TRANSFORMATION_KIND_INVALID; + } +} + +#ifndef NDEBUG +void +print_binary_debug( + char* name, + unsigned char *value, + uint32_t size) +{ + uint32_t i; + printf("%s: ",name ); + for( i=0; i< size; i++) + { + printf("%x",value[i]); + } + printf("\n"); +} + +void +print_binary_properties_debug( + const DDS_Security_DataHolder *token) +{ + uint32_t i; + for (i = 0; i < token->binary_properties._length ; i++) { + print_binary_debug( token->binary_properties._buffer[i].name, token->binary_properties._buffer[i].value._buffer, token->binary_properties._buffer[i].value._length); + } + +} +#endif + + +DDS_Security_config_item_prefix_t +DDS_Security_get_conf_item_type( + const char *str, + char **data) +{ + DDS_Security_config_item_prefix_t kind = DDS_SECURITY_CONFIG_ITEM_PREFIX_UNKNOWN; + const char *CONFIG_FILE_PREFIX = "file:"; + const char *CONFIG_DATA_PREFIX = "data:,"; + const char *CONFIG_PKCS11_PREFIX = "pkcs11:"; + size_t CONFIG_FILE_PREFIX_LEN = strlen(CONFIG_FILE_PREFIX); + size_t CONFIG_DATA_PREFIX_LEN = strlen(CONFIG_DATA_PREFIX); + size_t CONFIG_PKCS11_PREFIX_LEN = strlen(CONFIG_PKCS11_PREFIX); + char *ptr; + + assert(str); + assert(data); + DDSRT_UNUSED_ARG(str); + + ptr = ddssec_strchrs(str, " \t", false); + + if (strncmp(ptr, CONFIG_FILE_PREFIX, CONFIG_FILE_PREFIX_LEN) == 0) { + const char *DOUBLE_SLASH = "//"; + size_t DOUBLE_SLASH_LEN = 2; + if (strncmp(&(ptr[CONFIG_FILE_PREFIX_LEN]), DOUBLE_SLASH, DOUBLE_SLASH_LEN) == 0) { + *data = ddsrt_strdup(&(ptr[CONFIG_FILE_PREFIX_LEN + DOUBLE_SLASH_LEN])); + } else { + *data = ddsrt_strdup(&(ptr[CONFIG_FILE_PREFIX_LEN])); + } + kind = DDS_SECURITY_CONFIG_ITEM_PREFIX_FILE; + } else if (strncmp(ptr, CONFIG_DATA_PREFIX, CONFIG_DATA_PREFIX_LEN) == 0) { + kind = DDS_SECURITY_CONFIG_ITEM_PREFIX_DATA; + *data = ddsrt_strdup(&(ptr[CONFIG_DATA_PREFIX_LEN])); + } else if (strncmp(ptr, CONFIG_PKCS11_PREFIX, CONFIG_PKCS11_PREFIX_LEN) == 0) { + kind = DDS_SECURITY_CONFIG_ITEM_PREFIX_PKCS11; + *data = ddsrt_strdup(&(ptr[CONFIG_PKCS11_PREFIX_LEN])); + } + + return kind; +} + + +char * +ddssec_strchrs ( + const char *str, + const char *chrs, + bool inc) +{ + bool eq; + char *ptr = NULL; + size_t i, j; + + assert (str != NULL); + assert (chrs != NULL); + + for (i = 0; str[i] != '\0' && ptr == NULL; i++) { + for (j = 0, eq = false; chrs[j] != '\0' && eq == false; j++) { + if (str[i] == chrs[j]) { + eq = true; + } + } + if (eq == inc) { + ptr = (char *)str + i; + } + } + + return ptr; +} + + +/* The result of os_fileNormalize should be freed with os_free */ +char * +DDS_Security_normalize_file( + const char *filepath) +{ + char *norm; + const char *fpPtr; + char *normPtr; +#if _WIN32 + #define __FILESEPCHAR '\\' +#else + #define __FILESEPCHAR '/' +#endif + norm = NULL; + if ((filepath != NULL) && (*filepath != '\0')) { + norm = ddsrt_malloc(strlen(filepath) + 1); + /* replace any / or \ by OS_FILESEPCHAR */ + fpPtr = (char *) filepath; + normPtr = norm; + while (*fpPtr != '\0') { + *normPtr = *fpPtr; + if ((*fpPtr == '/') || (*fpPtr == '\\')) { + *normPtr = __FILESEPCHAR; + normPtr++; + } else { + if (*fpPtr != '\"') { + normPtr++; + } + } + fpPtr++; + } + *normPtr = '\0'; + } +#undef __FILESEPCHAR + return norm; +} + +/** + * Parses an XML date string and returns this as a dds_time_t value. As leap seconds are not permitted + * in the XML date format (as stated in the XML Schema specification), this parser function does not + * accept leap seconds in its input string. This complies with the dds_time_t representation on posix, + * which is a unix timestamp (that also ignores leap seconds). + * + * As a dds_time_t is expressed as nanoseconds, the fractional seconds part of the input string will + * be rounded in case the fractional part has more than 9 digits. + */ +dds_time_t +DDS_Security_parse_xml_date( + char *buf) +{ + int32_t year = -1; + int32_t month = -1; + int32_t day = -1; + int32_t hour = -1; + int32_t minute = -1; + int32_t second = -1; + int32_t hour_offset = -1; + int32_t minute_offset = -1; + + int64_t frac_ns = 0; + + size_t cnt = 0; + size_t cnt_frac_sec = 0; + + assert(buf != NULL); + + /* Make an integrity check of the string before the conversion*/ + while (buf[cnt] != '\0') + { + if (cnt == 4 || cnt == 7) + { + if (buf[cnt] != '-') + return DDS_TIME_INVALID; + } + else if (cnt == 10) + { + if (buf[cnt] != 'T') + return DDS_TIME_INVALID; + } + else if (cnt == 13 || cnt == 16) + { + if (buf[cnt] != ':') + return DDS_TIME_INVALID; + } + else if (cnt == 19) + { + if (buf[cnt] != 'Z' && buf[cnt] != '+' && buf[cnt] != '-' && buf[cnt] != '.') + return DDS_TIME_INVALID; + + /* If a dot is found then a variable number of fractional seconds is present. + A second integrity loop to account for the variability is used */ + if (buf[cnt] == '.' && !cnt_frac_sec) + { + cnt_frac_sec = 1; + while (buf[cnt + 1] != '\0' && buf[cnt + 1] >= '0' && buf[cnt + 1] <= '9') + { + cnt_frac_sec++; + cnt++; + } + } + } + else if (cnt == 19 + cnt_frac_sec) + { + if (buf[cnt] != 'Z' && buf[cnt] != '+' && buf[cnt] != '-') + return DDS_TIME_INVALID; + } + else if (cnt == 22 + cnt_frac_sec) + { + if (buf[cnt] != ':') + return DDS_TIME_INVALID; + } + else + { + if (buf[cnt] < '0' || buf[cnt] > '9') + return DDS_TIME_INVALID; + } + cnt++; + } + + /* Do not allow more than 12 (13 including the dot) and less than 1 fractional second digits if they are used */ + if (cnt_frac_sec && (cnt_frac_sec < 2 || cnt_frac_sec > 13)) + return DDS_TIME_INVALID; + + /* Valid string length value at this stage are 19, 20 and 25 plus the fractional seconds part */ + if (cnt != 19 + cnt_frac_sec && cnt != 20 + cnt_frac_sec && cnt != 25 + cnt_frac_sec) + return DDS_TIME_INVALID; + + year = ddsrt_todigit(buf[0]) * 1000 + ddsrt_todigit(buf[1]) * 100 + ddsrt_todigit(buf[2]) * 10 + ddsrt_todigit(buf[3]); + month = ddsrt_todigit(buf[5]) * 10 + ddsrt_todigit(buf[6]); + day = ddsrt_todigit(buf[8]) * 10 + ddsrt_todigit(buf[9]); + + hour = ddsrt_todigit(buf[11]) * 10 + ddsrt_todigit(buf[12]); + minute = ddsrt_todigit(buf[14]) * 10 + ddsrt_todigit(buf[15]); + second = ddsrt_todigit(buf[17]) * 10 + ddsrt_todigit(buf[18]); + + { + int64_t frac_ns_pow = DDS_NSECS_IN_SEC / 10; + size_t n = 0; + for (n = 0; cnt_frac_sec && n < cnt_frac_sec - 1; n++) + { + /* Maximum granularity is nanosecond so round to maximum 9 digits */ + if (n == 9) + { + if (ddsrt_todigit(buf[20 + n]) >= 5) + frac_ns++; + break; + } + frac_ns += ddsrt_todigit(buf[20 + n]) * frac_ns_pow; + frac_ns_pow = frac_ns_pow / 10; + } + } + + /* If the length is 20 the last character must be a Z representing UTC time zone */ + if (cnt == 19 + cnt_frac_sec || (cnt == 20 + cnt_frac_sec && buf[19 + cnt_frac_sec] == 'Z')) + { + hour_offset = 0; + minute_offset = 0; + } + else if (cnt == 25 + cnt_frac_sec) + { + hour_offset = ddsrt_todigit(buf[20 + cnt_frac_sec]) * 10 + ddsrt_todigit(buf[21 + cnt_frac_sec]); + minute_offset = ddsrt_todigit(buf[23 + cnt_frac_sec]) * 10 + ddsrt_todigit(buf[24 + cnt_frac_sec]); + } + else + return DDS_TIME_INVALID; + + /* Make a limit check to make sure that all the numbers are within absolute boundaries. + Note that leap seconds are not allowed in XML dates and therefore not supported. */ + if (year < 1970 || year > 2262 || month < 1 || month > 12 || day < 1 || day > 31 || + hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59 || + ((hour_offset < 0 || hour_offset > 11 || minute_offset < 0 || minute_offset > 59) && (hour_offset != 12 || minute_offset != 0))) + { + return DDS_TIME_INVALID; + } + + /* Boundary check including consideration for month and leap years */ + if (!(((month == 4 || month == 6 || month == 9 || month == 11) && (day >= 1 && day <= 30)) || + ((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && (day >= 1 && day <= 31)) || + (month == 2 && ((year % 100 != 0 && year % 4 == 0) || (year % 400 == 0)) && (day >= 1 && day <= 29)) || + (month == 2 && (day >= 1 && day <= 28)))) + { + return DDS_TIME_INVALID; + } + + /* Convert the year-month-day to total number of days */ + int32_t total_leap_years = (year - 1970 + 1) / 4; + /* Leap year count decreased by the number of xx00 years before current year because these are not leap years, + except for 2000. The year 2400 is not in the valid year range so we don't take that into account. */ + if (year > 2100) + total_leap_years -= year / 100 - 20; + if (year == 2200) + total_leap_years++; + + int32_t total_reg_years = year - 1970 - total_leap_years; + int32_t total_num_days = total_leap_years * 366 + total_reg_years * 365; + int32_t month_cnt; + + for (month_cnt = 1; month_cnt < month; month_cnt++) + { + if (month_cnt == 4 || month_cnt == 6 || month_cnt == 9 || month_cnt == 11) + total_num_days += 30; + else if (month_cnt == 2) + { + if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) + total_num_days += 29; + else + total_num_days += 28; + } + else + total_num_days += 31; + } + total_num_days += day - 1; + + /* Correct the offset sign if negative */ + if (buf[19 + cnt_frac_sec] == '-') + { + hour_offset = -hour_offset; + minute_offset = -minute_offset; + } + /* Convert the total number of days to seconds */ + int64_t ts_days = (int64_t)total_num_days * 24 * 60 * 60; + int64_t ts_hms = hour * 60 * 60 + minute * 60 + second; + if (ts_days + ts_hms > INT64_MAX / DDS_NSECS_IN_SEC) + return DDS_TIME_INVALID; + int64_t ts = DDS_SECS(ts_days + ts_hms); + + /* Apply the hour and minute offset */ + int64_t ts_offset = DDS_SECS((int64_t)hour_offset * 60 * 60 + minute_offset * 60); + + /* Prevent the offset from making the timestamp negative or overflow it */ + if ((ts_offset <= 0 || (ts_offset > 0 && ts_offset < ts)) && INT64_MAX - ts - frac_ns >= -ts_offset) + return ts - ts_offset + frac_ns; + + return DDS_TIME_INVALID; +} + diff --git a/src/security/core/src/shared_secret.c b/src/security/core/src/shared_secret.c new file mode 100644 index 0000000..2446906 --- /dev/null +++ b/src/security/core/src/shared_secret.c @@ -0,0 +1,41 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#include "dds/security/core/shared_secret.h" + +const DDS_Security_octet* +get_challenge1_from_secret_handle (DDS_Security_SharedSecretHandle handle) +{ + DDS_Security_SharedSecretHandleImpl *secret = (DDS_Security_SharedSecretHandleImpl *)(uintptr_t)handle; + return secret->challenge1; +} + +const DDS_Security_octet* +get_challenge2_from_secret_handle (DDS_Security_SharedSecretHandle handle) +{ + DDS_Security_SharedSecretHandleImpl *secret = (DDS_Security_SharedSecretHandleImpl *)(uintptr_t)handle; + return secret->challenge2; +} + +const DDS_Security_octet* +get_secret_from_secret_handle (DDS_Security_SharedSecretHandle handle) +{ + DDS_Security_SharedSecretHandleImpl *secret = (DDS_Security_SharedSecretHandleImpl *)(uintptr_t)handle; + return secret->shared_secret; +} + +size_t +get_secret_size_from_secret_handle (DDS_Security_SharedSecretHandle handle) +{ + DDS_Security_SharedSecretHandleImpl *secret = (DDS_Security_SharedSecretHandleImpl *)(uintptr_t)handle; + return (size_t) secret->shared_secret_size; +} diff --git a/src/security/core/tests/CMakeLists.txt b/src/security/core/tests/CMakeLists.txt new file mode 100644 index 0000000..a1aaa93 --- /dev/null +++ b/src/security/core/tests/CMakeLists.txt @@ -0,0 +1,122 @@ +# +# Copyright(c) 2006 to 2019 ADLINK Technology Limited and others +# +# This program and the accompanying materials are made available under the +# terms of the Eclipse Public License v. 2.0 which is available at +# http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +# v. 1.0 which is available at +# http://www.eclipse.org/org/documents/edl-v10.php. +# +# SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +# +include (GenerateExportHeader) +include (CUnit) + +idlc_generate(SecurityCoreTests SecurityCoreTests.idl) + +function(add_wrapper libname linklibs) + set(srcs_wrapper + "${CMAKE_CURRENT_LIST_DIR}/common/${libname}_wrapper.c" + "${CMAKE_CURRENT_LIST_DIR}/common/plugin_wrapper_msg_q.c") + add_library("dds_security_${libname}_wrapper" SHARED "") + if(CMAKE_GENERATOR MATCHES "Visual Studio") + set_target_properties("dds_security_${libname}_wrapper" PROPERTIES LINK_FLAGS "/ignore:4099") + endif() + + generate_export_header( + "dds_security_${libname}_wrapper" + BASE_NAME SECURITY + EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/include/dds/security/${libname}_wrapper_export.h") + + set_target_properties( + "dds_security_${libname}_wrapper" + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR} + RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR} + RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_CURRENT_BINARY_DIR} + RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_CURRENT_BINARY_DIR} + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_BINARY_DIR} + LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_BINARY_DIR} + LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_CURRENT_BINARY_DIR} + LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_CURRENT_BINARY_DIR}) + + if(APPLE) + set_target_properties("dds_security_${libname}_wrapper" PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") + endif() + + target_link_libraries("dds_security_${libname}_wrapper" PRIVATE CUnit) + target_include_directories("dds_security_${libname}_wrapper" PRIVATE "${CUNIT_DIR}/include") + + target_link_libraries("dds_security_${libname}_wrapper" PUBLIC ddsc ${linklibs}) + target_sources("dds_security_${libname}_wrapper" PRIVATE ${srcs_wrapper}) + target_include_directories("dds_security_${libname}_wrapper" + PUBLIC + "$>" + "$>" + "$>" + "$" + "$" + "$") +endfunction() + +set(security_core_test_sources + "fsm.c" + "timed_cb.c" + "security_utils.c" +) + +if(ENABLE_SSL) + add_wrapper(access_control dds_security_ac) + add_wrapper(authentication dds_security_auth) + add_wrapper(cryptography dds_security_crypto) + + list(APPEND security_core_test_sources + "common/security_config_test_utils.c" + "common/test_utils.c" + "common/cert_utils.c" + "authentication.c" + "access_control.c" + "config.c" + "crypto.c" + "handshake.c" + "plugin_loading.c" + "secure_communication.c" + ) +endif() + +add_cunit_executable(cunit_security_core ${security_core_test_sources}) +if(CMAKE_GENERATOR MATCHES "Visual Studio") + set_target_properties(cunit_security_core PROPERTIES LINK_FLAGS "/ignore:4099") +endif() + +target_include_directories( + cunit_security_core PRIVATE + "$" + "$>" + "$>" + "$>" + "$" + "$" + "$" + "$" + ) +if(ENABLE_SSL) + target_include_directories( + cunit_security_core PRIVATE + "$>" + ) +endif() + +set(common_etc_dir "${CMAKE_CURRENT_SOURCE_DIR}/common/etc") +set(plugin_wrapper_lib_dir "${CMAKE_CURRENT_BINARY_DIR}") +configure_file("common/config_env.h.in" "common/config_env.h") + +target_link_libraries(cunit_security_core PRIVATE ddsc security_api SecurityCoreTests) +if(ENABLE_SSL) + target_link_libraries(cunit_security_core PRIVATE dds_security_auth dds_security_ac dds_security_crypto dds_security_access_control_wrapper dds_security_authentication_wrapper dds_security_cryptography_wrapper) + target_link_libraries(cunit_security_core PRIVATE OpenSSL::SSL) + target_link_libraries(cunit_security_core PRIVATE security_openssl) +endif() +target_include_directories(cunit_security_core PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") diff --git a/src/security/core/tests/SecurityCoreTests.idl b/src/security/core/tests/SecurityCoreTests.idl new file mode 100644 index 0000000..8e2290c --- /dev/null +++ b/src/security/core/tests/SecurityCoreTests.idl @@ -0,0 +1,24 @@ +/* + * 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 + */ +module SecurityCoreTests { + struct Type1 { + long id; //@Key + long value; + }; +#pragma keylist Type1 id + + struct Type2 { + long id; //@Key + string text; + }; +#pragma keylist Type2 id +}; diff --git a/src/security/core/tests/access_control.c b/src/security/core/tests/access_control.c new file mode 100644 index 0000000..6fbdb52 --- /dev/null +++ b/src/security/core/tests/access_control.c @@ -0,0 +1,885 @@ +/* + * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include + +#include "dds/dds.h" +#include "CUnit/Test.h" +#include "CUnit/Theory.h" + +#include "dds/version.h" +#include "dds/ddsrt/cdtors.h" +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/process.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/io.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsi/ddsi_security_omg.h" +#include "dds/ddsi/q_config.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/ddsi/q_misc.h" +#include "dds/ddsi/ddsi_xqos.h" +#include "dds__entity.h" + +#include "dds/security/dds_security_api.h" + +#include "common/config_env.h" +#include "common/access_control_wrapper.h" +#include "common/cryptography_wrapper.h" +#include "common/security_config_test_utils.h" +#include "common/test_identity.h" +#include "common/test_utils.h" +#include "common/cert_utils.h" +#include "SecurityCoreTests.h" + +static const char *config = + "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}" + "" + " " + " 0" + " \\${CYCLONEDDS_PID}" + " " + " " + " " + " " + " data:,${TEST_IDENTITY_CERTIFICATE}" + " data:,${TEST_IDENTITY_PRIVATE_KEY}" + " data:,${TEST_IDENTITY_CA_CERTIFICATE}" + " " + " " + " " + " ${INCL_GOV:+}" + " ${INCL_PERM_CA:+}${TEST_PERMISSIONS_CA}${INCL_PERM_CA:+}" + " ${INCL_PERM:+}" + " " + " " + " " + " " + " " + ""; + +#define MAX_DOMAINS 10 +#define DDS_DOMAINID 0 + +static dds_entity_t g_domain[MAX_DOMAINS]; +static dds_entity_t g_participant[MAX_DOMAINS]; +static uint32_t g_topic_nr = 0; + +static void access_control_init( + size_t n_nodes, + const char * id_certs[], const char * id_keys[], const char * id_ca[], bool exp_pp_fail[], + const char * ac_init_fns[], const char * ac_fini_fns[], + bool incl_gov[], const char * gov[], + bool incl_perm[], const char * perm[], + bool incl_ca[], const char * ca[]) +{ + CU_ASSERT_FATAL (n_nodes <= MAX_DOMAINS); + for (size_t i = 0; i < n_nodes; i++) + { + print_test_msg ("init domain %"PRIuSIZE"\n", i); + struct kvp config_vars[] = { + { "TEST_IDENTITY_CERTIFICATE", id_certs[i], 1 }, + { "TEST_IDENTITY_PRIVATE_KEY", id_keys[i], 1 }, + { "TEST_IDENTITY_CA_CERTIFICATE", id_ca[i], 1 }, + { "ACCESS_CONTROL_INIT", ac_init_fns ? ac_init_fns[i] : NULL, 1 }, + { "ACCESS_CONTROL_FINI", ac_fini_fns ? ac_fini_fns[i] : NULL, 1 }, + { "INCL_GOV", incl_gov[i] ? "1" : "", 2 }, + { "INCL_PERM", incl_perm[i] ? "1" : "", 2 }, + { "INCL_PERM_CA", incl_ca[i] ? "1" : "", 2 }, + { "TEST_GOVERNANCE", gov[i], 1 }, + { "TEST_PERMISSIONS", perm[i], 1 }, + { "TEST_PERMISSIONS_CA", ca[i], 1 }, + { NULL, NULL, 0 } + }; + char *conf = ddsrt_expand_vars_sh (config, &expand_lookup_vars_env, config_vars); + CU_ASSERT_EQUAL_FATAL (expand_lookup_unmatched (config_vars), 0); + g_domain[i] = dds_create_domain (DDS_DOMAINID + (dds_domainid_t)i, conf); + dds_free (conf); + g_participant[i] = dds_create_participant (DDS_DOMAINID + (dds_domainid_t)i, NULL, NULL); + CU_ASSERT_EQUAL_FATAL (exp_pp_fail[i], g_participant[i] <= 0); + } +} + +static void access_control_fini(size_t n, void * res[], size_t nres) +{ + for (size_t i = 0; i < n; i++) + CU_ASSERT_EQUAL_FATAL (dds_delete (g_domain[i]), DDS_RETCODE_OK); + if (res != NULL) + { + for (size_t i = 0; i < nres; i++) + ddsrt_free (res[i]); + } +} + +#define GOV_F PF_F COMMON_ETC_PATH("default_governance.p7s") +#define GOV_FNE PF_F COMMON_ETC_PATH("default_governance_non_existing.p7s") +#define GOV_DI PF_D COMMON_ETC_PATH("default_governance.p7s") +#define PERM_F PF_F COMMON_ETC_PATH("default_permissions.p7s") +#define PERM_FNE PF_F COMMON_ETC_PATH("default_permissions_non_existing.p7s") +#define PERM_DI PF_D COMMON_ETC_PATH("default_permissions.p7s") +#define CA_F PF_F COMMON_ETC_PATH("default_permissions_ca.pem") +#define CA_FNE PF_F COMMON_ETC_PATH("default_permissions_ca_non_existing.pem") +#define CA_DI PF_D COMMON_ETC_PATH("default_permissions_ca.pem") +#define CA_D PF_D TEST_PERMISSIONS_CA_CERTIFICATE + +CU_TheoryDataPoints(ddssec_access_control, config_parameters_file) = { + CU_DataPoints(const char *, + /* */"existing files", + /* | */"non-existing files", + /* | | */"non-existing governance file", + /* | | | */"non-existing permissions file", + /* | | | | */"non-existing permissions ca file", + /* | | | | | */"empty governance", + /* | | | | | | */"empty permissions", + /* | | | | | | | */"empty permissions ca", + /* | | | | | | | | */"all empty", + /* | | | | | | | | | */"invalid governance uri type", + /* | | | | | | | | | | */"permissions ca type data", + /* | | | | | | | | | | | */"no governance element", + /* | | | | | | | | | | | | */"no permissions element", + /* | | | | | | | | | | | | | */"no permissions ca element"), + CU_DataPoints(const char *, GOV_F, GOV_FNE, GOV_FNE, GOV_F, GOV_F, "", GOV_F, GOV_F, "", GOV_DI, GOV_F, "", GOV_F, GOV_F), // Governance config + CU_DataPoints(const char *, PERM_F, PERM_FNE, PERM_F, PERM_FNE, PERM_F, PERM_F, "", PERM_F, "", PERM_F, PERM_F, PERM_F, "", PERM_F), // Permissions config + CU_DataPoints(const char *, CA_F, CA_FNE, CA_F, CA_F, CA_FNE, CA_F, CA_F, "", "", CA_F, CA_D, CA_F, CA_F, ""), // Permissions CA + CU_DataPoints(bool, true, true, true, true, true, true, true, true, true, true, true, false, false, false), // include empty config elements + CU_DataPoints(bool, false, true, true, true, true, true, true, true, false, true, false, true, true, true) // expect failure +}; +/* Testing configuration parameters for the access control security plugin, + using configuration from file. The test cases include using non-existing + files, empty configuration files, mixing configudation from file and inline + in the cyclone XML configuration. */ +CU_Theory((const char * test_descr, const char * gov, const char * perm, const char * ca, bool incl_empty_els, bool exp_fail), + ddssec_access_control, config_parameters_file) +{ + print_test_msg ("running test config_parameters_file: %s\n", test_descr); + bool has_gov = incl_empty_els || strlen (gov); + bool has_perm = incl_empty_els || strlen (perm); + bool has_ca = incl_empty_els || strlen (ca); + access_control_init ( + 2, + (const char *[]) { TEST_IDENTITY1_CERTIFICATE, TEST_IDENTITY1_CERTIFICATE }, + (const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY }, + (const char *[]) { TEST_IDENTITY_CA1_CERTIFICATE, TEST_IDENTITY_CA1_CERTIFICATE }, + (bool []) { exp_fail, exp_fail }, NULL, NULL, + (bool []) { has_gov, has_gov }, (const char *[]) { gov, gov }, + (bool []) { has_perm, has_perm }, (const char *[]) { perm, perm }, + (bool []) { has_ca, has_ca }, (const char *[]) { ca, ca }); + access_control_fini (2, NULL, 0); +} + +#define S(n) (n) +#define M(n) (S(n)*60) +#define H(n) (M(n)*60) +#define D(n) (H(n)*24) +CU_TheoryDataPoints(ddssec_access_control, permissions_expiry) = { + CU_DataPoints(const char *, + /* */"valid 1 minute from now", + /* | */"valid -1 minute until now", + /* | | */"1s valid, create pp after 1100ms", + /* | | | */"node 2 permissions expired", + /* | | | | */"node 1 4s valid, write/read for 10s", + /* | | | | | */"node 2 4s valid, write/read for 10s"), + CU_DataPoints(int32_t, 0, -M(1), 0, 0, 0, 0), /* node 1 permissions not before (offset from local time) */ + CU_DataPoints(int32_t, M(1), 0, S(1), D(1), S(4), D(1)), /* node 1 permissions not after (offset from local time) */ + CU_DataPoints(int32_t, 0, -M(1), 0, -D(1), 0, 0), /* node 2 permissions not before (offset from local time) */ + CU_DataPoints(int32_t, M(1), 0, S(1), 0, D(1), S(4)), /* node 2 permissions not after (offset from local time) */ + CU_DataPoints(uint32_t, 0, 0, 1100, 0, 0, 0), /* delay (ms) after generating permissions */ + CU_DataPoints(bool, false, true, true, false, false, false), /* expect pp 1 create failure */ + CU_DataPoints(bool, false, true, true, true, false, false), /* expect pp 2 create failure */ + CU_DataPoints(uint32_t, 1, 0, 0, 0, 10000, 10000), /* write/read data during x ms */ + CU_DataPoints(bool, false, false, false, false, true, true), /* expect read data failure */ +}; +#undef S +#undef D +#undef H +#undef M +/* Testing expiry of the (signed) permissions XML. Test cases include using + permissions config that is valid for 1 minute, was valid in the past minute, + expires before data is written, expires during writing data. */ +CU_Theory( + (const char * test_descr, + int32_t perm1_not_before, int32_t perm1_not_after, int32_t perm2_not_before, int32_t perm2_not_after, + uint32_t delay_perm, bool exp_pp1_fail, bool exp_pp2_fail, uint32_t write_read_dur, bool exp_read_fail), + ddssec_access_control, permissions_expiry, .timeout=30) +{ + print_test_msg ("running test permissions_expiry: %s\n", test_descr); + + char topic_name[100]; + create_topic_name ("ddssec_access_control_", g_topic_nr++, topic_name, sizeof (topic_name)); + + /* create ca and id1/id2 certs that will not expire during this test */ + char *ca, *id1, *id2, *id1_subj, *id2_subj; + ca = generate_ca ("ca1", TEST_IDENTITY_CA1_PRIVATE_KEY, 0, 3600); + id1 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id1", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id1_subj); + id2 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id2", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id2_subj); + + /* localtime will be converted to gmtime in get_permissions_grant */ + dds_time_t now = dds_time (); + char * rules_xml = get_permissions_rules (NULL, topic_name, topic_name, NULL, NULL); + char * grants[] = { + get_permissions_grant ("id1", id1_subj, now + DDS_SECS(perm1_not_before), now + DDS_SECS(perm1_not_after), rules_xml, NULL), + get_permissions_grant ("id2", id2_subj, now + DDS_SECS(perm2_not_before), now + DDS_SECS(perm2_not_after), rules_xml, NULL) }; + char * perm_config = get_permissions_config (grants, 2, true); + dds_sleepfor (DDS_MSECS (delay_perm)); + + const char * def_gov = PF_F COMMON_ETC_PATH("default_governance.p7s"); + const char * def_perm_ca = PF_F COMMON_ETC_PATH("default_permissions_ca.pem"); + access_control_init ( + 2, + (const char *[]) { id1, id2 }, + (const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY }, + (const char *[]) { ca, ca }, + (bool []) { exp_pp1_fail, exp_pp2_fail }, NULL, NULL, + (bool []) { true, true }, (const char *[]) { def_gov, def_gov }, + (bool []) { true, true }, (const char *[]) { perm_config, perm_config }, + (bool []) { true, true }, (const char *[]) { def_perm_ca, def_perm_ca }); + + if (write_read_dur > 0) + { + dds_entity_t wr = 0, rd = 0; + dds_entity_t pub, sub; + dds_entity_t topic0, topic1; + rd_wr_init (g_participant[0], &pub, &topic0, &wr, g_participant[1], &sub, &topic1, &rd, topic_name); + sync_writer_to_readers(g_participant[0], wr, 1, DDS_SECS(2)); + write_read_for (wr, g_participant[1], rd, DDS_MSECS (write_read_dur), false, exp_read_fail); + } + + access_control_fini (2, (void * []) { rules_xml, grants[0], grants[1], perm_config, ca, id1_subj, id2_subj, id1, id2 }, 9); +} + + +#define N_WR 3 +#define N_NODES (1 + N_WR) +#define PERM_EXP_BASE 2 +#define PERM_EXP_INCR 2 +/* Tests permissions configuration expiry using multiple writers, to validate + that a reader keeps receiving data from writers that have valid permissions config */ +CU_Test(ddssec_access_control, permissions_expiry_multiple, .timeout=20) +{ + char topic_name[100]; + create_topic_name ("ddssec_access_control_", g_topic_nr++, topic_name, sizeof (topic_name)); + + dds_time_t t_perm = dds_time (); + char *ca = generate_ca ("ca1", TEST_IDENTITY_CA1_PRIVATE_KEY, 0, 3600); + char *rules_xml = get_permissions_rules (NULL, topic_name, topic_name, NULL, NULL); + + // 1st node used as reader, other nodes as writer + print_test_msg ("creating permissions grants\n"); + const char *id[N_NODES], *pk[N_NODES], *ca_list[N_NODES], *gov[N_NODES], *perm_conf[N_NODES], *perm_ca[N_NODES]; + char * id_subj[N_NODES], *grants[N_NODES]; + bool exp_fail[N_NODES], incl_el[N_NODES]; + + for (int i = 0; i < N_NODES; i++) + { + char *id_name; + ddsrt_asprintf (&id_name, "id_%d", i); + pk[i] = TEST_IDENTITY1_PRIVATE_KEY; + ca_list[i] = ca; + id[i] = generate_identity (ca_list[i], TEST_IDENTITY_CA1_PRIVATE_KEY, id_name, pk[i], 0, 3600, &id_subj[i]); + exp_fail[i] = false; + gov[i] = PF_F COMMON_ETC_PATH ("default_governance.p7s"); + perm_ca[i] = PF_F COMMON_ETC_PATH ("default_permissions_ca.pem"); + incl_el[i] = true; + dds_duration_t v = DDS_SECS(i == 0 ? 3600 : PERM_EXP_BASE + PERM_EXP_INCR * i); /* reader should not expire */ + dds_time_t t_exp = ddsrt_time_add_duration (t_perm, v); + if (i >= 1) + print_test_msg ("w[%d] grant expires at %d.%06d\n", i - 1, (int32_t) (t_exp / DDS_NSECS_IN_SEC), (int32_t) (t_exp % DDS_NSECS_IN_SEC) / 1000); + grants[i] = get_permissions_grant (id_name, id_subj[i], t_perm, t_exp, rules_xml, NULL); + ddsrt_free (id_name); + } + + char * perm_config_str = get_permissions_config (grants, N_NODES, true); + for (int i = 0; i < N_NODES; i++) + perm_conf[i] = perm_config_str; + + access_control_init ( + N_NODES, + id, pk, ca_list, exp_fail, NULL, NULL, + incl_el, gov, incl_el, perm_conf, incl_el, perm_ca); + + // create 1 reader + dds_qos_t * rdqos = get_default_test_qos (); + dds_entity_t sub = dds_create_subscriber (g_participant[0], NULL, NULL); + CU_ASSERT_FATAL (sub > 0); + dds_entity_t sub_tp = dds_create_topic (g_participant[0], &SecurityCoreTests_Type1_desc, topic_name, NULL, NULL); + CU_ASSERT_FATAL (sub_tp > 0); + dds_entity_t rd = dds_create_reader (sub, sub_tp, rdqos, NULL); + CU_ASSERT_FATAL (rd > 0); + dds_set_status_mask (rd, DDS_SUBSCRIPTION_MATCHED_STATUS); + dds_delete_qos (rdqos); + + // create N_WR writers + dds_qos_t * wrqos = get_default_test_qos (); + dds_entity_t wr[N_WR]; + for (int i = 0; i < N_WR; i++) + { + dds_entity_t pub = dds_create_publisher (g_participant[i + 1], NULL, NULL); + CU_ASSERT_FATAL (pub > 0); + dds_entity_t pub_tp = dds_create_topic (g_participant[i + 1], &SecurityCoreTests_Type1_desc, topic_name, NULL, NULL); + CU_ASSERT_FATAL (pub_tp > 0); + wr[i] = dds_create_writer (pub, pub_tp, wrqos, NULL); + CU_ASSERT_FATAL (wr[i] > 0); + dds_set_status_mask (wr[i], DDS_PUBLICATION_MATCHED_STATUS); + sync_writer_to_readers (g_participant[i + 1], wr[i], 1, DDS_SECS(2)); + } + dds_delete_qos (wrqos); + + sync_reader_to_writers (g_participant[0], rd, N_WR, DDS_SECS (2)); + + // write data + SecurityCoreTests_Type1 sample = { 1, 1 }; + dds_return_t ret; + dds_entity_t ws = dds_create_waitset (g_participant[0]); + dds_entity_t gcond = dds_create_guardcondition (g_participant[0]); + dds_set_guardcondition (gcond, false); + dds_waitset_attach (ws, gcond, 0); + + dds_set_status_mask (rd, DDS_DATA_AVAILABLE_STATUS); + for (int run = 0; run < N_WR; run++) + { + // wait until 1s after next writer pp permission expires + dds_waitset_wait_until (ws, NULL, 0, t_perm + DDS_SECS (PERM_EXP_BASE + PERM_EXP_INCR * run + 1)); + print_test_msg ("run %d\n", run); + for (int w = 0; w < N_WR; w++) + { + sample.id = w; + ret = dds_write (wr[w], &sample); + print_test_msg ("write %d\n", w); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + } + } + + // wait until last pp's permissions are expired + dds_waitset_wait_until (ws, NULL, 0, t_perm + DDS_SECS (PERM_EXP_BASE + PERM_EXP_INCR * N_WR + 1)); + + // check received data + SecurityCoreTests_Type1 * data = ddsrt_calloc (N_WR, sizeof (*data)); + dds_sample_info_t rd_info[N_WR]; + static void * rd_samples[N_WR]; + for (int i = 0; i < N_WR; i++) + rd_samples[i] = &data[i]; + + for (int w = 0; w < N_WR; w++) + { + sample.id = w; + dds_instance_handle_t ih = dds_lookup_instance(rd, &sample); + CU_ASSERT_NOT_EQUAL_FATAL(ih, DDS_HANDLE_NIL); + ret = dds_take_instance (rd, rd_samples, rd_info, N_WR, N_WR, ih); + print_test_msg ("samples from writer %d: %d\n", w, ret); + CU_ASSERT_EQUAL_FATAL (ret, w + 1); + print_test_msg ("writer %d instance state: %d\n", w, rd_info[w].instance_state); + CU_ASSERT_EQUAL_FATAL (rd_info[w].instance_state, DDS_NOT_ALIVE_DISPOSED_INSTANCE_STATE); + print_test_msg ("writer %d valid data: %d\n", w, rd_info[w].valid_data); + CU_ASSERT_EQUAL_FATAL (rd_info[w].valid_data, true); + } + + access_control_fini (N_NODES, (void * []) { ca, rules_xml, perm_config_str, data }, 4); + for (int i = 0; i < N_NODES; i++) + { + ddsrt_free (grants[i]); + ddsrt_free (id_subj[i]); + ddsrt_free ((char *)id[i]); + } +} +#undef N_WR +#undef N_NODES +#undef PERM_EXP_BASE +#undef PERM_EXP_INCR + +#define na false +CU_TheoryDataPoints(ddssec_access_control, hooks) = { + CU_DataPoints(const char *, + /* */"init_test_access_control_local_participant_not_allowed", + /* | */"init_test_access_control_local_permissions_not_allowed", + /* | | */"init_test_access_control_local_topic_not_allowed", + /* | | | */"init_test_access_control_local_writer_not_allowed", + /* | | | | */"init_test_access_control_local_reader_not_allowed", + /* | | | | | */"init_test_access_control_remote_permissions_not_allowed", + /* | | | | | | */"init_test_access_control_remote_participant_not_allowed", + /* | | | | | | | */"init_test_access_control_remote_topic_not_allowed", + /* | | | | | | | | */"init_test_access_control_remote_writer_not_allowed", + /* | | | | | | | | | */"init_test_access_control_remote_reader_not_allowed", + /* | | | | | | | | | | */"init_test_access_control_remote_reader_relay_only"), + CU_DataPoints(bool, true, true, false, false, false, false, false, false, false, false, false), // exp_pp_fail + CU_DataPoints(bool, na, na, true, false, false, false, false, false, false, false, false), // exp_local_topic_fail + CU_DataPoints(bool, na, na, false, false, false, false, false, false, false, false, false), // exp_remote_topic_fail + CU_DataPoints(bool, na, na, na, true, false, false, false, false, false, false, false), // exp_wr_fail + CU_DataPoints(bool, na, na, na, false, true, false, false, false, false, false, false), // exp_rd_fail + CU_DataPoints(bool, na, na, na, na, na, true, true, true, false, true, true), // exp_wr_rd_sync_fail + CU_DataPoints(bool, na, na, na, false, na, true, true, true, true, false, false), // exp_rd_wr_sync_fail +}; +#undef na +/* Test that the security implementation in DDSI is correctly handling denial of + creating enities, e.g. local participant not allowed, local writer not allowed, + remote topic not allowed, etc. This test is initializing the wrapper plugin in a + not-allowed mode to force denial of a specified entity. */ +CU_Theory( + (const char * init_fn, bool exp_pp_fail, bool exp_local_topic_fail, bool exp_remote_topic_fail, bool exp_wr_fail, bool exp_rd_fail, bool exp_wr_rd_sync_fail, bool exp_rd_wr_sync_fail), + ddssec_access_control, hooks, .timeout=60) +{ + for (int i = 0; i <= 1; i++) + { + bool discovery_protection = (i == 0); + print_test_msg ("running test access_control_hooks: %s with discovery protection %s\n", init_fn, discovery_protection ? "enabled" : "disabled"); + + char * gov_topic_rule = get_governance_topic_rule ("*", discovery_protection, false, true, true, PK_N, BPK_N); + char * gov_config = get_governance_config (false, true, PK_E, PK_N, PK_N, gov_topic_rule, true); + + const char * def_perm = PF_F COMMON_ETC_PATH("default_permissions.p7s"); + const char * def_perm_ca = PF_F COMMON_ETC_PATH("default_permissions_ca.pem"); + + access_control_init ( + 2, + (const char *[]) { TEST_IDENTITY1_CERTIFICATE, TEST_IDENTITY1_CERTIFICATE }, + (const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY }, + (const char *[]) { TEST_IDENTITY_CA1_CERTIFICATE, TEST_IDENTITY_CA1_CERTIFICATE }, + (bool []) { exp_pp_fail, false }, + (const char *[]) { init_fn, "init_test_access_control_wrapped" }, (const char *[]) { "finalize_test_access_control_not_allowed", "finalize_test_access_control_wrapped" }, + (bool []) { true, true, true }, (const char *[]) { gov_config, gov_config }, + (bool []) { true, true, true }, (const char *[]) { def_perm, def_perm }, + (bool []) { true, true, true }, (const char *[]) { def_perm_ca, def_perm_ca }); + + if (!exp_pp_fail) + { + dds_entity_t lwr = 0, rwr = 0, lrd = 0, rrd = 0; + dds_entity_t ltopic[2], rtopic[2]; + dds_entity_t lpub, lsub, rpub, rsub; + char topic_name[100]; + + // Local writer, remote reader + create_topic_name (AC_WRAPPER_TOPIC_PREFIX, g_topic_nr++, topic_name, sizeof (topic_name)); + rd_wr_init_fail ( + g_participant[0], &lpub, <opic[0], &lwr, + g_participant[1], &rsub, &rtopic[0], &rrd, + topic_name, exp_local_topic_fail, exp_wr_fail, exp_remote_topic_fail, false); + if (!exp_local_topic_fail && !exp_remote_topic_fail && !exp_wr_fail) + sync_writer_to_readers (g_participant[0], lwr, exp_wr_rd_sync_fail ? 0 : 1, DDS_SECS(2)); + + // Local reader, remote writer + create_topic_name (AC_WRAPPER_TOPIC_PREFIX, g_topic_nr++, topic_name, sizeof (topic_name)); + rd_wr_init_fail ( + g_participant[1], &rpub, &rtopic[1], &rwr, + g_participant[0], &lsub, <opic[1], &lrd, + topic_name, exp_remote_topic_fail, false, exp_local_topic_fail, exp_rd_fail); + if (!exp_local_topic_fail && !exp_remote_topic_fail && !exp_rd_fail) + sync_reader_to_writers (g_participant[0], lrd, exp_rd_wr_sync_fail ? 0 : 1, DDS_SECS(1)); + } + + access_control_fini (2, (void * []) { gov_topic_rule, gov_config }, 2); + } +} + +#define na false +CU_TheoryDataPoints(ddssec_access_control, join_access_control) = { + CU_DataPoints(const char *, + /* */"no join access control", + /* | */"join access control pp1, valid", + /* | | */"join access control pp1 and pp2, valid", + /* | | | */"join access control pp1, invalid", + /* | | | | */"join access control pp1 and pp2, invalid"), + CU_DataPoints(bool, false, true, true, true, true), /* join access control pp 1 enabled */ + CU_DataPoints(bool, false, false, true, false, true), /* join access control pp 2 enabled */ + CU_DataPoints(bool, false, false, false, true, true), /* permissions pp 1 invalid */ + CU_DataPoints(bool, false, false, false, false, true), /* permissions pp 2 invalid */ + CU_DataPoints(bool, false, false, false, true, true), /* expect pp 1 create failure */ + CU_DataPoints(bool, false, false, false, false, true), /* expect pp 2 create failure */ + CU_DataPoints(bool, false, false, false, na, na), /* expect handshake failure */ +}; +#undef na +/* Testing handshake result using join access control setting enabled/disabled and + valid/invalid permissions for 2 participants. */ +CU_Theory( + (const char * test_descr, bool join_ac_pp1, bool join_ac_pp2, bool perm_inv_pp1, bool perm_inv_pp2, bool exp_pp1_fail, bool exp_pp2_fail, bool exp_hs_fail), + ddssec_access_control, join_access_control, .timeout=30) +{ + print_test_msg ("running test join_access_control: %s\n", test_descr); + + char topic_name[100]; + create_topic_name ("ddssec_access_control_", g_topic_nr++, topic_name, sizeof (topic_name)); + + /* create ca and id1/id2 certs that will not expire during this test */ + char *ca, *id1, *id2, *id1_subj, *id2_subj; + ca = generate_ca ("ca1", TEST_IDENTITY_CA1_PRIVATE_KEY, 0, 3600); + id1 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id1", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id1_subj); + id2 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id2", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id2_subj); + + dds_time_t now = dds_time (); + char * rules1_xml = get_permissions_rules (perm_inv_pp1 ? "99" : NULL, topic_name, topic_name, NULL, NULL); + char * rules2_xml = get_permissions_rules (perm_inv_pp2 ? "99" : NULL, topic_name, topic_name, NULL, NULL); + char * grants[] = { + get_permissions_grant ("id1", id1_subj, now, now + DDS_SECS(3600), rules1_xml, NULL), + get_permissions_grant ("id2", id2_subj, now, now + DDS_SECS(3600), rules2_xml, NULL) }; + char * perm_config = get_permissions_config (grants, 2, true); + + char * gov_topic_rule = get_governance_topic_rule ("*", false, false, true, true, PK_N, BPK_N); + char * gov_config_pp1 = get_governance_config (false, join_ac_pp1, PK_N, PK_N, PK_N, gov_topic_rule, true); + char * gov_config_pp2 = get_governance_config (false, join_ac_pp2, PK_N, PK_N, PK_N, gov_topic_rule, true); + const char * def_perm_ca = PF_F COMMON_ETC_PATH("default_permissions_ca.pem"); + + access_control_init ( + 2, + (const char *[]) { id1, id2 }, + (const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY }, + (const char *[]) { ca, ca }, + (bool []) { exp_pp1_fail, exp_pp2_fail }, NULL, NULL, + (bool []) { true, true }, (const char *[]) { gov_config_pp1, gov_config_pp2 }, + (bool []) { true, true }, (const char *[]) { perm_config, perm_config }, + (bool []) { true, true }, (const char *[]) { def_perm_ca, def_perm_ca }); + + if (!exp_pp1_fail && !exp_pp2_fail) + validate_handshake (DDS_DOMAINID, exp_hs_fail, NULL, NULL, NULL, DDS_SECS(2)); + + access_control_fini (2, (void * []) { gov_config_pp1, gov_config_pp2, gov_topic_rule, rules1_xml, rules2_xml, grants[0], grants[1], perm_config, ca, id1_subj, id2_subj, id1, id2 }, 13); +} + +#define na false +CU_TheoryDataPoints(ddssec_access_control, discovery_liveliness_protection) = { + CU_DataPoints(const char *, + /* */"disabled", + /* | */"enabled, protection kind none", + /* | | */"disabled, protection kind encrypt", + /* | | | */"enabled, protection kind encrypt", + /* | | | | */"enabled, protection kind sign", + /* | | | | | */"enabled, protection kind encrypt-with-origin_auth", + /* | | | | | | */"enabled for node 1, disabled for node 2", + /* | | | | | | | */"node 1 and node 2 different protection kinds"), + CU_DataPoints(bool, false, true, false, true, true, true, true, true), /* enable_discovery_protection for pp 1 */ + CU_DataPoints(bool, false, true, false, true, true, true, false, true), /* enable_discovery_protection for pp 2 */ + CU_DataPoints(DDS_Security_ProtectionKind, PK_N, PK_N, PK_E, PK_E, PK_S, PK_EOA, PK_E, PK_E), /* discovery_protection_kind pp 1 */ + CU_DataPoints(DDS_Security_ProtectionKind, PK_N, PK_N, PK_E, PK_E, PK_S, PK_EOA, PK_N, PK_S), /* discovery_protection_kind pp 2 */ + CU_DataPoints(bool, false, false, false, false, false, false, true, true), /* expect rd-wr match fail */ + CU_DataPoints(bool, false, false, true, true, true, true, true, true), /* expect SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER of pp 1 to have a crypto handle */ + CU_DataPoints(bool, na, na, true, true, true, true, false, false), /* expect encode_datawriter_submessage for SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER of pp 1 */ +}; +#undef na + +enum test_discovery_liveliness +{ + TEST_DISCOVERY, + TEST_LIVELINESS +}; + +static void test_discovery_liveliness_protection(enum test_discovery_liveliness kind, + bool enable_protection_pp1, bool enable_protection_pp2, + DDS_Security_ProtectionKind protection_kind_pp1, DDS_Security_ProtectionKind protection_kind_pp2, + bool exp_rd_wr_match_fail, bool exp_secure_pub_wr_handle, bool exp_secure_pub_wr_encode_decode) +{ + bool dp = kind == TEST_DISCOVERY, lp = kind == TEST_LIVELINESS; + char topic_name[100]; + create_topic_name ("ddssec_access_control_", g_topic_nr++, topic_name, sizeof (topic_name)); + + /* create ca and id1/id2 certs that will not expire during this test */ + char *ca, *id1, *id2, *id1_subj, *id2_subj; + ca = generate_ca ("ca1", TEST_IDENTITY_CA1_PRIVATE_KEY, 0, 3600); + id1 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id1", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id1_subj); + id2 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id2", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id2_subj); + + char * grants[] = { + get_permissions_default_grant ("id1", id1_subj, topic_name), + get_permissions_default_grant ("id2", id2_subj, topic_name) }; + char * perm_config = get_permissions_config (grants, 2, true); + + char * gov_topic_rule1 = get_governance_topic_rule (topic_name, dp && enable_protection_pp1, lp && enable_protection_pp1, true, true, PK_E, BPK_N); + char * gov_topic_rule2 = get_governance_topic_rule (topic_name, dp && enable_protection_pp2, lp && enable_protection_pp2, true, true, PK_E, BPK_N); + char * gov_config1 = get_governance_config (false, true, dp ? protection_kind_pp1 : PK_N, lp ? protection_kind_pp1 : PK_N, PK_E, gov_topic_rule1, true); + char * gov_config2 = get_governance_config (false, true, dp ? protection_kind_pp2 : PK_N, lp ? protection_kind_pp2 : PK_N, PK_E, gov_topic_rule2, true); + const char * def_perm_ca = PF_F COMMON_ETC_PATH("default_permissions_ca.pem"); + + access_control_init ( + 2, + (const char *[]) { id1, id2 }, + (const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY }, + (const char *[]) { ca, ca }, + (bool []) { false, false }, NULL, NULL, + (bool []) { true, true }, (const char *[]) { gov_config1, gov_config2 }, + (bool []) { true, true }, (const char *[]) { perm_config, perm_config }, + (bool []) { true, true }, (const char *[]) { def_perm_ca, def_perm_ca }); + validate_handshake (DDS_DOMAINID, false, NULL, NULL, NULL, DDS_SECS(2)); + + dds_entity_t pub, sub, pub_tp, sub_tp, wr, rd; + rd_wr_init (g_participant[0], &pub, &pub_tp, &wr, g_participant[1], &sub, &sub_tp, &rd, topic_name); + sync_writer_to_readers (g_participant[0], wr, exp_rd_wr_match_fail ? 0 : 1, DDS_SECS(2)); + if (!exp_rd_wr_match_fail) + write_read_for (wr, g_participant[1], rd, DDS_MSECS (100), false, false); + + unsigned builtin_wr = dp ? NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER : NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER; + const char * builtin_wr_descr = dp ? "SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER" : "P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER"; + DDS_Security_DatawriterCryptoHandle secure_pub_wr_handle = get_builtin_writer_crypto_handle (g_participant[0], builtin_wr); + print_test_msg ("crypto handle for %s: %ld\n", builtin_wr_descr, secure_pub_wr_handle); + CU_ASSERT_EQUAL_FATAL (exp_secure_pub_wr_handle, secure_pub_wr_handle != 0); + + struct dds_security_cryptography_impl * crypto_context_pub = get_cryptography_context (g_participant[0]); + CU_ASSERT_FATAL (crypto_context_pub != NULL); + + struct crypto_encode_decode_data *log = get_encode_decode_log (crypto_context_pub, ENCODE_DATAWRITER_SUBMESSAGE, secure_pub_wr_handle); + CU_ASSERT_EQUAL_FATAL (exp_secure_pub_wr_handle && exp_secure_pub_wr_encode_decode, log != NULL); + if (log != NULL) + { + print_test_msg ("encode_datawriter_submessage count for %s: %u\n", builtin_wr_descr, log->count); + CU_ASSERT_FATAL (log->count > 0); + ddsrt_free (log); + } + + access_control_fini (2, (void * []) { gov_config1, gov_config2, gov_topic_rule1, gov_topic_rule2, grants[0], grants[1], perm_config, ca, id1_subj, id2_subj, id1, id2 }, 12); +} +/* Testing discovery and liveliness protection by checking that encode_datawriter_submessage + is called for SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER and/or P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER + depending on the discovery and liveliness protection settings in security configuration. */ +CU_Theory( + (const char * test_descr, bool enable_discovery_protection_pp1, bool enable_discovery_protection_pp2, + DDS_Security_ProtectionKind discovery_protection_kind_pp1, DDS_Security_ProtectionKind discovery_protection_kind_pp2, + bool exp_rd_wr_match_fail, bool exp_secure_pub_wr_handle, bool exp_secure_pub_wr_encode_decode), + ddssec_access_control, discovery_liveliness_protection, .timeout=40) +{ + enum test_discovery_liveliness kinds[2] = { TEST_DISCOVERY, TEST_LIVELINESS }; + for (size_t i = 0; i < sizeof (kinds) / sizeof (kinds[0]); i++) + { + print_test_msg ("running test %s_protection: %s\n", kinds[i] == TEST_DISCOVERY ? "discovery" : "liveliness", test_descr); + test_discovery_liveliness_protection (kinds[i], enable_discovery_protection_pp1, enable_discovery_protection_pp2, + discovery_protection_kind_pp1, discovery_protection_kind_pp2, exp_rd_wr_match_fail, exp_secure_pub_wr_handle, exp_secure_pub_wr_encode_decode); + } +} + +static void test_encoding_mismatch( + bool exp_hs_fail, bool exp_rd_wr_fail, + DDS_Security_ProtectionKind rtps_pk1, DDS_Security_ProtectionKind rtps_pk2, + DDS_Security_ProtectionKind discovery_pk1, DDS_Security_ProtectionKind discovery_pk2, + DDS_Security_ProtectionKind liveliness_pk1, DDS_Security_ProtectionKind liveliness_pk2, + DDS_Security_ProtectionKind metadata_pk1, DDS_Security_ProtectionKind metadata_pk2, + DDS_Security_BasicProtectionKind payload_pk1, DDS_Security_BasicProtectionKind payload_pk2) +{ + char topic_name[100]; + create_topic_name ("ddssec_access_control_", g_topic_nr++, topic_name, sizeof (topic_name)); + + /* create ca and id1/id2 certs that will not expire during this test */ + char *ca, *id1, *id2, *id1_subj, *id2_subj; + ca = generate_ca ("ca1", TEST_IDENTITY_CA1_PRIVATE_KEY, 0, 3600); + id1 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id1", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id1_subj); + id2 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id2", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id2_subj); + + char * grants[] = { + get_permissions_default_grant ("id1", id1_subj, topic_name), + get_permissions_default_grant ("id2", id2_subj, topic_name) }; + char * perm_config = get_permissions_config (grants, 2, true); + + char * gov_topic_rule1 = get_governance_topic_rule (topic_name, true, true, true, true, metadata_pk1, payload_pk1); + char * gov_topic_rule2 = get_governance_topic_rule (topic_name, true, true, true, true, metadata_pk2, payload_pk2); + char * gov_config1 = get_governance_config (false, true, discovery_pk1, liveliness_pk1, rtps_pk1, gov_topic_rule1, true); + char * gov_config2 = get_governance_config (false, true, discovery_pk2, liveliness_pk2, rtps_pk2, gov_topic_rule2, true); + const char * def_perm_ca = PF_F COMMON_ETC_PATH("default_permissions_ca.pem"); + + access_control_init ( + 2, + (const char *[]) { id1, id2 }, + (const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY }, + (const char *[]) { ca, ca }, + (bool []) { false, false }, NULL, NULL, + (bool []) { true, true }, (const char *[]) { gov_config1, gov_config2 }, + (bool []) { true, true }, (const char *[]) { perm_config, perm_config }, + (bool []) { true, true }, (const char *[]) { def_perm_ca, def_perm_ca }); + + struct Handshake *hs_list; + int nhs; + validate_handshake (DDS_DOMAINID, false, NULL, &hs_list, &nhs, DDS_SECS(2)); + CU_ASSERT_EQUAL_FATAL (exp_hs_fail, nhs < 1); + handshake_list_fini (hs_list, nhs); + + if (!exp_hs_fail) + { + dds_entity_t pub, sub, pub_tp, sub_tp, wr, rd; + rd_wr_init (g_participant[0], &pub, &pub_tp, &wr, g_participant[1], &sub, &sub_tp, &rd, topic_name); + sync_writer_to_readers (g_participant[0], wr, exp_rd_wr_fail ? 0 : 1, DDS_SECS(1)); + } + + access_control_fini (2, (void * []) { gov_config1, gov_config2, gov_topic_rule1, gov_topic_rule2, grants[0], grants[1], perm_config, ca, id1_subj, id2_subj, id1, id2 }, 12); +} + +/* Testing handshake result for any combination of protection kind values for rtps, discovery, + liveliness, metadata (submsg) and payload encoding. In all cases where there is an encoding + mismatch, the security handshake is expect to fail */ +static DDS_Security_ProtectionKind pk[] = { PK_N, PK_S, PK_E, PK_SOA, PK_EOA }; +static DDS_Security_BasicProtectionKind bpk[] = { BPK_N, BPK_S, BPK_E }; + +CU_Test(ddssec_access_control, encoding_mismatch_rtps, .timeout=30) +{ + for (size_t pk1 = 0; pk1 < sizeof (pk) / sizeof (pk[0]); pk1++) + for (size_t pk2 = pk1 + 1; pk2 < sizeof (pk) / sizeof (pk[0]); pk2++) + test_encoding_mismatch (pk1 != pk2, false, pk[pk1], pk[pk2], PK_N, PK_N, PK_N, PK_N, PK_N, PK_N, BPK_N, BPK_N); +} + +CU_Test(ddssec_access_control, encoding_mismatch_discovery, .timeout=30) +{ + for (size_t pk1 = 0; pk1 < sizeof (pk) / sizeof (pk[0]); pk1++) + for (size_t pk2 = pk1 + 1; pk2 < sizeof (pk) / sizeof (pk[0]); pk2++) + test_encoding_mismatch (pk1 != pk2, false, PK_N, PK_N, pk[pk1], pk[pk2], PK_N, PK_N, PK_N, PK_N, BPK_N, BPK_N); +} + +CU_Test(ddssec_access_control, encoding_mismatch_liveliness, .timeout=30) +{ + for (size_t pk1 = 0; pk1 < sizeof (pk) / sizeof (pk[0]); pk1++) + for (size_t pk2 = pk1 + 1; pk2 < sizeof (pk) / sizeof (pk[0]); pk2++) + test_encoding_mismatch (pk1 != pk2, false, PK_N, PK_N, PK_N, PK_N, pk[pk1], pk[pk2], PK_N, PK_N, BPK_N, BPK_N); +} + +CU_Test(ddssec_access_control, encoding_mismatch_metadata, .timeout=30) +{ + for (size_t pk1 = 0; pk1 < sizeof (pk) / sizeof (pk[0]); pk1++) + for (size_t pk2 = pk1 + 1; pk2 < sizeof (pk) / sizeof (pk[0]); pk2++) + test_encoding_mismatch (false, pk1 != pk2, PK_N, PK_N, PK_N, PK_N, PK_N, PK_N, pk[pk1], pk[pk2], BPK_N, BPK_N); +} + +CU_Test(ddssec_access_control, encoding_mismatch_payload, .timeout=30) +{ + for (size_t pk1 = 0; pk1 < sizeof (bpk) / sizeof (bpk[0]); pk1++) + for (size_t pk2 = pk1 + 1; pk2 < sizeof (bpk) / sizeof (bpk[0]); pk2++) + test_encoding_mismatch (false, pk1 != pk2, PK_N, PK_N, PK_N, PK_N, PK_N, PK_N, PK_N, PK_N, bpk[pk1], bpk[pk2]); +} + + +static void test_readwrite_protection ( + bool allow_pub, bool allow_sub, bool deny_pub, bool deny_sub, bool write_ac, bool read_ac, + bool exp_pub_pp_fail, bool exp_pub_tp_fail, bool exp_wr_fail, + bool exp_sub_pp_fail, bool exp_sub_tp_fail, bool exp_rd_fail, + bool exp_sync_fail, const char * default_policy) +{ + print_test_msg ("running test readwrite_protection: \n"); + print_test_msg ("- allow_pub=%d | allow_sub=%d | deny_pub=%d | deny_sub=%d | write_ac=%d | read_ac=%d | default_policy=%s\n", allow_pub, allow_sub, deny_pub, deny_sub, write_ac, read_ac, default_policy); + print_test_msg ("- exp_pub_pp_fail=%d | exp_pub_tp_fail=%d | exp_wr_fail=%d | exp_sub_pp_fail=%d | exp_sub_tp_fail=%d | exp_rd_fail=%d | exp_sync_fail=%d\n", exp_pub_pp_fail, exp_pub_tp_fail, exp_wr_fail, exp_sub_pp_fail, exp_sub_tp_fail, exp_rd_fail, exp_sync_fail); + + char topic_name[100]; + create_topic_name ("ddssec_access_control_", g_topic_nr++, topic_name, sizeof (topic_name)); + + /* create ca and id1/id2 certs that will not expire during this test */ + char *ca, *id1, *id2, *id1_subj, *id2_subj; + ca = generate_ca ("ca1", TEST_IDENTITY_CA1_PRIVATE_KEY, 0, 3600); + id1 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id1", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id1_subj); + id2 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id2", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id2_subj); + + dds_time_t now = dds_time (); + char * rules_xml = get_permissions_rules (NULL, allow_pub ? topic_name : NULL, allow_sub ? topic_name : NULL, deny_pub ? topic_name : NULL, deny_sub ? topic_name : NULL); + char * grants[] = { + get_permissions_grant ("id1", id1_subj, now, now + DDS_SECS(3600), rules_xml, default_policy), + get_permissions_grant ("id2", id2_subj, now, now + DDS_SECS(3600), rules_xml, default_policy) }; + char * perm_config = get_permissions_config (grants, 2, true); + + char * gov_topic_rule = get_governance_topic_rule (topic_name, false, false, read_ac, write_ac, PK_E, BPK_E); + char * gov_config = get_governance_config (false, true, PK_N, PK_N, PK_N, gov_topic_rule, true); + const char * def_perm_ca = PF_F COMMON_ETC_PATH("default_permissions_ca.pem"); + + access_control_init ( + 2, + (const char *[]) { id1, id2 }, + (const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY }, + (const char *[]) { ca, ca }, + (bool []) { exp_pub_pp_fail, exp_sub_pp_fail }, NULL, NULL, + (bool []) { true, true }, (const char *[]) { gov_config, gov_config }, + (bool []) { true, true }, (const char *[]) { perm_config, perm_config }, + (bool []) { true, true }, (const char *[]) { def_perm_ca, def_perm_ca }); + + if (!exp_pub_pp_fail && !exp_sub_pp_fail) + { + dds_entity_t pub, sub, pub_tp, sub_tp, wr, rd; + validate_handshake_nofail (DDS_DOMAINID, DDS_SECS(2)); + rd_wr_init_fail (g_participant[0], &pub, &pub_tp, &wr, g_participant[1], &sub, &sub_tp, &rd, topic_name, exp_pub_tp_fail, exp_wr_fail, exp_sub_tp_fail, exp_rd_fail); + if (!exp_pub_tp_fail && !exp_wr_fail && !exp_sub_tp_fail && !exp_rd_fail) + sync_writer_to_readers (g_participant[0], wr, exp_sync_fail ? 0 : 1, DDS_SECS(1)); + } + + access_control_fini (2, (void * []) { gov_config, gov_topic_rule, rules_xml, grants[0], grants[1], perm_config, ca, id1_subj, id2_subj, id1, id2 }, 11); +} +/* Test read/write access control by running test cases with different combinations + of allow and deny rules for publishing and subscribing on a topic, and check correct + working of the default policy. */ +CU_Test(ddssec_access_control, readwrite_protection, .timeout=60) +{ + for (int allow_pub = 0; allow_pub <= 1; allow_pub++) + for (int allow_sub = 0; allow_sub <= 1; allow_sub++) + for (int deny_pub = 0; deny_pub <= 1 && !(allow_pub && deny_pub); deny_pub++) + for (int deny_sub = 0; deny_sub <= 1 && !(allow_sub && deny_sub); deny_sub++) + for (int write_ac = 0; write_ac <= 1; write_ac++) + for (int read_ac = 0; read_ac <= 1; read_ac++) + for (int default_deny = 0; default_deny <= 1; default_deny++) + { + /* creating local writer/reader fails if write_ac/read_ac enabled and no allow-pub/sub or a deny-pub/sub rule exists */ + bool exp_wr_fail = write_ac && !allow_pub && (deny_pub || default_deny); + bool exp_rd_fail = read_ac && !allow_sub && (deny_sub || default_deny); + /* if both read_ac and write_ac are enabled, and pub and sub not allowed, topic creation should fail */ + bool exp_tp_fail = write_ac && read_ac && !allow_pub && !allow_sub && (deny_pub || deny_sub || default_deny); + /* participant creation should fail under same conditions as topic creation (as opposed to the DDS Security spec, + table 63, that states that participant creation fails when there is not any topic that has enable_read/write_ac + set to false and join_ac is enabled; it seems that the allow_rule condition is missing there) */ + bool exp_pp_fail = write_ac && read_ac && !allow_pub && !allow_sub && default_deny; + /* join-ac is enabled in this test, so check_remote_pp fails (and therefore the reader/writer sync) in case not any allow rule exists */ + bool exp_sync_fail = !allow_pub && !allow_sub && default_deny; + + test_readwrite_protection (allow_pub, allow_sub, deny_pub, deny_sub, write_ac, read_ac, + exp_pp_fail, exp_tp_fail, exp_wr_fail, exp_pp_fail, exp_tp_fail, exp_rd_fail, exp_sync_fail, default_deny ? "DENY" : "ALLOW"); + } +} + +/* Check that communication for a topic that is allowed in the permissions config + keeps working in case the publisher also creates a writer for a non-allowed topic */ +CU_Test(ddssec_access_control, denied_topic) +{ + char topic_name[100], denied_topic_name[100]; + create_topic_name ("ddssec_access_control_", g_topic_nr++, topic_name, sizeof (topic_name)); + create_topic_name ("ddssec_access_control_", g_topic_nr++, denied_topic_name, sizeof (denied_topic_name)); + + char *ca, *id1, *id2, *id1_subj, *id2_subj; + ca = generate_ca ("ca1", TEST_IDENTITY_CA1_PRIVATE_KEY, 0, 3600); + id1 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id1", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id1_subj); + id2 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id2", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id2_subj); + + dds_time_t now = dds_time (); + char * sub_rules_xml = get_permissions_rules (NULL, NULL, NULL, denied_topic_name, denied_topic_name); + char * grants_pub[] = { get_permissions_grant ("id1", id1_subj, now, now + DDS_SECS(3600), NULL, "ALLOW") }; + char * grants_sub[] = { get_permissions_grant ("id2", id2_subj, now, now + DDS_SECS(3600), sub_rules_xml, "ALLOW") }; + char * perm_config_pub = get_permissions_config (grants_pub, 1, true); + char * perm_config_sub = get_permissions_config (grants_sub, 1, true); + + char * gov_topic_rule = get_governance_topic_rule (NULL, true, true, true, true, PK_E, BPK_E); + char * gov_config = get_governance_config (false, true, PK_E, PK_E, PK_E, gov_topic_rule, true); + const char * def_perm_ca = PF_F COMMON_ETC_PATH("default_permissions_ca.pem"); + + access_control_init ( + 2, + (const char *[]) { id1, id2 }, + (const char *[]) { TEST_IDENTITY1_PRIVATE_KEY, TEST_IDENTITY1_PRIVATE_KEY }, + (const char *[]) { ca, ca }, + (bool []) { false, false }, + NULL, NULL, + (bool []) { true, true }, (const char *[]) { gov_config, gov_config }, + (bool []) { true, true }, (const char *[]) { perm_config_pub, perm_config_sub }, + (bool []) { true, true }, (const char *[]) { def_perm_ca, def_perm_ca }); + + dds_entity_t pub, sub, pub_tp, sub_tp, wr, rd; + rd_wr_init (g_participant[0], &pub, &pub_tp, &wr, g_participant[1], &sub, &sub_tp, &rd, topic_name); + sync_writer_to_readers (g_participant[0], wr, 1, DDS_SECS (1)); + sync_reader_to_writers (g_participant[1], rd, 1, DDS_SECS (1)); + + /* Create a topic that is denied in the subscriber pp security config */ + dds_entity_t denied_pub_tp = dds_create_topic (g_participant[0], &SecurityCoreTests_Type1_desc, denied_topic_name, NULL, NULL); + CU_ASSERT_FATAL (denied_pub_tp > 0); + dds_qos_t * qos = get_default_test_qos (); + dds_entity_t denied_tp_wr = dds_create_writer (pub, denied_pub_tp, qos, NULL); + CU_ASSERT_FATAL (denied_tp_wr > 0); + + /* Check that creating denied topic for subscriber fails */ + dds_entity_t denied_sub_tp = dds_create_topic (g_participant[1], &SecurityCoreTests_Type1_desc, denied_topic_name, NULL, NULL); + CU_ASSERT_FATAL (denied_sub_tp == DDS_RETCODE_NOT_ALLOWED_BY_SECURITY); + + /* Check if communication for allowed topic is still working */ + write_read_for (wr, g_participant[1], rd, DDS_MSECS (10), false, false); + + dds_delete_qos (qos); + access_control_fini (2, (void * []) { gov_config, gov_topic_rule, sub_rules_xml, grants_pub[0], grants_sub[0], perm_config_pub, perm_config_sub, ca, id1_subj, id2_subj, id1, id2 }, 12); +} diff --git a/src/security/core/tests/authentication.c b/src/security/core/tests/authentication.c new file mode 100644 index 0000000..a09ad7d --- /dev/null +++ b/src/security/core/tests/authentication.c @@ -0,0 +1,354 @@ +/* + * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include + +#include "dds/dds.h" +#include "CUnit/Test.h" +#include "CUnit/Theory.h" + +#include "dds/version.h" +#include "dds/ddsrt/cdtors.h" +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/io.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsi/q_config.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/ddsi/q_misc.h" +#include "dds/ddsi/ddsi_xqos.h" + +#include "dds/security/dds_security_api.h" + +#include "common/config_env.h" +#include "common/authentication_wrapper.h" +#include "common/test_utils.h" +#include "common/security_config_test_utils.h" +#include "common/test_identity.h" +#include "common/cert_utils.h" + +#define ID1 TEST_IDENTITY1_CERTIFICATE +#define ID1K TEST_IDENTITY1_PRIVATE_KEY +#define ID2 TEST_IDENTITY2_CERTIFICATE +#define ID2K TEST_IDENTITY2_PRIVATE_KEY +#define ID3 TEST_IDENTITY3_CERTIFICATE +#define ID3K TEST_IDENTITY3_PRIVATE_KEY +#define CA1 TEST_IDENTITY_CA1_CERTIFICATE +#define CA1K TEST_IDENTITY_CA1_PRIVATE_KEY +#define CA2 TEST_IDENTITY_CA2_CERTIFICATE +#define CA2K TEST_IDENTITY_CA2_PRIVATE_KEY + +static const char *config = + "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}" + "" + " " + " 0" + " \\${CYCLONEDDS_PID}" + " " + " " + " " + " " + " data:,${TEST_IDENTITY_CERTIFICATE}" + " data:,${TEST_IDENTITY_PRIVATE_KEY}" + " data:,${TEST_IDENTITY_CA_CERTIFICATE}" + " ${TRUSTED_CA_DIR:+}${TRUSTED_CA_DIR}${TRUSTED_CA_DIR:+}" + " " + " " + " " + " " + " file:" COMMON_ETC_PATH("default_permissions_ca.pem") "" + " " + " " + " " + " " + " " + " " + ""; + +static const char *config_non_secure = + "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}" + "" + " " + " 0" + " \\${CYCLONEDDS_PID}" + " " + ""; + + +#define DDS_DOMAINID1 0 +#define DDS_DOMAINID2 1 + +#define DEF_PERM_CONF "file:" COMMON_ETC_PATH("default_permissions.p7s") +#define DEF_GOV_CONF "file:" COMMON_ETC_PATH("default_governance.p7s") + +static dds_entity_t g_domain1; +static dds_entity_t g_participant1; +static dds_entity_t g_pub; +static dds_entity_t g_pub_tp; +static dds_entity_t g_wr; + +static dds_entity_t g_domain2; +static dds_entity_t g_participant2; +static dds_entity_t g_sub; +static dds_entity_t g_sub_tp; +static dds_entity_t g_rd; + +static uint32_t g_topic_nr = 0; + +static void init_domain_pp (bool pp_secure, bool exp_pp_fail, + dds_domainid_t domain_id, const char *id_cert, const char * id_key, const char * id_ca, const char * gov_config, const char * perm_config, const char * trusted_ca_dir, + dds_entity_t *domain, dds_entity_t *pp) +{ + char *conf; + if (pp_secure) + { + struct kvp config_vars[] = + { + { "TEST_IDENTITY_CERTIFICATE", id_cert, 1 }, + { "TEST_IDENTITY_PRIVATE_KEY", id_key, 1 }, + { "TEST_IDENTITY_CA_CERTIFICATE", id_ca, 1 }, + { "TRUSTED_CA_DIR", trusted_ca_dir, 3 }, + { "PERMISSIONS_CONFIG", perm_config, 1 }, + { "GOVERNANCE_CONFIG", gov_config, 1 }, + { NULL, NULL, 0 } + }; + conf = ddsrt_expand_vars_sh (config, &expand_lookup_vars_env, config_vars); + CU_ASSERT_EQUAL_FATAL (expand_lookup_unmatched (config_vars), 0); + } + else + { + struct kvp config_vars[] = { { NULL, NULL, 0 } }; + conf = ddsrt_expand_vars_sh (config_non_secure, &expand_lookup_vars_env, config_vars); + CU_ASSERT_EQUAL_FATAL (expand_lookup_unmatched (config_vars), 0); + } + *domain = dds_create_domain (domain_id, conf); + *pp = dds_create_participant (domain_id, NULL, NULL); + CU_ASSERT_EQUAL_FATAL (exp_pp_fail, *pp <= 0); + ddsrt_free (conf); +} + +static void authentication_init( + bool pp1_secure, const char * id1_cert, const char * id1_key, const char * id1_ca, bool exp_pp1_fail, const char * gov_conf1, const char * perm_conf1, + bool pp2_secure, const char * id2_cert, const char * id2_key, const char * id2_ca, bool exp_pp2_fail, const char * gov_conf2, const char * perm_conf2, + const char * trusted_ca_dir) +{ + init_domain_pp (pp1_secure, exp_pp1_fail, DDS_DOMAINID1, id1_cert, id1_key, id1_ca, gov_conf1, perm_conf1, trusted_ca_dir, &g_domain1, &g_participant1); + init_domain_pp (pp2_secure, exp_pp2_fail, DDS_DOMAINID2, id2_cert, id2_key, id2_ca, gov_conf2, perm_conf2, trusted_ca_dir, &g_domain2, &g_participant2); +} + +static void authentication_fini(bool delete_pp1, bool delete_pp2, void * res[], size_t nres) +{ + if (delete_pp1) + CU_ASSERT_EQUAL_FATAL (dds_delete (g_participant1), DDS_RETCODE_OK); + if (delete_pp2) + CU_ASSERT_EQUAL_FATAL (dds_delete (g_participant2), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL (dds_delete (g_domain1), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL (dds_delete (g_domain2), DDS_RETCODE_OK); + if (res != NULL) + { + for (size_t i = 0; i < nres; i++) + ddsrt_free (res[i]); + } +} + +#define FM_CA "error: unable to get local issuer certificate" +#define FM_INVK "Failed to finalize digest context" +CU_TheoryDataPoints(ddssec_authentication, id_ca_certs) = { + CU_DataPoints(const char *, + /* */"valid ID1-ID1", + /* | */"non-trusted remote CA ID1(CA1)-ID2(CA2)", + /* | | */"valid ID1-ID3", + /* | | | */"invalid ca ID1(CA1)-ID1(CA2)", + /* | | | | */"invalid remote key ID3(K1)"), + CU_DataPoints(const char *, ID1, ID2, ID3, ID1, ID3), /* Identity for domain 2 */ + CU_DataPoints(const char *, ID1K, ID2K, ID3K, ID1K, ID1K), /* Private key for domain 2 identity */ + CU_DataPoints(const char *, CA1, CA2, CA1, CA2, CA1), /* CA for domain 2 identity */ + CU_DataPoints(bool, false, false, false, false, false), /* expect create participant1 fails */ + CU_DataPoints(bool, false, false, false, true, false), /* expect create participant2 fails */ + CU_DataPoints(bool, false, false, false, true, false), /* expect validate local failed for domain 2 */ + CU_DataPoints(const char *, NULL, NULL, NULL, FM_CA, NULL), /* expected error message for validate local failed */ + CU_DataPoints(bool, false, true, false, false, true), /* expect handshake request failed */ + CU_DataPoints(const char *, NULL, NULL, NULL, NULL, FM_INVK), /* expected error message for handshake request failed */ + CU_DataPoints(bool, false, true, false, true, true), /* expect handshake reply failed */ + CU_DataPoints(const char *, NULL, FM_CA, NULL, FM_CA, NULL) /* expected error message for handshake reply failed */ +}; +#undef FM_CA +#undef FM_INVK +/* Test the security handshake result in test-cases using identity CA's that match and do not + match (i.e. a different CA that was not used for creating the identity) the identities used + in the participants security configuration. */ +CU_Theory((const char * test_descr, const char * id2, const char *key2, const char *ca2, + bool exp_fail_pp1, bool exp_fail_pp2, + bool exp_fail_local, const char * fail_local_msg, + bool exp_fail_hs_req, const char * fail_hs_req_msg, + bool exp_fail_hs_reply, const char * fail_hs_reply_msg), + ddssec_authentication, id_ca_certs, .timeout=30) +{ + struct Handshake *hs_list; + int nhs; + print_test_msg ("running test id_ca_certs: %s\n", test_descr); + authentication_init ( + true, ID1, ID1K, CA1, exp_fail_pp1, DEF_GOV_CONF, DEF_PERM_CONF, + true, id2, key2, ca2, exp_fail_pp2, DEF_GOV_CONF, DEF_PERM_CONF, + NULL); + + // Domain 1 + validate_handshake (DDS_DOMAINID1, false, NULL, &hs_list, &nhs, DDS_SECS(2)); + for (int n = 0; n < nhs; n++) + validate_handshake_result (&hs_list[n], exp_fail_hs_req, fail_hs_req_msg, exp_fail_hs_reply, fail_hs_reply_msg); + handshake_list_fini (hs_list, nhs); + + // Domain 2 + validate_handshake (DDS_DOMAINID2, exp_fail_local, fail_local_msg, &hs_list, &nhs, DDS_SECS(2)); + for (int n = 0; n < nhs; n++) + validate_handshake_result (&hs_list[n], exp_fail_hs_req, fail_hs_req_msg, exp_fail_hs_reply, fail_hs_reply_msg); + handshake_list_fini (hs_list, nhs); + + authentication_fini (!exp_fail_pp1, !exp_fail_pp2, NULL, 0); +} + +CU_TheoryDataPoints(ddssec_authentication, trusted_ca_dir) = { + CU_DataPoints(const char *, "", ".", "/nonexisting", NULL), + CU_DataPoints(bool, false, false, true, false) +}; +/* Test correct and incorrect values for the trusted CA directory in the + authentication plugin configuration */ +CU_Theory((const char * ca_dir, bool exp_fail), ddssec_authentication, trusted_ca_dir) +{ + print_test_msg ("Testing custom CA dir: %s\n", ca_dir); + authentication_init ( + true, ID1, ID1K, CA1, exp_fail, DEF_GOV_CONF, DEF_PERM_CONF, + true, ID1, ID1K, CA1, exp_fail, DEF_GOV_CONF, DEF_PERM_CONF, + ca_dir); + if (!exp_fail) + { + validate_handshake_nofail (DDS_DOMAINID1, DDS_SECS (2)); + validate_handshake_nofail (DDS_DOMAINID2, DDS_SECS (2)); + } + authentication_fini (!exp_fail, !exp_fail, NULL, 0); +} + +#define S(n) (n) +#define M(n) (S(n)*60) +#define H(n) (M(n)*60) +#define D(n) (H(n)*24) +CU_TheoryDataPoints(ddssec_authentication, expired_cert) = { + CU_DataPoints(const char *, + /* */"all valid 1d", + /* | */"ca expired", + /* | | */"id1 expired", + /* | | | */"id2 expired", + /* | | | | */"ca and id1 1min valid", + /* | | | | | */"id1 and id2 1s valid, delay 1100ms", + /* | | | | | | */"id1 valid after 1s, delay 1100ms", + /* | | | | | | | */"id1 expires during session"), + CU_DataPoints(int32_t, 0, -M(1), 0, 0, 0, 0, 0, 0 ), /* CA1 not before */ + CU_DataPoints(int32_t, D(1), 0, D(1), D(1), M(1), D(1), D(1), D(1) ), /* CA1 not after (offset from local time) */ + CU_DataPoints(int32_t, 0, 0, -D(1), 0, 0, 0, S(1), 0 ), /* ID1 not before (offset from local time) */ + CU_DataPoints(int32_t, D(1), D(1), 0, D(1), M(1), S(1), D(1), S(4) ), /* ID1 not after (offset from local time) */ + CU_DataPoints(bool, false, true, true, false, false, true, false, false ), /* expect validate local ID1 fail */ + CU_DataPoints(int32_t, 0, 0, 0, -D(1), 0, 0, 0, 0 ), /* ID2 not before (offset from local time) */ + CU_DataPoints(int32_t, D(1), D(1), D(1), 0, D(1), S(1), D(1), D(1) ), /* ID2 not after (offset from local time) */ + CU_DataPoints(bool, false, true, false, true, false, true, false, false ), /* expect validate local ID2 fail */ + CU_DataPoints(uint32_t, 0, 0, 0, 0, 0, 1100, 1100, 0 ), /* delay (ms) after generating certificate */ + CU_DataPoints(uint32_t, 1, 0, 0, 0, 1, 0, 1, 10000 ), /* write/read data during x ms */ + CU_DataPoints(bool, false, false, false, false, false, false, false, true ), /* expect read data failure */ +}; +/* Test the security handshake result and check communication for scenarios using + valid identities, identities that are expired and identities that are not yet valid. + A test case using an identity that expires during the test is also included. */ +CU_Theory( + (const char * test_descr, int32_t ca_not_before, int32_t ca_not_after, + int32_t id1_not_before, int32_t id1_not_after, bool id1_local_fail, + int32_t id2_not_before, int32_t id2_not_after, bool id2_local_fail, + uint32_t delay, uint32_t write_read_dur, bool exp_read_fail), + ddssec_authentication, expired_cert, .timeout=30) +{ + print_test_msg ("running test expired_cert: %s\n", test_descr); + + char topic_name[100]; + create_topic_name("ddssec_authentication_", g_topic_nr++, topic_name, sizeof (topic_name)); + + print_test_msg ("generate ids (id1: %d-%d, id2: %d-%d):\n", id1_not_before, id1_not_after, id2_not_before, id2_not_after); + char *ca, *id1, *id2, *id1_subj, *id2_subj; + ca = generate_ca ("ca1", CA1K, ca_not_before, ca_not_after); + id1 = generate_identity (ca, CA1K, "id1", ID1K, id1_not_before, id1_not_after, &id1_subj); + id2 = generate_identity (ca, CA1K, "id2", ID1K, id2_not_before, id2_not_after, &id2_subj); + dds_sleepfor (DDS_MSECS (delay)); + + char * grants[] = { + get_permissions_default_grant ("id1", id1_subj, topic_name), + get_permissions_default_grant ("id2", id2_subj, topic_name) }; + char * perm_config = get_permissions_config (grants, 2, true); + authentication_init ( + true, id1, ID1K, ca, id1_local_fail, DEF_GOV_CONF, perm_config, + true, id2, ID1K, ca, id2_local_fail, DEF_GOV_CONF, perm_config, + NULL); + validate_handshake (DDS_DOMAINID1, id1_local_fail, NULL, NULL, NULL, DDS_SECS(2)); + validate_handshake (DDS_DOMAINID2, id2_local_fail, NULL, NULL, NULL, DDS_SECS(2)); + if (write_read_dur > 0) + { + rd_wr_init (g_participant1, &g_pub, &g_pub_tp, &g_wr, g_participant2, &g_sub, &g_sub_tp, &g_rd, topic_name); + sync_writer_to_readers(g_participant1, g_wr, 1, DDS_SECS(2)); + write_read_for (g_wr, g_participant2, g_rd, DDS_MSECS (write_read_dur), false, exp_read_fail); + } + authentication_fini (!id1_local_fail, !id2_local_fail, (void * []){ grants[0], grants[1], perm_config, ca, id1_subj, id2_subj, id1, id2 }, 8); +} +#undef D +#undef H +#undef M + +/* Test communication for a non-secure participant with a secure participant that + allows unauthenticated nodes in its governance configuration. Samples for a secured + topic should not be received by a reader in the non-secure participant; samples for + a non-secure topic should. */ +CU_Test(ddssec_authentication, unauthenticated_pp) +{ + char topic_name_secure[100]; + char topic_name_plain[100]; + create_topic_name ("ddssec_authentication_secure_", g_topic_nr++, topic_name_secure, sizeof (topic_name_secure)); + create_topic_name ("ddssec_authentication_plain_", g_topic_nr++, topic_name_plain, sizeof (topic_name_plain)); + + /* create ca and id1 cert that will not expire during this test */ + char *ca, *id1, *id1_subj; + ca = generate_ca ("ca1", TEST_IDENTITY_CA1_PRIVATE_KEY, 0, 3600); + id1 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id1", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id1_subj); + + char * grants[] = { get_permissions_default_grant ("id1", id1_subj, topic_name_secure) }; + char * perm_config = get_permissions_config (grants, 1, true); + + char * topic_rule_sec = get_governance_topic_rule (topic_name_secure, true, true, true, true, PK_E, BPK_N); + char * topic_rule_plain = get_governance_topic_rule (topic_name_plain, false, false, false, false, PK_N, BPK_N); + char * gov_topic_rules; + ddsrt_asprintf(&gov_topic_rules, "%s%s", topic_rule_sec, topic_rule_plain); + char * gov_config = get_governance_config (true, true, PK_N, PK_N, PK_N, gov_topic_rules, true); + + authentication_init ( + true, id1, TEST_IDENTITY1_PRIVATE_KEY, ca, false, gov_config, perm_config, + false, NULL, NULL, NULL, false, NULL, NULL, + NULL); + + print_test_msg ("writing sample for plain topic\n"); + dds_entity_t pub, sub, pub_tp, sub_tp, wr, rd; + rd_wr_init (g_participant1, &pub, &pub_tp, &wr, g_participant2, &sub, &sub_tp, &rd, topic_name_plain); + sync_writer_to_readers(g_participant1, wr, 1, DDS_SECS(5)); + write_read_for (wr, g_participant2, rd, DDS_MSECS (10), false, false); + + print_test_msg ("writing sample for secured topic\n"); + dds_entity_t spub, ssub, spub_tp, ssub_tp, swr, srd; + rd_wr_init (g_participant1, &spub, &spub_tp, &swr, g_participant2, &ssub, &ssub_tp, &srd, topic_name_secure); + sync_writer_to_readers(g_participant1, swr, 0, DDS_SECS(2)); + write_read_for (swr, g_participant2, srd, DDS_MSECS (10), false, true); + + authentication_fini (true, true, (void * []) { gov_config, gov_topic_rules, topic_rule_sec, topic_rule_plain, grants[0], perm_config, ca, id1_subj, id1 }, 9); +} + diff --git a/src/security/core/tests/common/access_control_wrapper.c b/src/security/core/tests/common/access_control_wrapper.c new file mode 100644 index 0000000..ac9cbd9 --- /dev/null +++ b/src/security/core/tests/common/access_control_wrapper.c @@ -0,0 +1,985 @@ +/* + * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include "CUnit/Test.h" +#include "dds/dds.h" +#include "dds/ddsrt/circlist.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "access_control_wrapper.h" + +int init_access_control(const char *argument, void **context, struct ddsi_domaingv *gv); +int finalize_access_control(void *context); + +enum ac_plugin_mode { + PLUGIN_MODE_ALL_OK, + PLUGIN_MODE_WRAPPED, + PLUGIN_MODE_NOT_ALLOWED, + PLUGIN_MODE_MISSING_FUNC, +}; + +enum ac_plugin_not_allowed { + NOT_ALLOWED_ID_LOCAL_PP, + NOT_ALLOWED_ID_LOCAL_TOPIC, + NOT_ALLOWED_ID_LOCAL_WRITER, + NOT_ALLOWED_ID_LOCAL_READER, + NOT_ALLOWED_ID_LOCAL_PERM, + NOT_ALLOWED_ID_REMOTE_PP, + NOT_ALLOWED_ID_REMOTE_TOPIC, + NOT_ALLOWED_ID_REMOTE_WRITER, + NOT_ALLOWED_ID_REMOTE_READER, + NOT_ALLOWED_ID_REMOTE_READER_RELAY_ONLY, + NOT_ALLOWED_ID_REMOTE_PERM, +}; + +#define NOT_ALLOWED_LOCAL_PP (1u << NOT_ALLOWED_ID_LOCAL_PP) +#define NOT_ALLOWED_LOCAL_TOPIC (1u << NOT_ALLOWED_ID_LOCAL_TOPIC) +#define NOT_ALLOWED_LOCAL_WRITER (1u << NOT_ALLOWED_ID_LOCAL_WRITER) +#define NOT_ALLOWED_LOCAL_READER (1u << NOT_ALLOWED_ID_LOCAL_READER) +#define NOT_ALLOWED_LOCAL_PERM (1u << NOT_ALLOWED_ID_LOCAL_PERM) +#define NOT_ALLOWED_REMOTE_PP (1u << NOT_ALLOWED_ID_REMOTE_PP) +#define NOT_ALLOWED_REMOTE_TOPIC (1u << NOT_ALLOWED_ID_REMOTE_TOPIC) +#define NOT_ALLOWED_REMOTE_WRITER (1u << NOT_ALLOWED_ID_REMOTE_WRITER) +#define NOT_ALLOWED_REMOTE_READER (1u << NOT_ALLOWED_ID_REMOTE_READER) +#define NOT_ALLOWED_REMOTE_READER_RELAY_ONLY (1u << NOT_ALLOWED_ID_REMOTE_READER_RELAY_ONLY) +#define NOT_ALLOWED_REMOTE_PERM (1u << NOT_ALLOWED_ID_REMOTE_PERM) + +struct returns_log_data { + struct ddsrt_circlist_elem e; + void * obj; +}; + + +/** + * Implementation structure for storing encapsulated members of the instance + * while giving only the interface definition to user + */ +struct dds_security_access_control_impl { + dds_security_access_control base; + dds_security_access_control *instance; + enum ac_plugin_mode mode; + uint32_t not_allowed_mask; + ddsrt_mutex_t returns_log_lock; + struct ddsrt_circlist returns_log; + bool invalid_return; +}; + + +static void init_returns_log(struct dds_security_access_control_impl *impl) +{ + ddsrt_mutex_init (&impl->returns_log_lock); + ddsrt_circlist_init (&impl->returns_log); + impl->invalid_return = false; +} + +static void fini_returns_log(struct dds_security_access_control_impl *impl) +{ + ddsrt_mutex_lock (&impl->returns_log_lock); + while (!ddsrt_circlist_isempty (&impl->returns_log)) + { + struct ddsrt_circlist_elem *list_elem = ddsrt_circlist_oldest (&impl->returns_log); + ddsrt_circlist_remove (&impl->returns_log, list_elem); + ddsrt_free (list_elem); + } + ddsrt_mutex_unlock (&impl->returns_log_lock); + ddsrt_mutex_destroy (&impl->returns_log_lock); +} + +static void register_return_obj (struct dds_security_access_control_impl * impl, void * obj) +{ + assert(impl->mode == PLUGIN_MODE_WRAPPED); + ddsrt_mutex_lock (&impl->returns_log_lock); + struct returns_log_data * attr_data = ddsrt_malloc (sizeof (*attr_data)); + attr_data->obj = obj; + ddsrt_circlist_append(&impl->returns_log, &attr_data->e); + ddsrt_mutex_unlock (&impl->returns_log_lock); +} + +static struct ddsrt_circlist_elem *find_return_obj_data (struct dds_security_access_control_impl * impl, void * obj) +{ + struct ddsrt_circlist_elem *elem0 = ddsrt_circlist_oldest (&impl->returns_log), *elem = elem0; + if (elem != NULL) + { + do + { + struct returns_log_data *data = DDSRT_FROM_CIRCLIST (struct returns_log_data, e, elem); + if (data->obj == obj) + return elem; + elem = elem->next; + } while (elem != elem0); + } + return NULL; +} + +static void unregister_return_obj (struct dds_security_access_control_impl * impl, void * obj) +{ + struct ddsrt_circlist_elem *elem; + assert(impl->mode == PLUGIN_MODE_WRAPPED); + ddsrt_mutex_lock (&impl->returns_log_lock); + if ((elem = find_return_obj_data (impl, obj)) != NULL) + { + ddsrt_circlist_remove (&impl->returns_log, elem); + ddsrt_free (elem); + } + else + { + impl->invalid_return = true; + printf ("invalid return %p\n", obj); + } + ddsrt_mutex_unlock (&impl->returns_log_lock); +} + +static bool all_returns_valid (struct dds_security_access_control_impl * impl) +{ + assert(impl->mode == PLUGIN_MODE_WRAPPED); + ddsrt_mutex_lock (&impl->returns_log_lock); + bool valid = !impl->invalid_return && ddsrt_circlist_isempty (&impl->returns_log); + ddsrt_mutex_unlock (&impl->returns_log_lock); + return valid; +} + +static DDS_Security_PermissionsHandle validate_local_permissions( + dds_security_access_control *instance, + const dds_security_authentication *auth_plugin, + const DDS_Security_IdentityHandle identity, + const DDS_Security_DomainId domain_id, + const DDS_Security_Qos *participant_qos, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_LOCAL_PERM) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: validate_local_permissions"); + return 0; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + { + DDS_Security_PermissionsHandle handle = impl->instance->validate_local_permissions(impl->instance, auth_plugin, identity, domain_id, participant_qos, ex); + return handle; + } + + default: + return 1; + } +} + +static DDS_Security_PermissionsHandle validate_remote_permissions( + dds_security_access_control *instance, + const dds_security_authentication *auth_plugin, + const DDS_Security_IdentityHandle local_identity_handle, + const DDS_Security_IdentityHandle remote_identity_handle, + const DDS_Security_PermissionsToken *remote_permissions_token, + const DDS_Security_AuthenticatedPeerCredentialToken *remote_credential_token, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_REMOTE_PERM) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: validate_remote_permissions"); + return 0; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + { + DDS_Security_PermissionsHandle handle = impl->instance->validate_remote_permissions(impl->instance, auth_plugin, local_identity_handle, remote_identity_handle, + remote_permissions_token, remote_credential_token, ex); + return handle; + } + + default: + return 0; + } +} + +static DDS_Security_boolean check_create_participant( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_Qos *participant_qos, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_LOCAL_PP) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_create_participant"); + return false; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + return impl->instance->check_create_participant(impl->instance, permissions_handle, domain_id, participant_qos, ex); + + default: + return true; + } +} + +static DDS_Security_boolean check_create_datawriter( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const char *topic_name, + const DDS_Security_Qos *writer_qos, + const DDS_Security_PartitionQosPolicy *partition, + const DDS_Security_DataTags *data_tag, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_LOCAL_WRITER) + { + if (topic_name && strncmp (topic_name, AC_WRAPPER_TOPIC_PREFIX, strlen (AC_WRAPPER_TOPIC_PREFIX)) == 0) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_create_datawriter"); + return false; + } + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + return impl->instance->check_create_datawriter(impl->instance, permissions_handle, domain_id, topic_name, writer_qos, partition, data_tag, ex); + + default: + return true; + } +} + +static DDS_Security_boolean check_create_datareader( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const char *topic_name, + const DDS_Security_Qos *reader_qos, + const DDS_Security_PartitionQosPolicy *partition, + const DDS_Security_DataTags *data_tag, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_LOCAL_READER) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_create_datareader"); + return false; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + return impl->instance->check_create_datareader(impl->instance, permissions_handle, domain_id, topic_name, reader_qos, partition, data_tag, ex); + + default: + return true; + } +} + +static DDS_Security_boolean check_create_topic( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const char *topic_name, + const DDS_Security_Qos *qos, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_LOCAL_TOPIC) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_create_topic"); + return false; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + return impl->instance->check_create_topic(impl->instance, permissions_handle, domain_id, topic_name, qos, ex); + + default: + return true; + } +} + +static DDS_Security_boolean check_local_datawriter_register_instance( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_Entity *writer, + const DDS_Security_DynamicData *key, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->check_local_datawriter_register_instance(impl->instance, permissions_handle, writer, key, ex); + + default: + return true; + } +} + +static DDS_Security_boolean check_local_datawriter_dispose_instance( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_Entity *writer, + const DDS_Security_DynamicData key, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->check_local_datawriter_dispose_instance(impl->instance, permissions_handle, writer, key, ex); + + default: + return true; + } +} + +static DDS_Security_boolean check_remote_participant( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_ParticipantBuiltinTopicDataSecure *participant_data, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_REMOTE_PP) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_remote_participant"); + return false; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + return impl->instance->check_remote_participant(impl->instance, permissions_handle, domain_id, participant_data, ex); + + default: + return true; + } +} + +static DDS_Security_boolean check_remote_datawriter( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_PublicationBuiltinTopicDataSecure *publication_data, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_REMOTE_WRITER) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_remote_datawriter"); + return false; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + return impl->instance->check_remote_datawriter(impl->instance, permissions_handle, domain_id, publication_data, ex); + + default: + return true; + } +} + +static DDS_Security_boolean check_remote_datareader( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_SubscriptionBuiltinTopicDataSecure *subscription_data, + DDS_Security_boolean *relay_only, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_REMOTE_READER) + { + if (subscription_data->topic_name && strncmp (subscription_data->topic_name, AC_WRAPPER_TOPIC_PREFIX, strlen (AC_WRAPPER_TOPIC_PREFIX)) == 0) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_remote_datareader"); + return false; + } + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + { + bool ret; + if ((ret = impl->instance->check_remote_datareader(impl->instance, permissions_handle, domain_id, subscription_data, relay_only, ex))) + { + /* Only relay_only for the user reader, not the builtin ones. */ + if (impl->mode == PLUGIN_MODE_NOT_ALLOWED && impl->not_allowed_mask & NOT_ALLOWED_REMOTE_READER_RELAY_ONLY) + { + if (subscription_data->topic_name && strncmp (subscription_data->topic_name, AC_WRAPPER_TOPIC_PREFIX, strlen (AC_WRAPPER_TOPIC_PREFIX)) == 0) + *relay_only = true; + } + } + return ret; + } + + default: + *relay_only = false; + return true; + } +} + +static DDS_Security_boolean check_remote_topic( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_DomainId domain_id, + const DDS_Security_TopicBuiltinTopicData *topic_data, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_NOT_ALLOWED: + if (impl->not_allowed_mask & NOT_ALLOWED_REMOTE_TOPIC) + { + ex->code = 1; + ex->message = ddsrt_strdup ("not_allowed: check_remote_topic"); + return false; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + return impl->instance->check_remote_topic(impl->instance, permissions_handle, domain_id, topic_data, ex); + + default: + return true; + } +} + +static DDS_Security_boolean check_local_datawriter_match( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle writer_permissions_handle, + const DDS_Security_PermissionsHandle reader_permissions_handle, + const DDS_Security_PublicationBuiltinTopicDataSecure *publication_data, + const DDS_Security_SubscriptionBuiltinTopicDataSecure *subscription_data, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->check_local_datawriter_match(impl->instance, writer_permissions_handle, reader_permissions_handle, publication_data, subscription_data, ex); + + default: + return true; + } +} + +static DDS_Security_boolean check_local_datareader_match( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle reader_permissions_handle, + const DDS_Security_PermissionsHandle writer_permissions_handle, + const DDS_Security_SubscriptionBuiltinTopicDataSecure *subscription_data, + const DDS_Security_PublicationBuiltinTopicDataSecure *publication_data, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->check_local_datareader_match(impl->instance, reader_permissions_handle, writer_permissions_handle, subscription_data, publication_data, ex); + + default: + return true; + } +} + +static DDS_Security_boolean check_remote_datawriter_register_instance( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_Entity *reader, + const DDS_Security_InstanceHandle publication_handle, + const DDS_Security_DynamicData key, + const DDS_Security_InstanceHandle instance_handle, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->check_remote_datawriter_register_instance(impl->instance, permissions_handle, reader, publication_handle, key, instance_handle, ex); + + default: + return true; + } +} + +static DDS_Security_boolean check_remote_datawriter_dispose_instance( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const DDS_Security_Entity *reader, + const DDS_Security_InstanceHandle publication_handle, + const DDS_Security_DynamicData key, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->check_remote_datawriter_dispose_instance(impl->instance, permissions_handle, reader, publication_handle, key, ex); + + default: + return true; + } +} + +static DDS_Security_boolean get_permissions_token( + dds_security_access_control *instance, + DDS_Security_PermissionsToken *permissions_token, + const DDS_Security_PermissionsHandle handle, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + register_return_obj (impl, (void*) permissions_token); + /* fall through */ + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->get_permissions_token(impl->instance, permissions_token, handle, ex); + + default: + memset(permissions_token, 0, sizeof(*permissions_token)); + permissions_token->class_id = ddsrt_strdup (""); + return true; + } +} + +static DDS_Security_boolean get_permissions_credential_token( + dds_security_access_control *instance, + DDS_Security_PermissionsCredentialToken *permissions_credential_token, + const DDS_Security_PermissionsHandle handle, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + register_return_obj (impl, (void*) permissions_credential_token); + /* fall through */ + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->get_permissions_credential_token(impl->instance, permissions_credential_token, handle, ex); + + default: + return true; + } +} + +static DDS_Security_boolean set_listener( + dds_security_access_control *instance, + const dds_security_access_control_listener *listener, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->set_listener (impl->instance, listener, ex); + + default: + return true; + } +} + +static DDS_Security_boolean return_permissions_token( + dds_security_access_control *instance, + const DDS_Security_PermissionsToken *token, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + unregister_return_obj (impl, (void*) token); + /* fall through */ + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->return_permissions_token (impl->instance, token, ex); + + default: + ddsrt_free (token->class_id); + return true; + } +} + +static DDS_Security_boolean return_permissions_credential_token( + dds_security_access_control *instance, + const DDS_Security_PermissionsCredentialToken *permissions_credential_token, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + unregister_return_obj (impl, (void*) permissions_credential_token); + /* fall through */ + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->return_permissions_credential_token(impl->instance, permissions_credential_token, ex); + + default: + return true; + } +} + +static DDS_Security_boolean get_participant_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + DDS_Security_ParticipantSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + register_return_obj (impl, (void*) attributes); + /* fall through */ + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->get_participant_sec_attributes(impl->instance, permissions_handle, attributes, ex); + + default: + return true; + } +} + +static DDS_Security_boolean get_topic_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const char *topic_name, + DDS_Security_TopicSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + register_return_obj (impl, (void*) attributes); + /* fall through */ + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->get_topic_sec_attributes(impl->instance, permissions_handle, topic_name, attributes, ex); + + default: + return true; + } +} + +static DDS_Security_boolean get_datawriter_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const char *topic_name, + const DDS_Security_PartitionQosPolicy *partition, + const DDS_Security_DataTagQosPolicy *data_tag, + DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + register_return_obj (impl, (void*) attributes); + /* fall through */ + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->get_datawriter_sec_attributes(impl->instance, permissions_handle, topic_name, partition, data_tag, attributes, ex); + + default: + return true; + } +} + +static DDS_Security_boolean get_datareader_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + const char *topic_name, + const DDS_Security_PartitionQosPolicy *partition, + const DDS_Security_DataTagQosPolicy *data_tag, + DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + register_return_obj (impl, (void*) attributes); + /* fall through */ + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->get_datareader_sec_attributes(impl->instance, permissions_handle, topic_name, partition, data_tag, attributes, ex); + + default: + return true; + } +} + +static DDS_Security_boolean return_participant_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_ParticipantSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + unregister_return_obj (impl, (void*) attributes); + /* fall through */ + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->return_participant_sec_attributes(impl->instance, attributes, ex); + + default: + return true; + } +} + +static DDS_Security_boolean return_topic_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_TopicSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + unregister_return_obj (impl, (void*) attributes); + /* fall through */ + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->return_topic_sec_attributes(impl->instance, attributes, ex); + + default: + return true; + } +} + +static DDS_Security_boolean return_datawriter_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + unregister_return_obj (impl, (void*) attributes); + /* fall through */ + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->return_datawriter_sec_attributes(impl->instance, attributes, ex); + + default: + return true; + } +} + +static DDS_Security_boolean return_datareader_sec_attributes( + dds_security_access_control *instance, + const DDS_Security_EndpointSecurityAttributes *attributes, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + unregister_return_obj (impl, (void*) attributes); + /* fall through */ + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->return_datareader_sec_attributes(impl->instance, attributes, ex); + + default: + return true; + } +} + +static DDS_Security_boolean return_permissions_handle( + dds_security_access_control *instance, + const DDS_Security_PermissionsHandle permissions_handle, + DDS_Security_SecurityException *ex) +{ + struct dds_security_access_control_impl *impl = (struct dds_security_access_control_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_NOT_ALLOWED: + return impl->instance->return_permissions_handle(impl->instance, permissions_handle, ex); + + default: + return true; + } +} + +static struct dds_security_access_control_impl * init_test_access_control_common(const char *argument, bool wrapped, struct ddsi_domaingv *gv) +{ + struct dds_security_access_control_impl *impl = ddsrt_malloc(sizeof(*impl)); + memset(impl, 0, sizeof(*impl)); + + if (wrapped) + { + if (init_access_control(argument, (void **)&impl->instance, gv) != DDS_SECURITY_SUCCESS) + return NULL; + } + + impl->base.validate_local_permissions = &validate_local_permissions; + impl->base.validate_remote_permissions = &validate_remote_permissions; + impl->base.check_create_participant = &check_create_participant; + impl->base.check_create_datawriter = &check_create_datawriter; + impl->base.check_create_datareader = &check_create_datareader; + impl->base.check_create_topic = &check_create_topic; + impl->base.check_local_datawriter_register_instance = &check_local_datawriter_register_instance; + impl->base.check_local_datawriter_dispose_instance = &check_local_datawriter_dispose_instance; + impl->base.check_remote_participant = &check_remote_participant; + impl->base.check_remote_datawriter = &check_remote_datawriter; + impl->base.check_remote_datareader = &check_remote_datareader; + impl->base.check_remote_topic = &check_remote_topic; + impl->base.check_local_datawriter_match = &check_local_datawriter_match; + impl->base.check_local_datareader_match = &check_local_datareader_match; + impl->base.check_remote_datawriter_register_instance = &check_remote_datawriter_register_instance; + impl->base.check_remote_datawriter_dispose_instance = &check_remote_datawriter_dispose_instance; + impl->base.get_permissions_token = &get_permissions_token; + impl->base.get_permissions_credential_token = &get_permissions_credential_token; + impl->base.set_listener = &set_listener; + impl->base.return_permissions_token = &return_permissions_token; + impl->base.return_permissions_credential_token = &return_permissions_credential_token; + impl->base.get_participant_sec_attributes = &get_participant_sec_attributes; + impl->base.get_topic_sec_attributes = &get_topic_sec_attributes; + impl->base.get_datawriter_sec_attributes = &get_datawriter_sec_attributes; + impl->base.get_datareader_sec_attributes = &get_datareader_sec_attributes; + impl->base.return_participant_sec_attributes = &return_participant_sec_attributes; + impl->base.return_topic_sec_attributes = &return_topic_sec_attributes; + impl->base.return_datawriter_sec_attributes = &return_datawriter_sec_attributes; + impl->base.return_datareader_sec_attributes = &return_datareader_sec_attributes; + impl->base.return_permissions_handle = &return_permissions_handle; + return impl; +} + +static int finalize_test_access_control_common(struct dds_security_access_control_impl * impl, bool wrapped) +{ + int32_t ret; + if (wrapped && (ret = finalize_access_control(impl->instance)) != DDS_SECURITY_SUCCESS) + return ret; + ddsrt_free(impl); + return DDS_SECURITY_SUCCESS; +} + +int init_test_access_control_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + DDSRT_UNUSED_ARG(context); + struct dds_security_access_control_impl *impl = init_test_access_control_common(argument, false, gv); + impl->mode = PLUGIN_MODE_ALL_OK; + *context = impl; + return 0; +} + +int finalize_test_access_control_all_ok(void *context) +{ + struct dds_security_access_control_impl* impl = (struct dds_security_access_control_impl*) context; + assert(impl->mode == PLUGIN_MODE_ALL_OK); + return finalize_test_access_control_common(impl, false); +} + +int init_test_access_control_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + struct dds_security_access_control_impl *impl = init_test_access_control_common(argument, true, gv); + if (!impl) + return DDS_SECURITY_FAILED; + impl->mode = PLUGIN_MODE_WRAPPED; + init_returns_log (impl); + *context = impl; + return DDS_SECURITY_SUCCESS; +} + +int finalize_test_access_control_wrapped(void *context) +{ + struct dds_security_access_control_impl* impl = (struct dds_security_access_control_impl*) context; + assert (impl->mode == PLUGIN_MODE_WRAPPED); + bool returns_valid = all_returns_valid (impl); + fini_returns_log (impl); + printf("returns result (impl %p): %s\n", impl, returns_valid ? "all valid" : "invalid"); + CU_ASSERT_FATAL (returns_valid); + return finalize_test_access_control_common (impl, true); +} + +int init_test_access_control_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + DDSRT_UNUSED_ARG(context); + struct dds_security_access_control_impl *impl = init_test_access_control_common(argument, false, gv); + impl->base.check_create_datareader = NULL; + impl->mode = PLUGIN_MODE_MISSING_FUNC; + *context = impl; + return 0; +} + +int finalize_test_access_control_missing_func(void *context) +{ + struct dds_security_access_control_impl* impl = (struct dds_security_access_control_impl*) context; + assert(impl->mode == PLUGIN_MODE_MISSING_FUNC); + return finalize_test_access_control_common(impl, false); +} + +#define INIT_NOT_ALLOWED(name_, mask_) \ + int init_test_access_control_##name_ (const char *argument, void **context, struct ddsi_domaingv *gv) \ + { \ + DDSRT_UNUSED_ARG(context); \ + struct dds_security_access_control_impl *impl = init_test_access_control_common(argument, true, gv); \ + impl->mode = PLUGIN_MODE_NOT_ALLOWED; \ + impl->not_allowed_mask = mask_; \ + *context = impl; \ + return 0; \ + } + +INIT_NOT_ALLOWED(local_participant_not_allowed, NOT_ALLOWED_LOCAL_PP) +INIT_NOT_ALLOWED(local_topic_not_allowed, NOT_ALLOWED_LOCAL_TOPIC) +INIT_NOT_ALLOWED(local_writer_not_allowed, NOT_ALLOWED_LOCAL_WRITER) +INIT_NOT_ALLOWED(local_reader_not_allowed, NOT_ALLOWED_LOCAL_READER) +INIT_NOT_ALLOWED(local_permissions_not_allowed, NOT_ALLOWED_LOCAL_PERM) +INIT_NOT_ALLOWED(remote_participant_not_allowed, NOT_ALLOWED_REMOTE_PP) +INIT_NOT_ALLOWED(remote_topic_not_allowed, NOT_ALLOWED_REMOTE_TOPIC) +INIT_NOT_ALLOWED(remote_writer_not_allowed, NOT_ALLOWED_REMOTE_WRITER) +INIT_NOT_ALLOWED(remote_reader_not_allowed, NOT_ALLOWED_REMOTE_READER) +INIT_NOT_ALLOWED(remote_reader_relay_only, NOT_ALLOWED_REMOTE_READER_RELAY_ONLY) +INIT_NOT_ALLOWED(remote_permissions_not_allowed, NOT_ALLOWED_REMOTE_PERM) + +int finalize_test_access_control_not_allowed(void *context) +{ + struct dds_security_access_control_impl* impl = (struct dds_security_access_control_impl*) context; + assert(impl->mode == PLUGIN_MODE_NOT_ALLOWED); + return finalize_test_access_control_common(impl, true); +} diff --git a/src/security/core/tests/common/access_control_wrapper.h b/src/security/core/tests/common/access_control_wrapper.h new file mode 100644 index 0000000..a876311 --- /dev/null +++ b/src/security/core/tests/common/access_control_wrapper.h @@ -0,0 +1,54 @@ +/* + * Copyright(c) 2006 to 2020 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 SECURITY_CORE_TEST_ACCESS_CONTROL_WRAPPER_H_ +#define SECURITY_CORE_TEST_ACCESS_CONTROL_WRAPPER_H_ + +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/access_control_wrapper_export.h" + +/* Topic name prefix expected by this wrapper when running in not-allowed + mode. This prefix is used to exclude built-in topics from being disallowed. */ +#define AC_WRAPPER_TOPIC_PREFIX "ddssec_access_control_" + +struct dds_security_access_control_impl; + +/* Init in all-ok mode: all functions return success without calling the actual plugin */ +SECURITY_EXPORT int init_test_access_control_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_access_control_all_ok(void *context); + +/* Init in missing function mode: one of the function pointers is null */ +SECURITY_EXPORT int init_test_access_control_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_access_control_missing_func(void *context); + +SECURITY_EXPORT int init_test_access_control_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_access_control_wrapped(void *context); + +/* Init functions for not-allowed modes */ +#define INIT_NOT_ALLOWED_DECL(name_) \ + SECURITY_EXPORT int init_test_access_control_##name_ (const char *argument, void **context, struct ddsi_domaingv *gv); + +INIT_NOT_ALLOWED_DECL(local_participant_not_allowed) +INIT_NOT_ALLOWED_DECL(local_topic_not_allowed) +INIT_NOT_ALLOWED_DECL(local_writer_not_allowed) +INIT_NOT_ALLOWED_DECL(local_reader_not_allowed) +INIT_NOT_ALLOWED_DECL(local_permissions_not_allowed) +INIT_NOT_ALLOWED_DECL(remote_participant_not_allowed) +INIT_NOT_ALLOWED_DECL(remote_topic_not_allowed) +INIT_NOT_ALLOWED_DECL(remote_writer_not_allowed) +INIT_NOT_ALLOWED_DECL(remote_reader_not_allowed) +INIT_NOT_ALLOWED_DECL(remote_reader_relay_only) +INIT_NOT_ALLOWED_DECL(remote_permissions_not_allowed) + +SECURITY_EXPORT int finalize_test_access_control_not_allowed(void *context); + +#endif /* SECURITY_CORE_TEST_ACCESS_CONTROL_WRAPPER_H_ */ diff --git a/src/security/core/tests/common/authentication_wrapper.c b/src/security/core/tests/common/authentication_wrapper.c new file mode 100644 index 0000000..693ac11 --- /dev/null +++ b/src/security/core/tests/common/authentication_wrapper.c @@ -0,0 +1,582 @@ +/* + * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include "dds/dds.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "authentication_wrapper.h" +#include "test_identity.h" +#include "plugin_wrapper_msg_q.h" + +int init_authentication(const char *argument, void **context, struct ddsi_domaingv *gv); +int finalize_authentication(void *context); + +enum auth_plugin_mode { + PLUGIN_MODE_ALL_OK, + PLUGIN_MODE_WRAPPED, + PLUGIN_MODE_MISSING_FUNC, + PLUGIN_MODE_INIT_FAIL +}; + +/** + * Implementation structure for storing encapsulated members of the instance + * while giving only the interface definition to user + */ +struct dds_security_authentication_impl +{ + dds_security_authentication base; + dds_security_authentication *instance; + struct message_queue msg_queue; + enum auth_plugin_mode mode; +}; + +static struct dds_security_authentication_impl **auth_impl; +static size_t auth_impl_idx = 0; +static size_t auth_impl_use = 0; + +static const char *test_identity_certificate = TEST_IDENTITY_CERTIFICATE_DUMMY; +static const char *test_private_key = TEST_IDENTITY_PRIVATE_KEY_DUMMY; +static const char *test_ca_certificate = TEST_IDENTITY_CA_CERTIFICATE_DUMMY; + +static DDS_Security_ValidationResult_t test_validate_local_identity_all_ok( + DDS_Security_GUID_t *adjusted_participant_guid, + const DDS_Security_Qos *participant_qos, + const DDS_Security_GUID_t *candidate_participant_guid) +{ + DDS_Security_ValidationResult_t result = DDS_SECURITY_VALIDATION_OK; + char *identity_ca = NULL; + char *identity_certificate = NULL; + char *private_key = NULL; + + memcpy(adjusted_participant_guid, candidate_participant_guid, sizeof(*adjusted_participant_guid)); + for (unsigned i = 0; i < participant_qos->property.value._length; i++) + { + printf("%s\n", participant_qos->property.value._buffer[i].name); + if (!strcmp(participant_qos->property.value._buffer[i].name, "dds.sec.auth.private_key")) + private_key = participant_qos->property.value._buffer[i].value; + else if (!strcmp(participant_qos->property.value._buffer[i].name, "dds.sec.auth.identity_ca")) + identity_ca = participant_qos->property.value._buffer[i].value; + else if (!strcmp(participant_qos->property.value._buffer[i].name, "dds.sec.auth.identity_certificate")) + identity_certificate = participant_qos->property.value._buffer[i].value; + } + + if (strcmp(identity_certificate, test_identity_certificate)) + { + 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)) + { + 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_private_key)) + { + printf("FAILED: Could not get private_key value properly\n"); + result = DDS_SECURITY_VALIDATION_FAILED; + } + if (result == DDS_SECURITY_VALIDATION_OK) + printf("DDS_SECURITY_VALIDATION_OK\n"); + + return result; +} + +static DDS_Security_ValidationResult_t test_validate_local_identity( + dds_security_authentication *instance, + DDS_Security_IdentityHandle *local_identity_handle, + DDS_Security_GUID_t *adjusted_participant_guid, + const DDS_Security_DomainId domain_id, + const DDS_Security_Qos *participant_qos, + const DDS_Security_GUID_t *candidate_participant_guid, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + { + DDS_Security_ValidationResult_t result = impl->instance->validate_local_identity( + impl->instance, local_identity_handle, adjusted_participant_guid, domain_id, participant_qos, candidate_participant_guid, ex); + add_message(&impl->msg_queue, MESSAGE_KIND_VALIDATE_LOCAL_IDENTITY, *local_identity_handle, + 0, 0, adjusted_participant_guid, NULL, result, ex ? ex->message : "", NULL, instance); + return result; + } + case PLUGIN_MODE_ALL_OK: + default: + return test_validate_local_identity_all_ok(adjusted_participant_guid, participant_qos, candidate_participant_guid); + } +} + +static DDS_Security_boolean test_get_identity_token(dds_security_authentication *instance, + DDS_Security_IdentityToken *identity_token, + const DDS_Security_IdentityHandle handle, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + return impl->instance->get_identity_token(impl->instance, identity_token, handle, ex); + + case PLUGIN_MODE_ALL_OK: + default: + { + memset(identity_token, 0, sizeof(*identity_token)); + identity_token->class_id = ddsrt_strdup(""); + return true; + } + } +} + +static DDS_Security_boolean test_get_identity_status_token( + dds_security_authentication *instance, + DDS_Security_IdentityStatusToken *identity_status_token, + const DDS_Security_IdentityHandle handle, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + return impl->instance->get_identity_status_token(impl->instance, identity_status_token, handle, ex); + case PLUGIN_MODE_ALL_OK: + default: + return true; + } +} + +static DDS_Security_boolean test_set_permissions_credential_and_token( + dds_security_authentication *instance, + const DDS_Security_IdentityHandle handle, + const DDS_Security_PermissionsCredentialToken *permissions_credential, + const DDS_Security_PermissionsToken *permissions_token, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + return impl->instance->set_permissions_credential_and_token(impl->instance, handle, permissions_credential, permissions_token, ex); + case PLUGIN_MODE_ALL_OK: + default: + return true; + } +} + +static DDS_Security_ValidationResult_t test_validate_remote_identity( + dds_security_authentication *instance, + DDS_Security_IdentityHandle *remote_identity_handle, + DDS_Security_AuthRequestMessageToken *local_auth_request_token, + const DDS_Security_AuthRequestMessageToken *remote_auth_request_token, + const DDS_Security_IdentityHandle local_identity_handle, + const DDS_Security_IdentityToken *remote_identity_token, + const DDS_Security_GUID_t *remote_participant_guid, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + { + DDS_Security_ValidationResult_t result = impl->instance->validate_remote_identity( + impl->instance, remote_identity_handle, local_auth_request_token, remote_auth_request_token, + local_identity_handle, remote_identity_token, remote_participant_guid, ex); + add_message(&impl->msg_queue, MESSAGE_KIND_VALIDATE_REMOTE_IDENTITY, local_identity_handle, + *remote_identity_handle, 0, NULL, remote_participant_guid, result, ex ? ex->message : "", local_auth_request_token, instance); + return result; + } + + case PLUGIN_MODE_ALL_OK: + default: + return DDS_SECURITY_VALIDATION_OK; + } +} + +static DDS_Security_ValidationResult_t test_begin_handshake_request( + dds_security_authentication *instance, + DDS_Security_HandshakeHandle *handshake_handle, + DDS_Security_HandshakeMessageToken *handshake_message, + const DDS_Security_IdentityHandle initiator_identity_handle, + const DDS_Security_IdentityHandle replier_identity_handle, + const DDS_Security_OctetSeq *serialized_local_participant_data, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + { + DDS_Security_ValidationResult_t result = impl->instance->begin_handshake_request( + impl->instance, handshake_handle, handshake_message, initiator_identity_handle, + replier_identity_handle, serialized_local_participant_data, ex); + add_message(&impl->msg_queue, MESSAGE_KIND_BEGIN_HANDSHAKE_REQUEST, initiator_identity_handle, + replier_identity_handle, *handshake_handle, NULL, NULL, result, ex ? ex->message : "", handshake_message, instance); + return result; + } + + case PLUGIN_MODE_ALL_OK: + default: + return DDS_SECURITY_VALIDATION_OK; + } +} + +static DDS_Security_ValidationResult_t test_begin_handshake_reply( + dds_security_authentication *instance, + DDS_Security_HandshakeHandle *handshake_handle, + DDS_Security_HandshakeMessageToken *handshake_message_out, + const DDS_Security_HandshakeMessageToken *handshake_message_in, + const DDS_Security_IdentityHandle initiator_identity_handle, + const DDS_Security_IdentityHandle replier_identity_handle, + const DDS_Security_OctetSeq *serialized_local_participant_data, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + { + DDS_Security_ValidationResult_t result = impl->instance->begin_handshake_reply( + impl->instance, handshake_handle, handshake_message_out, handshake_message_in, + initiator_identity_handle, replier_identity_handle, serialized_local_participant_data, ex); + add_message(&impl->msg_queue, MESSAGE_KIND_BEGIN_HANDSHAKE_REPLY, replier_identity_handle, + initiator_identity_handle, *handshake_handle, NULL, NULL, result, ex ? ex->message : "", handshake_message_out, instance); + return result; + } + + case PLUGIN_MODE_ALL_OK: + default: + return DDS_SECURITY_VALIDATION_OK; + } +} + +static DDS_Security_ValidationResult_t test_process_handshake( + dds_security_authentication *instance, + DDS_Security_HandshakeMessageToken *handshake_message_out, + const DDS_Security_HandshakeMessageToken *handshake_message_in, + const DDS_Security_HandshakeHandle handshake_handle, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + { + DDS_Security_ValidationResult_t result = impl->instance->process_handshake(impl->instance, handshake_message_out, handshake_message_in, handshake_handle, ex); + add_message(&impl->msg_queue, MESSAGE_KIND_PROCESS_HANDSHAKE, 0, 0, handshake_handle, + NULL, NULL, result, ex ? ex->message : "", handshake_message_out, instance); + return result; + } + + case PLUGIN_MODE_ALL_OK: + default: + return DDS_SECURITY_VALIDATION_OK; + } +} + +static DDS_Security_SharedSecretHandle test_get_shared_secret( + dds_security_authentication *instance, + const DDS_Security_HandshakeHandle handshake_handle, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + return impl->instance->get_shared_secret(impl->instance, handshake_handle, ex); + case PLUGIN_MODE_ALL_OK: + default: + return 0; + } +} + +static DDS_Security_boolean test_get_authenticated_peer_credential_token( + dds_security_authentication *instance, + DDS_Security_AuthenticatedPeerCredentialToken *peer_credential_token, + const DDS_Security_HandshakeHandle handshake_handle, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + return impl->instance->get_authenticated_peer_credential_token(impl->instance, peer_credential_token, handshake_handle, ex); + case PLUGIN_MODE_ALL_OK: + default: + return true; + } +} + +static DDS_Security_boolean test_set_listener(dds_security_authentication *instance, + const dds_security_authentication_listener *listener, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + return impl->instance->set_listener(impl->instance, listener, ex); + case PLUGIN_MODE_ALL_OK: + default: + return true; + } +} + +static DDS_Security_boolean test_return_identity_token(dds_security_authentication *instance, + const DDS_Security_IdentityToken *token, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + return impl->instance->return_identity_token(impl->instance, token, ex); + case PLUGIN_MODE_ALL_OK: + default: + if (token->class_id) + ddsrt_free (token->class_id); + return true; + } +} + +static DDS_Security_boolean test_return_identity_status_token( + dds_security_authentication *instance, + const DDS_Security_IdentityStatusToken *token, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + return impl->instance->return_identity_status_token(impl->instance, token, ex); + case PLUGIN_MODE_ALL_OK: + default: + return true; + } +} + +static DDS_Security_boolean test_return_authenticated_peer_credential_token( + dds_security_authentication *instance, + const DDS_Security_AuthenticatedPeerCredentialToken *peer_credential_token, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + return impl->instance->return_authenticated_peer_credential_token(impl->instance, peer_credential_token, ex); + case PLUGIN_MODE_ALL_OK: + default: + return true; + } +} + +static DDS_Security_boolean test_return_handshake_handle(dds_security_authentication *instance, + const DDS_Security_HandshakeHandle handshake_handle, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + return impl->instance->return_handshake_handle(impl->instance, handshake_handle, ex); + case PLUGIN_MODE_ALL_OK: + default: + return true; + } +} + +static DDS_Security_boolean test_return_identity_handle( + dds_security_authentication *instance, + const DDS_Security_IdentityHandle identity_handle, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + return impl->instance->return_identity_handle(impl->instance, identity_handle, ex); + default: + return true; + } +} + +static DDS_Security_boolean test_return_sharedsecret_handle( + dds_security_authentication *instance, + const DDS_Security_SharedSecretHandle sharedsecret_handle, + DDS_Security_SecurityException *ex) +{ + struct dds_security_authentication_impl *impl = (struct dds_security_authentication_impl *)instance; + switch (impl->mode) + { + case PLUGIN_MODE_WRAPPED: + return impl->instance->return_sharedsecret_handle(impl->instance, sharedsecret_handle, ex); + case PLUGIN_MODE_ALL_OK: + default: + return true; + } +} + +static struct dds_security_authentication_impl * get_impl_for_domain(dds_domainid_t domain_id) +{ + for (size_t i = 0; i < auth_impl_idx; i++) + { + if (auth_impl[i] && auth_impl[i]->instance->gv->config.domainId == domain_id) + { + return auth_impl[i]; + } + } + return NULL; +} + +enum take_message_result test_authentication_plugin_take_msg(dds_domainid_t domain_id, message_kind_t kind, DDS_Security_IdentityHandle lidHandle, DDS_Security_IdentityHandle ridHandle, DDS_Security_IdentityHandle hsHandle, dds_time_t abstimeout, struct message **msg) +{ + struct dds_security_authentication_impl *impl = get_impl_for_domain(domain_id); + assert(impl); + return take_message(&impl->msg_queue, kind, lidHandle, ridHandle, hsHandle, abstimeout, msg); +} + +void test_authentication_plugin_release_msg(struct message *msg) +{ + delete_message(msg); +} + +static struct dds_security_authentication_impl * init_test_authentication_common() +{ + struct dds_security_authentication_impl * impl = ddsrt_malloc(sizeof(*impl)); + memset(impl, 0, sizeof(*impl)); + impl->base.validate_local_identity = &test_validate_local_identity; + impl->base.get_identity_token = &test_get_identity_token; + impl->base.get_identity_status_token = &test_get_identity_status_token; + impl->base.set_permissions_credential_and_token = &test_set_permissions_credential_and_token; + impl->base.validate_remote_identity = &test_validate_remote_identity; + impl->base.begin_handshake_request = &test_begin_handshake_request; + impl->base.begin_handshake_reply = &test_begin_handshake_reply; + impl->base.process_handshake = &test_process_handshake; + impl->base.get_shared_secret = &test_get_shared_secret; + impl->base.get_authenticated_peer_credential_token = &test_get_authenticated_peer_credential_token; + impl->base.set_listener = &test_set_listener; + impl->base.return_identity_token = &test_return_identity_token; + impl->base.return_identity_status_token = &test_return_identity_status_token; + impl->base.return_authenticated_peer_credential_token = &test_return_authenticated_peer_credential_token; + impl->base.return_handshake_handle = &test_return_handshake_handle; + impl->base.return_identity_handle = &test_return_identity_handle; + impl->base.return_sharedsecret_handle = &test_return_sharedsecret_handle; + return impl; +} + +int init_test_authentication_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + DDSRT_UNUSED_ARG(argument); + DDSRT_UNUSED_ARG(context); + DDSRT_UNUSED_ARG(gv); + struct dds_security_authentication_impl *impl = init_test_authentication_common(); + impl->mode = PLUGIN_MODE_ALL_OK; + *context = impl; + return 0; +} + +int finalize_test_authentication_all_ok(void *context) +{ + assert(((struct dds_security_authentication_impl *)context)->mode == PLUGIN_MODE_ALL_OK); + ddsrt_free(context); + return 0; +} + +int init_test_authentication_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + DDSRT_UNUSED_ARG(argument); + DDSRT_UNUSED_ARG(context); + DDSRT_UNUSED_ARG(gv); + struct dds_security_authentication_impl *impl = init_test_authentication_common(); + impl->base.get_shared_secret = NULL; + impl->mode = PLUGIN_MODE_MISSING_FUNC; + *context = impl; + return 0; +} + +int finalize_test_authentication_missing_func(void *context) +{ + assert(((struct dds_security_authentication_impl *)context)->mode == PLUGIN_MODE_MISSING_FUNC); + ddsrt_free(context); + return 0; +} + +int init_test_authentication_init_error(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + DDSRT_UNUSED_ARG(argument); + DDSRT_UNUSED_ARG(context); + DDSRT_UNUSED_ARG(gv); + return 1; +} + +int finalize_test_authentication_init_error(void *context) +{ + DDSRT_UNUSED_ARG(context); + return 0; +} + +/** + * Init and fini functions for using wrapped mode for the authentication plugin. + * These functions assumes that there are no concurrent calls, as the static + * variables used here are not protected by a lock. */ +int init_test_authentication_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + int ret; + struct dds_security_authentication_impl *impl = init_test_authentication_common(); + impl->mode = PLUGIN_MODE_WRAPPED; + + init_message_queue(&impl->msg_queue); + ret = init_authentication(argument, (void **)&impl->instance, gv); + auth_impl_idx++; + auth_impl = ddsrt_realloc(auth_impl, auth_impl_idx * sizeof(*auth_impl)); + auth_impl[auth_impl_idx - 1] = impl; + auth_impl_use++; + *context = impl; + return ret; +} + +int finalize_test_authentication_wrapped(void *context) +{ + int ret; + struct dds_security_authentication_impl *impl = context; + assert(impl->mode == PLUGIN_MODE_WRAPPED); + deinit_message_queue(&impl->msg_queue); + ret = finalize_authentication(impl->instance); + + size_t idx; + for (idx = 0; idx < auth_impl_idx; idx++) + if (auth_impl[idx] == impl) + break; + assert (idx < auth_impl_idx); + auth_impl[idx] = NULL; + + ddsrt_free(context); + + if (--auth_impl_use == 0) + { + ddsrt_free (auth_impl); + auth_impl = NULL; + auth_impl_idx = 0; + } + + return ret; +} + diff --git a/src/security/core/tests/common/authentication_wrapper.h b/src/security/core/tests/common/authentication_wrapper.h new file mode 100644 index 0000000..939db10 --- /dev/null +++ b/src/security/core/tests/common/authentication_wrapper.h @@ -0,0 +1,39 @@ +/* + * Copyright(c) 2006 to 2020 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 SECURITY_CORE_TEST_AUTHENTICATION_WRAPPER_H_ +#define SECURITY_CORE_TEST_AUTHENTICATION_WRAPPER_H_ + +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/authentication_wrapper_export.h" +#include "plugin_wrapper_msg_q.h" + +/* Init in wrapper mode */ +SECURITY_EXPORT int init_test_authentication_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_authentication_wrapped(void *context); + +/* Init in all-ok mode: all functions return success without calling the actual plugin */ +SECURITY_EXPORT int init_test_authentication_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_authentication_all_ok(void *context); + +/* Init in missing function mode: one of the function pointers is null */ +SECURITY_EXPORT int init_test_authentication_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_authentication_missing_func(void *context); + +/* Init function fails */ +SECURITY_EXPORT int init_test_authentication_init_error(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_authentication_init_error(void *context); + +SECURITY_EXPORT enum take_message_result test_authentication_plugin_take_msg(dds_domainid_t domain_id, message_kind_t kind, DDS_Security_IdentityHandle lidHandle, DDS_Security_IdentityHandle ridHandle, DDS_Security_IdentityHandle hsHandle, dds_time_t abstimeout, struct message **msg); +SECURITY_EXPORT void test_authentication_plugin_release_msg(struct message *msg); + +#endif /* SECURITY_CORE_TEST_AUTHENTICATION_WRAPPER_H_ */ diff --git a/src/security/core/tests/common/cert_utils.c b/src/security/core/tests/common/cert_utils.c new file mode 100644 index 0000000..fbaf7a9 --- /dev/null +++ b/src/security/core/tests/common/cert_utils.c @@ -0,0 +1,137 @@ +/* + * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/security/openssl_support.h" +#include "CUnit/Test.h" +#include "cert_utils.h" + +#define MAX_EMAIL 255 +#define EMAIL_HOST "cycloneddssecurity.adlinktech.com" + +static X509 * get_x509(int not_valid_before, int not_valid_after, const char * cn, const char * email) +{ + X509 * cert = X509_new (); + CU_ASSERT_FATAL (cert != NULL); + ASN1_INTEGER_set (X509_get_serialNumber (cert), 1); + X509_gmtime_adj (X509_get_notBefore (cert), not_valid_before); + X509_gmtime_adj (X509_get_notAfter (cert), not_valid_after); + + X509_NAME * name = X509_get_subject_name (cert); + X509_NAME_add_entry_by_txt (name, "C", MBSTRING_ASC, (unsigned char *) "NL", -1, -1, 0); + X509_NAME_add_entry_by_txt (name, "O", MBSTRING_ASC, (unsigned char *) "Example Organization", -1, -1, 0); + X509_NAME_add_entry_by_txt (name, "CN", MBSTRING_ASC, (unsigned char *) cn, -1, -1, 0); + X509_NAME_add_entry_by_txt (name, "emailAddress", MBSTRING_ASC, (unsigned char *) email, -1, -1, 0); + return cert; +} + +static char * get_x509_data(X509 * cert) +{ + // Create BIO for writing output + BIO *output_bio = BIO_new (BIO_s_mem ()); + if (!PEM_write_bio_X509 (output_bio, cert)) { + printf ("Error writing certificate\n"); + CU_ASSERT_FATAL (false); + } + + // Get string + char *output_tmp = NULL; + size_t output_sz = (size_t) BIO_get_mem_data (output_bio, &output_tmp); + char * output = ddsrt_malloc (output_sz + 1); + memcpy (output, output_tmp, output_sz); + output[output_sz] = 0; + BIO_free (output_bio); + + return output; +} + +static EVP_PKEY * get_priv_key(const char * priv_key_str) +{ + BIO *pkey_bio = BIO_new_mem_buf (priv_key_str, -1); + EVP_PKEY *priv_key = PEM_read_bio_PrivateKey (pkey_bio, NULL, NULL, 0); + CU_ASSERT_FATAL (priv_key != NULL); + BIO_free (pkey_bio); + return priv_key; +} + +static X509 * get_cert(const char * cert_str) +{ + BIO *cert_bio = BIO_new_mem_buf (cert_str, -1); + X509 *cert = PEM_read_bio_X509 (cert_bio, NULL, NULL, 0); + CU_ASSERT_FATAL (cert != NULL); + BIO_free (cert_bio); + return cert; +} + +char * generate_ca(const char *ca_name, const char * ca_priv_key_str, int not_valid_before, int not_valid_after) +{ + EVP_PKEY *ca_priv_key = get_priv_key (ca_priv_key_str); + + char * email = malloc (MAX_EMAIL); + snprintf(email, MAX_EMAIL, "%s@%s" , ca_name, EMAIL_HOST); + X509 * ca_cert = get_x509 (not_valid_before, not_valid_after, ca_name, email); + ddsrt_free (email); + + X509_set_pubkey (ca_cert, ca_priv_key); + X509_set_issuer_name (ca_cert, X509_get_subject_name (ca_cert)); /* self-signed */ + X509_sign (ca_cert, ca_priv_key, EVP_sha1 ()); + char * output = get_x509_data (ca_cert); + + EVP_PKEY_free (ca_priv_key); + X509_free (ca_cert); + + return output; +} + +char * generate_identity(const char * ca_cert_str, const char * ca_priv_key_str, const char * name, const char * priv_key_str, int not_valid_before, int not_valid_after, char ** subject) +{ + X509 *ca_cert = get_cert (ca_cert_str); + EVP_PKEY *ca_key_pkey = get_priv_key (ca_priv_key_str); + EVP_PKEY *id_pkey = get_priv_key (priv_key_str); + EVP_PKEY *ca_cert_pkey = X509_get_pubkey (ca_cert); + X509_REQ *csr = X509_REQ_new (); + X509_REQ_set_pubkey (csr, id_pkey); + X509_REQ_sign (csr, id_pkey, EVP_sha256 ()); + + char * email = malloc (MAX_EMAIL); + snprintf(email, MAX_EMAIL, "%s@%s" , name, EMAIL_HOST); + X509 * cert = get_x509 (not_valid_before, not_valid_after, name, email); + ddsrt_free (email); + + EVP_PKEY *csr_pkey = X509_REQ_get_pubkey (csr); + X509_set_pubkey (cert, csr_pkey); + X509_set_issuer_name (cert, X509_get_subject_name (ca_cert)); + X509_sign (cert, ca_key_pkey, EVP_sha256 ()); + char * output = get_x509_data (cert); + + if (subject) + { + X509_NAME *subj_name = X509_get_subject_name (cert); + char * subj_openssl = X509_NAME_oneline (subj_name, NULL, 0); + *subject = ddsrt_strdup (subj_openssl); + OPENSSL_free (subj_openssl); + } + + X509_REQ_free (csr); + EVP_PKEY_free (id_pkey); + EVP_PKEY_free (ca_cert_pkey); + EVP_PKEY_free (ca_key_pkey); + EVP_PKEY_free (csr_pkey); + X509_free (cert); + X509_free (ca_cert); + + return output; +} diff --git a/src/security/core/tests/common/cert_utils.h b/src/security/core/tests/common/cert_utils.h new file mode 100644 index 0000000..f6f9e92 --- /dev/null +++ b/src/security/core/tests/common/cert_utils.h @@ -0,0 +1,20 @@ +/* + * Copyright(c) 2006 to 2020 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 SECURITY_CORE_TEST_CERT_UTILS_H_ +#define SECURITY_CORE_TEST_CERT_UTILS_H_ + +#include + +char * generate_ca(const char *ca_name, const char * ca_priv_key_str, int not_valid_before, int not_valid_after); +char * generate_identity(const char * ca_cert_str, const char * ca_priv_key_str, const char * name, const char * priv_key_str, int not_valid_before, int not_valid_after, char ** subject); + +#endif /* SECURITY_CORE_TEST_CERT_UTILS_H_ */ diff --git a/src/security/core/tests/common/config_env.h.in b/src/security/core/tests/common/config_env.h.in new file mode 100644 index 0000000..d4811fc --- /dev/null +++ b/src/security/core/tests/common/config_env.h.in @@ -0,0 +1,27 @@ +/* + * Copyright(c) 2006 to 2020 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 CONFIG_ENV_H +#define CONFIG_ENV_H + +#define FILE_PATH_SEP "/" +#define COMMON_ETC_DIR "@common_etc_dir@" +#define PLUGIN_WRAPPER_LIB_DIR "@plugin_wrapper_lib_dir@" +#define PLUGIN_WRAPPER_LIB_PREFIX "@CMAKE_SHARED_LIBRARY_PREFIX@" +#define PLUGIN_WRAPPER_LIB_SUFFIX "@CMAKE_SHARED_LIBRARY_SUFFIX@" + +#define WRAPPERLIB_PATH(name) \ + PLUGIN_WRAPPER_LIB_DIR FILE_PATH_SEP PLUGIN_WRAPPER_LIB_PREFIX name PLUGIN_WRAPPER_LIB_SUFFIX + +#define COMMON_ETC_PATH(name) \ + COMMON_ETC_DIR FILE_PATH_SEP name + +#endif /* CONFIG_ENV_H */ diff --git a/src/security/core/tests/common/cryptography_wrapper.c b/src/security/core/tests/common/cryptography_wrapper.c new file mode 100644 index 0000000..47d06c7 --- /dev/null +++ b/src/security/core/tests/common/cryptography_wrapper.c @@ -0,0 +1,1246 @@ +/* + * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include "CUnit/Test.h" +#include "dds/dds.h" +#include "dds/ddsrt/circlist.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/dds_security_api_defs.h" +#include "dds/security/core/dds_security_utils.h" +#include "cryptography_wrapper.h" + +#define CRYPTO_TOKEN_CLASS_ID "DDS:Crypto:AES_GCM_GMAC" +#define CRYPTO_TOKEN_PROPERTY_NAME "dds.cryp.keymat" + +int32_t init_crypto(const char *argument, void **context, struct ddsi_domaingv *gv); +int32_t finalize_crypto(void *context); + +enum crypto_plugin_mode { + PLUGIN_MODE_ALL_OK, + PLUGIN_MODE_MISSING_FUNC, + PLUGIN_MODE_WRAPPED, + PLUGIN_MODE_TOKEN_LOG, + PLUGIN_MODE_PLAIN_DATA +}; + +struct dds_security_crypto_key_exchange_impl { + struct dds_security_crypto_key_exchange base; + struct dds_security_crypto_key_exchange *instance; + struct dds_security_cryptography_impl *parent; +}; + +struct dds_security_crypto_key_factory_impl { + struct dds_security_crypto_key_factory base; + struct dds_security_crypto_key_factory *instance; + struct dds_security_cryptography_impl *parent; +}; + +struct dds_security_crypto_transform_impl { + struct dds_security_crypto_transform base; + struct dds_security_crypto_transform *instance; + struct dds_security_cryptography_impl *parent; +}; + +struct dds_security_cryptography_impl { + struct dds_security_cryptography base; + struct dds_security_cryptography *instance; + struct dds_security_crypto_transform_impl transform_wrap; + struct dds_security_crypto_key_factory_impl factory_wrap; + struct dds_security_crypto_key_exchange_impl exchange_wrap; + enum crypto_plugin_mode mode; + bool protection_kinds_set; + bool disc_protection_kinds_set; + DDS_Security_ProtectionKind rtps_protection_kind; + DDS_Security_ProtectionKind metadata_protection_kind; + DDS_Security_BasicProtectionKind payload_protection_kind; + DDS_Security_ProtectionKind disc_protection_kind; + DDS_Security_ProtectionKind liveliness_protection_kind; + const char * pp_secret; + const char * groupdata_secret; + const char * ep_secret; + const char * encrypted_secret; + ddsrt_mutex_t token_data_lock; + struct ddsrt_circlist token_data_list; + ddsrt_mutex_t encode_decode_log_lock; + struct ddsrt_circlist encode_decode_log; + bool force_plain_rtps; + bool force_plain_submsg; + bool force_plain_payload; + DDS_Security_DatawriterCryptoHandle force_plain_sender_handle; +}; + +static DDS_Security_ParticipantCryptoHandle g_local_participant_handle = 0; +static ddsrt_once_t lock_inited = DDSRT_ONCE_INIT; +static ddsrt_mutex_t g_print_token_lock; + +void set_protection_kinds( + struct dds_security_cryptography_impl * impl, + DDS_Security_ProtectionKind rtps_protection_kind, + DDS_Security_ProtectionKind metadata_protection_kind, + DDS_Security_BasicProtectionKind payload_protection_kind) +{ + assert(impl); + impl->rtps_protection_kind = rtps_protection_kind; + impl->metadata_protection_kind = metadata_protection_kind; + impl->payload_protection_kind = payload_protection_kind; + impl->protection_kinds_set = true; +} + +void set_encrypted_secret(struct dds_security_cryptography_impl * impl, const char * secret) +{ + assert(impl); + impl->encrypted_secret = secret; +} + +void set_disc_protection_kinds( + struct dds_security_cryptography_impl * impl, + DDS_Security_ProtectionKind disc_protection_kind, + DDS_Security_ProtectionKind liveliness_protection_kind) +{ + assert(impl); + impl->disc_protection_kind = disc_protection_kind; + impl->liveliness_protection_kind = liveliness_protection_kind; + impl->disc_protection_kinds_set = true; +} + +void set_entity_data_secret(struct dds_security_cryptography_impl * impl, const char * pp_secret, const char * groupdata_secret, const char * ep_secret) +{ + assert(impl); + impl->pp_secret = pp_secret; + impl->groupdata_secret = groupdata_secret; + impl->ep_secret = ep_secret; +} + +void set_force_plain_data(struct dds_security_cryptography_impl * impl, DDS_Security_DatawriterCryptoHandle handle, bool plain_rtps, bool plain_submsg, bool plain_payload) +{ + assert (impl); + assert (impl->mode == PLUGIN_MODE_PLAIN_DATA); + impl->force_plain_rtps = plain_rtps; + impl->force_plain_submsg = plain_submsg; + impl->force_plain_payload = plain_payload; + impl->force_plain_sender_handle = handle; +} + +static bool check_crypto_tokens(const DDS_Security_DataHolderSeq *tokens) +{ + bool result = true; + + if (tokens->_length == 0 || tokens->_buffer == NULL) + return false; + + for (uint32_t i = 0; result && (i < tokens->_length); i++) + { + result = (tokens->_buffer[i].class_id != NULL && + strcmp(CRYPTO_TOKEN_CLASS_ID, tokens->_buffer[i].class_id) == 0 && + tokens->_buffer[i].binary_properties._length == 1 && + tokens->_buffer[i].binary_properties._buffer != NULL && + tokens->_buffer[i].binary_properties._buffer[0].name != NULL && + strcmp(CRYPTO_TOKEN_PROPERTY_NAME, tokens->_buffer[i].binary_properties._buffer[0].name) == 0 && + tokens->_buffer[i].binary_properties._buffer[0].value._length > 0 && + tokens->_buffer[i].binary_properties._buffer[0].value._buffer != NULL); + } + return result; +} + +const char *get_crypto_token_type_str (enum crypto_tokens_type type) +{ + switch (type) + { + case LOCAL_PARTICIPANT_TOKENS: return "LOCAL_PARTICIPANT_TOKENS"; + case LOCAL_WRITER_TOKENS: return "LOCAL_WRITER_TOKENS"; + case LOCAL_READER_TOKENS: return "LOCAL_READER_TOKENS"; + case REMOTE_PARTICIPANT_TOKENS: return "REMOTE_PARTICIPANT_TOKENS"; + case REMOTE_WRITER_TOKENS: return "REMOTE_WRITER_TOKENS"; + case REMOTE_READER_TOKENS: return "REMOTE_READER_TOKENS"; + default: assert (0); return ""; + } +} + +static void print_tokens (enum crypto_tokens_type type, const DDS_Security_ParticipantCryptoHandle lch, const DDS_Security_ParticipantCryptoHandle rch, + const DDS_Security_ParticipantCryptoTokenSeq *tokens) +{ + ddsrt_mutex_lock (&g_print_token_lock); + printf ("Token type %s, local %"PRIx64" / remote %"PRIx64", count: %u\n", get_crypto_token_type_str (type), lch, rch, tokens->_length); + for (uint32_t i = 0; i < tokens->_length; i++) + { + printf ("- token: "); + for (uint32_t j = 0; j < tokens->_buffer[i].binary_properties._buffer[0].value._length && j < 32; j++) + printf ("%02x", tokens->_buffer[i].binary_properties._buffer[0].value._buffer[j]); + printf ("\n"); + } + printf ("\n"); + ddsrt_mutex_unlock (&g_print_token_lock); +} + +static void add_tokens (struct ddsrt_circlist *list, enum crypto_tokens_type type, + const DDS_Security_ParticipantCryptoHandle lch, const DDS_Security_ParticipantCryptoHandle rch, + const DDS_Security_ParticipantCryptoTokenSeq *tokens) +{ + struct crypto_token_data *token_data = ddsrt_malloc (sizeof (*token_data)); + token_data->type = type; + token_data->local_handle = lch; + token_data->remote_handle = rch; + token_data->n_tokens = tokens->_length; + assert (tokens->_length <= CRYPTO_TOKEN_MAXCOUNT); + for (uint32_t i = 0; i < tokens->_length; i++) + { + size_t len = tokens->_buffer[i].binary_properties._buffer[0].value._length; + assert (len <= CRYPTO_TOKEN_SIZE); + memcpy (token_data->data[i], tokens->_buffer[i].binary_properties._buffer[0].value._buffer, len); + token_data->data_len[i] = len; + } + ddsrt_circlist_append(list, &token_data->e); +} + +static void store_tokens (struct dds_security_crypto_key_exchange_impl *impl, enum crypto_tokens_type type, const DDS_Security_ParticipantCryptoHandle lch, + const DDS_Security_ParticipantCryptoHandle rch, const DDS_Security_ParticipantCryptoTokenSeq *tokens) +{ + if (!check_crypto_tokens ((const DDS_Security_DataHolderSeq *) tokens)) + { + printf ("%d ERROR\n", type); + return; + } + + ddsrt_mutex_lock (&impl->parent->token_data_lock); + add_tokens (&impl->parent->token_data_list, type, lch, rch, tokens); + ddsrt_mutex_unlock (&impl->parent->token_data_lock); + + print_tokens (type, lch, rch, tokens); +} + +struct ddsrt_circlist * get_crypto_tokens (struct dds_security_cryptography_impl * impl) +{ + struct ddsrt_circlist *tokens = ddsrt_malloc (sizeof (*tokens)); + ddsrt_circlist_init (tokens); + + ddsrt_mutex_lock (&impl->token_data_lock); + if (ddsrt_circlist_isempty (&impl->encode_decode_log)) + { + ddsrt_mutex_unlock (&impl->token_data_lock); + return tokens; + } + + struct ddsrt_circlist_elem *elem0 = ddsrt_circlist_oldest (&impl->token_data_list), *elem = elem0; + do + { + struct crypto_token_data *elem_data = DDSRT_FROM_CIRCLIST (struct crypto_token_data, e, elem); + struct crypto_token_data *token_data = ddsrt_malloc (sizeof (*token_data)); + memcpy (token_data, elem_data, sizeof (*token_data)); + ddsrt_circlist_append (tokens, &token_data->e); + elem = elem->next; + } while (elem != elem0); + ddsrt_mutex_unlock (&impl->token_data_lock); + + return tokens; +} + +struct crypto_token_data * find_crypto_token (struct dds_security_cryptography_impl * impl, enum crypto_tokens_type type, unsigned char * data, size_t data_len) +{ + assert (data_len <= CRYPTO_TOKEN_SIZE); + ddsrt_mutex_lock (&impl->token_data_lock); + if (ddsrt_circlist_isempty (&impl->encode_decode_log)) + { + ddsrt_mutex_unlock (&impl->token_data_lock); + return NULL; + } + struct ddsrt_circlist_elem *elem0 = ddsrt_circlist_oldest (&impl->token_data_list), *elem = elem0; + do + { + struct crypto_token_data *elem_data = DDSRT_FROM_CIRCLIST (struct crypto_token_data, e, elem); + if (elem_data->type == type) + { + for (uint32_t i = 0; i < elem_data->n_tokens; i++) + { + size_t len = elem_data->data_len[i]; + assert (len <= CRYPTO_TOKEN_SIZE); + if (!memcmp (data, elem_data->data[i], data_len < len ? data_len : len)) + { + ddsrt_mutex_unlock (&impl->token_data_lock); + return elem_data; + } + } + } + elem = elem->next; + } while (elem != elem0); + ddsrt_mutex_unlock (&impl->token_data_lock); + return NULL; +} + +static void log_encode_decode (struct dds_security_cryptography_impl * impl, enum crypto_encode_decode_fn function, DDS_Security_long_long handle) +{ + ddsrt_mutex_lock (&impl->encode_decode_log_lock); + if (!ddsrt_circlist_isempty (&impl->encode_decode_log)) + { + struct ddsrt_circlist_elem *elem0 = ddsrt_circlist_oldest (&impl->encode_decode_log), *elem = elem0; + do + { + struct crypto_encode_decode_data *data = DDSRT_FROM_CIRCLIST (struct crypto_encode_decode_data, e, elem); + if (data->function == function && data->handle == handle) + { + data->count++; + ddsrt_mutex_unlock (&impl->encode_decode_log_lock); + return; + } + elem = elem->next; + } while (elem != elem0); + } + /* add new entry */ + struct crypto_encode_decode_data *new_data = ddsrt_malloc (sizeof (*new_data)); + new_data->function = function; + new_data->handle = handle; + new_data->count = 1; + ddsrt_circlist_append(&impl->encode_decode_log, &new_data->e); + ddsrt_mutex_unlock (&impl->encode_decode_log_lock); +} + +struct crypto_encode_decode_data * get_encode_decode_log (struct dds_security_cryptography_impl * impl, enum crypto_encode_decode_fn function, DDS_Security_long_long handle) +{ + ddsrt_mutex_lock (&impl->encode_decode_log_lock); + if (!ddsrt_circlist_isempty (&impl->encode_decode_log)) + { + struct ddsrt_circlist_elem *elem0 = ddsrt_circlist_oldest (&impl->encode_decode_log), *elem = elem0; + do + { + struct crypto_encode_decode_data *data = DDSRT_FROM_CIRCLIST (struct crypto_encode_decode_data, e, elem); + if (data->function == function && data->handle == handle) + { + struct crypto_encode_decode_data *result = ddsrt_malloc (sizeof (*result)); + memcpy (result, data, sizeof (*result)); + ddsrt_mutex_unlock (&impl->encode_decode_log_lock); + return result; + } + elem = elem->next; + } while (elem != elem0); + } + ddsrt_mutex_unlock (&impl->encode_decode_log_lock); + return NULL; +} + +static unsigned char * find_buffer_match(const unsigned char *input, size_t input_len, const unsigned char *match, size_t match_len) +{ + if (match_len <= input_len && match_len > 0 && input_len > 0) + { + const unsigned char *match_end = match + match_len; + unsigned char *i = (unsigned char *) input; + while (i <= input + input_len - match_len) + { + unsigned char *m = (unsigned char *) match, *j = i; + while (*m == *j && j < input + input_len) + { + j++; + if (++m == match_end) + return i; + } + i++; + } + } + return NULL; +} + +static bool check_buffers(const DDS_Security_OctetSeq *encoded_buffer, const DDS_Security_OctetSeq *plain_buffer, bool expect_encrypted, DDS_Security_SecurityException *ex) +{ + unsigned char *m = find_buffer_match (encoded_buffer->_buffer, encoded_buffer->_length, + plain_buffer->_buffer, plain_buffer->_length); + if ((m == NULL) != expect_encrypted) + { + ex->code = 1; + ex->message = ddsrt_strdup (expect_encrypted ? + "Expect encryption, but clear payload found after encoding." : "Expect only signature, but clear payload was not found in source after decoding."); + return false; + } + return true; +} + +static DDS_Security_long_long check_handle(DDS_Security_long_long handle) +{ + /* Assume that handle, which actually is a pointer, has a value that is likely to be + a valid memory address and not a value returned by the mock implementation. */ + CU_ASSERT_FATAL (handle == 0 || handle > 4096); + return handle; +} + +static bool expect_encrypted_buffer (DDS_Security_ProtectionKind pk) +{ + return pk == DDS_SECURITY_PROTECTION_KIND_ENCRYPT || pk == DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION; +} + +static void copy_octetseq(DDS_Security_OctetSeq *encoded_submsg, const DDS_Security_OctetSeq *plain_submsg) +{ + encoded_submsg->_length = encoded_submsg->_maximum = plain_submsg->_length; + if (plain_submsg->_length > 0) + { + encoded_submsg->_buffer = ddsrt_malloc(encoded_submsg->_length); + memcpy(encoded_submsg->_buffer, plain_submsg->_buffer, encoded_submsg->_length); + } + else + { + encoded_submsg->_buffer = NULL; + } +} + +/** + * Crypto key exchange + */ +static DDS_Security_boolean create_local_participant_crypto_tokens( + dds_security_crypto_key_exchange *instance, + DDS_Security_ParticipantCryptoTokenSeq *local_participant_crypto_tokens, + const DDS_Security_ParticipantCryptoHandle local_participant_crypto, + const DDS_Security_ParticipantCryptoHandle remote_participant_crypto, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_exchange_impl *impl = (struct dds_security_crypto_key_exchange_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + { + DDS_Security_boolean ret = impl->instance->create_local_participant_crypto_tokens (impl->instance, local_participant_crypto_tokens, + local_participant_crypto, remote_participant_crypto, ex); + if (ret && impl->parent->mode == PLUGIN_MODE_TOKEN_LOG) + store_tokens (impl, LOCAL_PARTICIPANT_TOKENS, local_participant_crypto, remote_participant_crypto, local_participant_crypto_tokens); + return ret; + } + default: + return true; + } +} + +static DDS_Security_boolean set_remote_participant_crypto_tokens( + dds_security_crypto_key_exchange *instance, + const DDS_Security_ParticipantCryptoHandle local_participant_crypto, + const DDS_Security_ParticipantCryptoHandle remote_participant_crypto, + const DDS_Security_ParticipantCryptoTokenSeq *remote_participant_tokens, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_exchange_impl *impl = (struct dds_security_crypto_key_exchange_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + { + DDS_Security_boolean ret = impl->instance->set_remote_participant_crypto_tokens (impl->instance, check_handle (local_participant_crypto), + check_handle (remote_participant_crypto), remote_participant_tokens, ex); + if (ret && impl->parent->mode == PLUGIN_MODE_TOKEN_LOG) + store_tokens (impl, REMOTE_PARTICIPANT_TOKENS, local_participant_crypto, remote_participant_crypto, remote_participant_tokens); + return ret; + } + default: + return true; + } +} + +static DDS_Security_boolean create_local_datawriter_crypto_tokens( + dds_security_crypto_key_exchange *instance, + DDS_Security_DatawriterCryptoTokenSeq *local_datawriter_crypto_tokens, + const DDS_Security_DatawriterCryptoHandle local_datawriter_crypto, + const DDS_Security_DatareaderCryptoHandle remote_datareader_crypto, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_exchange_impl *impl = (struct dds_security_crypto_key_exchange_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + { + DDS_Security_boolean ret = impl->instance->create_local_datawriter_crypto_tokens (impl->instance, local_datawriter_crypto_tokens, + check_handle (local_datawriter_crypto), check_handle (remote_datareader_crypto), ex); + if (ret && impl->parent->mode == PLUGIN_MODE_TOKEN_LOG) + store_tokens (impl, LOCAL_WRITER_TOKENS, local_datawriter_crypto, remote_datareader_crypto, local_datawriter_crypto_tokens); + return ret; + } + default: + return true; + } +} + +static DDS_Security_boolean set_remote_datawriter_crypto_tokens( + dds_security_crypto_key_exchange *instance, + const DDS_Security_DatareaderCryptoHandle local_datareader_crypto, + const DDS_Security_DatawriterCryptoHandle remote_datawriter_crypto, + const DDS_Security_DatawriterCryptoTokenSeq *remote_datawriter_tokens, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_exchange_impl *impl = (struct dds_security_crypto_key_exchange_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + { + DDS_Security_boolean ret = impl->instance->set_remote_datawriter_crypto_tokens (impl->instance, check_handle (local_datareader_crypto), + check_handle (remote_datawriter_crypto), remote_datawriter_tokens, ex); + if (ret && impl->parent->mode == PLUGIN_MODE_TOKEN_LOG) + store_tokens (impl, REMOTE_WRITER_TOKENS, local_datareader_crypto, remote_datawriter_crypto, remote_datawriter_tokens); + return ret; + } + default: + return true; + } +} + +static DDS_Security_boolean create_local_datareader_crypto_tokens( + dds_security_crypto_key_exchange *instance, + DDS_Security_DatareaderCryptoTokenSeq *local_datareader_cryto_tokens, + const DDS_Security_DatareaderCryptoHandle local_datareader_crypto, + const DDS_Security_DatawriterCryptoHandle remote_datawriter_crypto, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_exchange_impl *impl = (struct dds_security_crypto_key_exchange_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + { + DDS_Security_boolean ret = impl->instance->create_local_datareader_crypto_tokens (impl->instance, local_datareader_cryto_tokens, + check_handle (local_datareader_crypto), check_handle (remote_datawriter_crypto), ex); + if (ret && impl->parent->mode == PLUGIN_MODE_TOKEN_LOG) + store_tokens (impl, LOCAL_READER_TOKENS, local_datareader_crypto, remote_datawriter_crypto, local_datareader_cryto_tokens); + return ret; + } + default: + return true; + } +} + +static DDS_Security_boolean set_remote_datareader_crypto_tokens( + dds_security_crypto_key_exchange *instance, + const DDS_Security_DatawriterCryptoHandle local_datawriter_crypto, + const DDS_Security_DatareaderCryptoHandle remote_datareader_crypto, + const DDS_Security_DatareaderCryptoTokenSeq *remote_datareader_tokens, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_exchange_impl *impl = (struct dds_security_crypto_key_exchange_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + { + DDS_Security_boolean ret = impl->instance->set_remote_datareader_crypto_tokens (impl->instance, check_handle (local_datawriter_crypto), + check_handle (remote_datareader_crypto), remote_datareader_tokens, ex); + if (ret && impl->parent->mode == PLUGIN_MODE_TOKEN_LOG) + store_tokens (impl, REMOTE_READER_TOKENS, local_datawriter_crypto, remote_datareader_crypto, remote_datareader_tokens); + return ret; + } + default: + return true; + } +} + +static DDS_Security_boolean return_crypto_tokens( + dds_security_crypto_key_exchange *instance, + DDS_Security_CryptoTokenSeq *crypto_tokens, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_exchange_impl *impl = (struct dds_security_crypto_key_exchange_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + return impl->instance->return_crypto_tokens (impl->instance, crypto_tokens, ex); + default: + return true; + } +} + +/** + * Crypto key factory + */ +static DDS_Security_ParticipantCryptoHandle register_local_participant( + dds_security_crypto_key_factory *instance, + const DDS_Security_IdentityHandle participant_identity, + const DDS_Security_PermissionsHandle participant_permissions, + const DDS_Security_PropertySeq *participant_properties, + const DDS_Security_ParticipantSecurityAttributes *participant_security_attributes, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_factory_impl *impl = (struct dds_security_crypto_key_factory_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + return check_handle (impl->instance->register_local_participant (impl->instance, check_handle (participant_identity), + check_handle (participant_permissions), participant_properties, participant_security_attributes, ex)); + default: + return ++g_local_participant_handle; + } +} + +static DDS_Security_ParticipantCryptoHandle register_matched_remote_participant( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle local_participant_crypto_handle, + const DDS_Security_IdentityHandle remote_participant_identity, + const DDS_Security_PermissionsHandle remote_participant_permissions, + const DDS_Security_SharedSecretHandle shared_secret, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_factory_impl *impl = (struct dds_security_crypto_key_factory_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + return check_handle (impl->instance->register_matched_remote_participant (impl->instance, local_participant_crypto_handle, + remote_participant_identity, remote_participant_permissions, shared_secret, ex)); + default: + return 0; + } +} + +static DDS_Security_DatawriterCryptoHandle register_local_datawriter( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle participant_crypto, + const DDS_Security_PropertySeq *datawriter_properties, + const DDS_Security_EndpointSecurityAttributes *datawriter_security_attributes, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_factory_impl *impl = (struct dds_security_crypto_key_factory_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + return check_handle (impl->instance->register_local_datawriter (impl->instance, check_handle (participant_crypto), + datawriter_properties, datawriter_security_attributes, ex)); + default: + return 0; + } +} + +static DDS_Security_DatareaderCryptoHandle register_matched_remote_datareader( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatawriterCryptoHandle local_datawriter_crypto_handle, + const DDS_Security_ParticipantCryptoHandle remote_participant_crypto, + const DDS_Security_SharedSecretHandle shared_secret, + const DDS_Security_boolean relay_only, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_factory_impl *impl = (struct dds_security_crypto_key_factory_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + return check_handle (impl->instance->register_matched_remote_datareader (impl->instance, check_handle (local_datawriter_crypto_handle), + check_handle (remote_participant_crypto), check_handle (shared_secret), relay_only, ex)); + default: + return 0; + } +} + +static DDS_Security_DatareaderCryptoHandle register_local_datareader( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle participant_crypto, + const DDS_Security_PropertySeq *datareader_properties, + const DDS_Security_EndpointSecurityAttributes *datareader_security_attributes, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_factory_impl *impl = (struct dds_security_crypto_key_factory_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + return check_handle (impl->instance->register_local_datareader (impl->instance, check_handle (participant_crypto), + datareader_properties, datareader_security_attributes, ex)); + default: + return 0; + } +} + +static DDS_Security_DatawriterCryptoHandle register_matched_remote_datawriter( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatareaderCryptoHandle local_datareader_crypto_handle, + const DDS_Security_ParticipantCryptoHandle remote_participant_crypt, + const DDS_Security_SharedSecretHandle shared_secret, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_factory_impl *impl = (struct dds_security_crypto_key_factory_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + return check_handle (impl->instance->register_matched_remote_datawriter (impl->instance, check_handle (local_datareader_crypto_handle), + check_handle (remote_participant_crypt), shared_secret, ex)); + default: + return 1; + } +} + +static DDS_Security_boolean unregister_participant( + dds_security_crypto_key_factory *instance, + const DDS_Security_ParticipantCryptoHandle participant_crypto_handle, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_factory_impl *impl = (struct dds_security_crypto_key_factory_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + return impl->instance->unregister_participant (impl->instance, check_handle (participant_crypto_handle), ex); + default: + return true; + } +} + +static DDS_Security_boolean unregister_datawriter( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatawriterCryptoHandle datawriter_crypto_handle, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_factory_impl *impl = (struct dds_security_crypto_key_factory_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + return impl->instance->unregister_datawriter (impl->instance, check_handle (datawriter_crypto_handle), ex); + default: + return true; + } +} + +static DDS_Security_boolean unregister_datareader( + dds_security_crypto_key_factory *instance, + const DDS_Security_DatareaderCryptoHandle datareader_crypto_handle, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_key_factory_impl *impl = (struct dds_security_crypto_key_factory_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + return impl->instance->unregister_datareader (impl->instance, check_handle (datareader_crypto_handle), ex); + default: + return true; + } +} + +/** + * Crypto transform + */ +static DDS_Security_boolean encode_serialized_payload( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_buffer, + DDS_Security_OctetSeq *extra_inline_qos, + const DDS_Security_OctetSeq *plain_buffer, + const DDS_Security_DatawriterCryptoHandle sending_datawriter_crypto, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_transform_impl *impl = (struct dds_security_crypto_transform_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_PLAIN_DATA: + if (impl->parent->force_plain_payload && impl->parent->force_plain_sender_handle == sending_datawriter_crypto) + { + copy_octetseq (encoded_buffer, plain_buffer); + return true; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + { + if (!impl->instance->encode_serialized_payload (impl->instance, encoded_buffer, + extra_inline_qos, plain_buffer, check_handle (sending_datawriter_crypto), ex)) + return false; + if (impl->parent->protection_kinds_set + && impl->parent->encrypted_secret + && (impl->parent->payload_protection_kind == DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT + || expect_encrypted_buffer (impl->parent->metadata_protection_kind) + || expect_encrypted_buffer (impl->parent->rtps_protection_kind))) + { + if (find_buffer_match (encoded_buffer->_buffer, encoded_buffer->_length, (const unsigned char *) impl->parent->encrypted_secret, strlen (impl->parent->encrypted_secret)) != NULL) + { + ex->code = 1; + ex->message = ddsrt_strdup ("Expect encryption, but found secret in payload after encoding"); + return false; + } + } + return !impl->parent->protection_kinds_set || check_buffers (encoded_buffer, plain_buffer, impl->parent->payload_protection_kind == DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT, ex); + } + default: + return true; + } +} + +static DDS_Security_boolean check_buffer_submsg( + struct dds_security_crypto_transform_impl *impl, + DDS_Security_OctetSeq *encoded_rtps_submessage, + const DDS_Security_OctetSeq *plain_rtps_submessage, + DDS_Security_SecurityException *ex) +{ + bool exp_enc = impl->parent->protection_kinds_set && (expect_encrypted_buffer (impl->parent->metadata_protection_kind) || expect_encrypted_buffer (impl->parent->rtps_protection_kind)); + if (exp_enc && impl->parent->encrypted_secret && find_buffer_match (encoded_rtps_submessage->_buffer, encoded_rtps_submessage->_length, (const unsigned char *) impl->parent->encrypted_secret, strlen (impl->parent->encrypted_secret)) != NULL) + { + ex->code = 1; + ex->message = ddsrt_strdup ("Expect encryption, but found secret in submessage after encoding"); + return false; + } + + return impl->parent->protection_kinds_set && expect_encrypted_buffer (impl->parent->metadata_protection_kind) ? check_buffers (encoded_rtps_submessage, plain_rtps_submessage, true, ex) : true; +} + +static DDS_Security_boolean encode_datawriter_submessage( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_rtps_submessage, + const DDS_Security_OctetSeq *plain_rtps_submessage, + const DDS_Security_DatawriterCryptoHandle sending_datawriter_crypto, + const DDS_Security_DatareaderCryptoHandleSeq *receiving_datareader_crypto_list, + int32_t *receiving_datareader_crypto_list_index, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_transform_impl *impl = (struct dds_security_crypto_transform_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_PLAIN_DATA: + if (impl->parent->force_plain_submsg && impl->parent->force_plain_sender_handle == sending_datawriter_crypto) + { + copy_octetseq (encoded_rtps_submessage, plain_rtps_submessage); + assert (receiving_datareader_crypto_list->_length <= INT32_MAX); + *receiving_datareader_crypto_list_index = (int32_t) receiving_datareader_crypto_list->_length; + return true; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + log_encode_decode (impl->parent, ENCODE_DATAWRITER_SUBMESSAGE, sending_datawriter_crypto); + /* fall-through */ + case PLUGIN_MODE_TOKEN_LOG: + if (!impl->instance->encode_datawriter_submessage (impl->instance, encoded_rtps_submessage, + plain_rtps_submessage, check_handle (sending_datawriter_crypto), receiving_datareader_crypto_list, receiving_datareader_crypto_list_index, ex)) + return false; + if (!check_buffer_submsg(impl, encoded_rtps_submessage, plain_rtps_submessage, ex)) + return false; + + if (impl->parent->disc_protection_kinds_set && expect_encrypted_buffer (impl->parent->disc_protection_kind)) + { + if (impl->parent->pp_secret && find_buffer_match (plain_rtps_submessage->_buffer, plain_rtps_submessage->_length, (const unsigned char *) impl->parent->pp_secret, strlen (impl->parent->pp_secret)) != NULL) + { + ex->code = 1; + ex->message = ddsrt_strdup ("Expect discovery encryption, but found participant userdata secret in submessage after encoding"); + return false; + } + if (impl->parent->groupdata_secret && find_buffer_match (plain_rtps_submessage->_buffer, plain_rtps_submessage->_length, (const unsigned char *) impl->parent->groupdata_secret, strlen (impl->parent->groupdata_secret)) != NULL) + { + ex->code = 1; + ex->message = ddsrt_strdup ("Expect discovery encryption, but found publisher/subscriber groupdata secret in submessage after encoding"); + return false; + } + if (impl->parent->ep_secret && find_buffer_match (plain_rtps_submessage->_buffer, plain_rtps_submessage->_length, (const unsigned char *) impl->parent->ep_secret, strlen (impl->parent->ep_secret)) != NULL) + { + ex->code = 1; + ex->message = ddsrt_strdup ("Expect discovery encryption, but found reader/writer userdata secret in submessage after encoding"); + return false; + } + } + return true; + + + default: + return true; + } +} + +static DDS_Security_boolean encode_datareader_submessage( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_rtps_submessage, + const DDS_Security_OctetSeq *plain_rtps_submessage, + const DDS_Security_DatareaderCryptoHandle sending_datareader_crypto, + const DDS_Security_DatawriterCryptoHandleSeq *receiving_datawriter_crypto_list, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_transform_impl *impl = (struct dds_security_crypto_transform_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_PLAIN_DATA: + if (impl->parent->force_plain_submsg && impl->parent->force_plain_sender_handle == sending_datareader_crypto) + { + copy_octetseq (encoded_rtps_submessage, plain_rtps_submessage); + return true; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + log_encode_decode (impl->parent, ENCODE_DATAREADER_SUBMESSAGE, sending_datareader_crypto); + /* fall-through */ + case PLUGIN_MODE_TOKEN_LOG: + if (!impl->instance->encode_datareader_submessage (impl->instance, encoded_rtps_submessage, + plain_rtps_submessage, check_handle (sending_datareader_crypto), receiving_datawriter_crypto_list, ex)) + return false; + return check_buffer_submsg(impl, encoded_rtps_submessage, plain_rtps_submessage, ex); + default: + return true; + } +} + +static DDS_Security_boolean encode_rtps_message( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *encoded_rtps_message, + const DDS_Security_OctetSeq *plain_rtps_message, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + const DDS_Security_ParticipantCryptoHandleSeq *receiving_participant_crypto_list, + int32_t *receiving_participant_crypto_list_index, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_transform_impl *impl = (struct dds_security_crypto_transform_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_PLAIN_DATA: + if (impl->parent->force_plain_rtps) + { + copy_octetseq (encoded_rtps_message, plain_rtps_message); + assert (receiving_participant_crypto_list->_length <= INT32_MAX); + *receiving_participant_crypto_list_index = (int32_t) receiving_participant_crypto_list->_length; + return true; + } + /* fall through */ + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + if (!impl->instance->encode_rtps_message (impl->instance, encoded_rtps_message, + plain_rtps_message, check_handle (sending_participant_crypto), receiving_participant_crypto_list, receiving_participant_crypto_list_index, ex)) + return false; + if (impl->parent->protection_kinds_set + && impl->parent->encrypted_secret + && expect_encrypted_buffer (impl->parent->rtps_protection_kind) + && find_buffer_match (encoded_rtps_message->_buffer, encoded_rtps_message->_length, (const unsigned char *) impl->parent->encrypted_secret, strlen (impl->parent->encrypted_secret)) != NULL) + { + ex->code = 1; + ex->message = ddsrt_strdup ("Expect encryption, but found secret in RTPS message after encoding"); + return false; + } + return impl->parent->protection_kinds_set && expect_encrypted_buffer (impl->parent->rtps_protection_kind) ? + check_buffers (encoded_rtps_message, plain_rtps_message, true, ex) : true; + default: + return true; + } +} + +static DDS_Security_boolean decode_rtps_message( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_buffer, + const DDS_Security_OctetSeq *encoded_buffer, + const DDS_Security_ParticipantCryptoHandle receiving_participant_crypto, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_transform_impl *impl = (struct dds_security_crypto_transform_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + return impl->instance->decode_rtps_message (impl->instance, plain_buffer, encoded_buffer, + check_handle (receiving_participant_crypto), check_handle (sending_participant_crypto), ex); + default: + return true; + } +} + +static DDS_Security_boolean preprocess_secure_submsg( + dds_security_crypto_transform *instance, + DDS_Security_DatawriterCryptoHandle *datawriter_crypto, + DDS_Security_DatareaderCryptoHandle *datareader_crypto, + DDS_Security_SecureSubmessageCategory_t *secure_submessage_category, + const DDS_Security_OctetSeq *encoded_rtps_submessage, + const DDS_Security_ParticipantCryptoHandle receiving_participant_crypto, + const DDS_Security_ParticipantCryptoHandle sending_participant_crypto, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_transform_impl *impl = (struct dds_security_crypto_transform_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + return impl->instance->preprocess_secure_submsg (impl->instance, datawriter_crypto, datareader_crypto, + secure_submessage_category, encoded_rtps_submessage, check_handle (receiving_participant_crypto), check_handle (sending_participant_crypto), ex); + default: + return true; + } +} + +static DDS_Security_boolean decode_datawriter_submessage( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_rtps_submessage, + const DDS_Security_OctetSeq *encoded_rtps_submessage, + const DDS_Security_DatareaderCryptoHandle receiving_datareader_crypto, + const DDS_Security_DatawriterCryptoHandle sending_datawriter_crypto, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_transform_impl *impl = (struct dds_security_crypto_transform_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_PLAIN_DATA: + case PLUGIN_MODE_WRAPPED: + log_encode_decode (impl->parent, DECODE_DATAWRITER_SUBMESSAGE, receiving_datareader_crypto); + /* fall-through */ + case PLUGIN_MODE_TOKEN_LOG: + return impl->instance->decode_datawriter_submessage (impl->instance, plain_rtps_submessage, + encoded_rtps_submessage, check_handle (receiving_datareader_crypto), check_handle (sending_datawriter_crypto), ex); + default: + return true; + } +} + +static DDS_Security_boolean decode_datareader_submessage( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_rtps_submessage, + const DDS_Security_OctetSeq *encoded_rtps_submessage, + const DDS_Security_DatawriterCryptoHandle receiving_datawriter_crypto, + const DDS_Security_DatareaderCryptoHandle sending_datareader_crypto, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_transform_impl *impl = (struct dds_security_crypto_transform_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_PLAIN_DATA: + case PLUGIN_MODE_WRAPPED: + log_encode_decode (impl->parent, DECODE_DATAREADER_SUBMESSAGE, receiving_datawriter_crypto); + /* fall-through */ + case PLUGIN_MODE_TOKEN_LOG: + return impl->instance->decode_datareader_submessage (impl->instance, plain_rtps_submessage, + encoded_rtps_submessage, check_handle (receiving_datawriter_crypto), check_handle (sending_datareader_crypto), ex); + default: + return true; + } +} + +static DDS_Security_boolean decode_serialized_payload( + dds_security_crypto_transform *instance, + DDS_Security_OctetSeq *plain_buffer, + const DDS_Security_OctetSeq *encoded_buffer, + const DDS_Security_OctetSeq *inline_qos, + const DDS_Security_DatareaderCryptoHandle receiving_datareader_crypto, + const DDS_Security_DatawriterCryptoHandle sending_datawriter_crypto, + DDS_Security_SecurityException *ex) +{ + struct dds_security_crypto_transform_impl *impl = (struct dds_security_crypto_transform_impl *)instance; + switch (impl->parent->mode) + { + case PLUGIN_MODE_WRAPPED: + case PLUGIN_MODE_TOKEN_LOG: + case PLUGIN_MODE_PLAIN_DATA: + return impl->instance->decode_serialized_payload(impl->instance, plain_buffer, encoded_buffer, + inline_qos, check_handle (receiving_datareader_crypto), check_handle (sending_datawriter_crypto), ex); + default: + return true; + } +} + +/** + * Init and finalize functions + */ +static struct dds_security_cryptography_impl * init_test_cryptography_common(const char *argument, bool wrapped, struct ddsi_domaingv *gv) +{ + struct dds_security_cryptography_impl *impl = (struct dds_security_cryptography_impl*) ddsrt_malloc(sizeof(*impl)); + memset(impl, 0, sizeof(*impl)); + + if (wrapped) + { + if (init_crypto(argument, (void **)&impl->instance, gv) != DDS_SECURITY_SUCCESS) + return NULL; + + impl->transform_wrap.instance = impl->instance->crypto_transform; + impl->factory_wrap.instance = impl->instance->crypto_key_factory; + impl->exchange_wrap.instance = impl->instance->crypto_key_exchange; + } + + impl->base.crypto_transform = (dds_security_crypto_transform *)&impl->transform_wrap; + impl->base.crypto_key_factory = (dds_security_crypto_key_factory *)&impl->factory_wrap; + impl->base.crypto_key_exchange = (dds_security_crypto_key_exchange *)&impl->exchange_wrap; + + impl->transform_wrap.parent = impl; + impl->factory_wrap.parent = impl; + impl->exchange_wrap.parent = impl; + + impl->factory_wrap.base.register_local_participant = ®ister_local_participant; + impl->factory_wrap.base.register_matched_remote_participant = ®ister_matched_remote_participant; + impl->factory_wrap.base.register_local_datawriter = ®ister_local_datawriter; + impl->factory_wrap.base.register_matched_remote_datareader = ®ister_matched_remote_datareader; + impl->factory_wrap.base.register_local_datareader = ®ister_local_datareader; + impl->factory_wrap.base.register_matched_remote_datawriter = ®ister_matched_remote_datawriter; + impl->factory_wrap.base.unregister_participant = &unregister_participant; + impl->factory_wrap.base.unregister_datawriter = &unregister_datawriter; + impl->factory_wrap.base.unregister_datareader = &unregister_datareader; + + impl->exchange_wrap.base.create_local_participant_crypto_tokens = &create_local_participant_crypto_tokens; + impl->exchange_wrap.base.set_remote_participant_crypto_tokens = &set_remote_participant_crypto_tokens; + impl->exchange_wrap.base.create_local_datawriter_crypto_tokens = &create_local_datawriter_crypto_tokens; + impl->exchange_wrap.base.set_remote_datawriter_crypto_tokens = &set_remote_datawriter_crypto_tokens; + impl->exchange_wrap.base.create_local_datareader_crypto_tokens = &create_local_datareader_crypto_tokens; + impl->exchange_wrap.base.set_remote_datareader_crypto_tokens = &set_remote_datareader_crypto_tokens; + impl->exchange_wrap.base.return_crypto_tokens = &return_crypto_tokens; + + impl->transform_wrap.base.encode_datawriter_submessage = &encode_datawriter_submessage; + impl->transform_wrap.base.encode_datareader_submessage = &encode_datareader_submessage; + impl->transform_wrap.base.encode_rtps_message = &encode_rtps_message; + impl->transform_wrap.base.decode_rtps_message = &decode_rtps_message; + impl->transform_wrap.base.preprocess_secure_submsg = &preprocess_secure_submsg; + impl->transform_wrap.base.decode_datawriter_submessage = &decode_datawriter_submessage; + impl->transform_wrap.base.decode_datareader_submessage = &decode_datareader_submessage; + impl->transform_wrap.base.decode_serialized_payload = &decode_serialized_payload; + impl->transform_wrap.base.encode_serialized_payload = &encode_serialized_payload; + + return impl; +} + +static int finalize_test_cryptography_common(struct dds_security_cryptography_impl * impl, bool wrapped) +{ + int ret; + if (wrapped && (ret = finalize_crypto(impl->instance)) != DDS_SECURITY_SUCCESS) + return ret; + ddsrt_free(impl); + return DDS_SECURITY_SUCCESS; +} + +int init_test_cryptography_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + struct dds_security_cryptography_impl *impl = init_test_cryptography_common(argument, false, gv); + if (!impl) + return DDS_SECURITY_FAILED; + impl->mode = PLUGIN_MODE_ALL_OK; + *context = impl; + return DDS_SECURITY_SUCCESS; +} + +int finalize_test_cryptography_all_ok(void *context) +{ + struct dds_security_cryptography_impl* impl = (struct dds_security_cryptography_impl*) context; + assert(impl->mode == PLUGIN_MODE_ALL_OK); + return finalize_test_cryptography_common(impl, false); +} + +int init_test_cryptography_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + struct dds_security_cryptography_impl *impl = init_test_cryptography_common(argument, false, gv); + if (!impl) + return DDS_SECURITY_FAILED; + impl->base.crypto_key_exchange->set_remote_participant_crypto_tokens = NULL; + impl->mode = PLUGIN_MODE_MISSING_FUNC; + *context = impl; + return DDS_SECURITY_SUCCESS; +} + +int finalize_test_cryptography_missing_func(void *context) +{ + struct dds_security_cryptography_impl* impl = (struct dds_security_cryptography_impl*) context; + assert(impl->mode == PLUGIN_MODE_MISSING_FUNC); + return finalize_test_cryptography_common(impl, false); +} + +static void init_encode_decode_log(struct dds_security_cryptography_impl *impl) +{ + ddsrt_mutex_init (&impl->encode_decode_log_lock); + ddsrt_circlist_init (&impl->encode_decode_log); +} + +static void fini_encode_decode_log(struct dds_security_cryptography_impl *impl) +{ + ddsrt_mutex_lock (&impl->encode_decode_log_lock); + while (!ddsrt_circlist_isempty (&impl->encode_decode_log)) + { + struct ddsrt_circlist_elem *list_elem = ddsrt_circlist_oldest (&impl->encode_decode_log); + ddsrt_circlist_remove (&impl->encode_decode_log, list_elem); + ddsrt_free (list_elem); + } + ddsrt_mutex_unlock (&impl->encode_decode_log_lock); + ddsrt_mutex_destroy (&impl->encode_decode_log_lock); +} + +int init_test_cryptography_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + struct dds_security_cryptography_impl *impl = init_test_cryptography_common(argument, true, gv); + if (!impl) + return DDS_SECURITY_FAILED; + impl->mode = PLUGIN_MODE_WRAPPED; + init_encode_decode_log(impl); + *context = impl; + return DDS_SECURITY_SUCCESS; +} + +int finalize_test_cryptography_wrapped(void *context) +{ + struct dds_security_cryptography_impl* impl = (struct dds_security_cryptography_impl*) context; + assert(impl->mode == PLUGIN_MODE_WRAPPED); + fini_encode_decode_log(impl); + return finalize_test_cryptography_common(impl, true); +} + +static void init_print_lock(void) +{ + ddsrt_mutex_init (&g_print_token_lock); +} + +int32_t init_test_cryptography_store_tokens(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + struct dds_security_cryptography_impl *impl = init_test_cryptography_common(argument, true, gv); + if (!impl) + return DDS_SECURITY_FAILED; + impl->mode = PLUGIN_MODE_TOKEN_LOG; + ddsrt_once (&lock_inited, &init_print_lock); + ddsrt_mutex_init (&impl->token_data_lock); + ddsrt_circlist_init (&impl->token_data_list); + *context = impl; + return DDS_SECURITY_SUCCESS; +} + +int32_t finalize_test_cryptography_store_tokens(void *context) +{ + struct dds_security_cryptography_impl* impl = (struct dds_security_cryptography_impl*) context; + assert(impl->mode == PLUGIN_MODE_TOKEN_LOG); + ddsrt_mutex_lock (&impl->token_data_lock); + while (!ddsrt_circlist_isempty (&impl->token_data_list)) + { + struct ddsrt_circlist_elem *list_elem = ddsrt_circlist_oldest (&impl->token_data_list); + ddsrt_circlist_remove (&impl->token_data_list, list_elem); + ddsrt_free (list_elem); + } + ddsrt_mutex_unlock (&impl->token_data_lock); + ddsrt_mutex_destroy (&impl->token_data_lock); + + /* don't detroy g_print_token_lock as this will result in multiple + calls to mutex_destroy for this lock in case of multiple domains */ + + return finalize_test_cryptography_common(impl, true); +} + +int init_test_cryptography_plain_data(const char *argument, void **context, struct ddsi_domaingv *gv) +{ + struct dds_security_cryptography_impl *impl = init_test_cryptography_common(argument, true, gv); + if (!impl) + return DDS_SECURITY_FAILED; + impl->mode = PLUGIN_MODE_PLAIN_DATA; + init_encode_decode_log(impl); + *context = impl; + return DDS_SECURITY_SUCCESS; +} + +int finalize_test_cryptography_plain_data(void *context) +{ + struct dds_security_cryptography_impl* impl = (struct dds_security_cryptography_impl*) context; + assert(impl->mode == PLUGIN_MODE_PLAIN_DATA); + fini_encode_decode_log(impl); + return finalize_test_cryptography_common(impl, true); +} + diff --git a/src/security/core/tests/common/cryptography_wrapper.h b/src/security/core/tests/common/cryptography_wrapper.h new file mode 100644 index 0000000..f466c55 --- /dev/null +++ b/src/security/core/tests/common/cryptography_wrapper.h @@ -0,0 +1,98 @@ +/* + * Copyright(c) 2006 to 2020 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 SECURITY_CORE_TEST_CRYPTO_WRAPPER_H_ +#define SECURITY_CORE_TEST_CRYPTO_WRAPPER_H_ + +#include "dds/ddsrt/circlist.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/dds_security_api_defs.h" +#include "dds/security/cryptography_wrapper_export.h" + +#define CRYPTO_TOKEN_MAXCOUNT 10 +#define CRYPTO_TOKEN_SIZE 256 + +struct dds_security_cryptography_impl; + +enum crypto_tokens_type { + LOCAL_PARTICIPANT_TOKENS, + LOCAL_WRITER_TOKENS, + LOCAL_READER_TOKENS, + REMOTE_PARTICIPANT_TOKENS, + REMOTE_WRITER_TOKENS, + REMOTE_READER_TOKENS, + TOKEN_TYPE_INVALID +}; + +struct crypto_token_data { + struct ddsrt_circlist_elem e; + enum crypto_tokens_type type; + DDS_Security_ParticipantCryptoHandle local_handle; + DDS_Security_ParticipantCryptoHandle remote_handle; + uint32_t n_tokens; + unsigned char data[CRYPTO_TOKEN_MAXCOUNT][CRYPTO_TOKEN_SIZE]; + size_t data_len[CRYPTO_TOKEN_MAXCOUNT]; +}; + +enum crypto_encode_decode_fn { + ENCODE_DATAWRITER_SUBMESSAGE, + ENCODE_DATAREADER_SUBMESSAGE, + DECODE_DATAWRITER_SUBMESSAGE, + DECODE_DATAREADER_SUBMESSAGE +}; + +struct crypto_encode_decode_data { + struct ddsrt_circlist_elem e; + enum crypto_encode_decode_fn function; + DDS_Security_long_long handle; + uint32_t count; +}; + +SECURITY_EXPORT void set_protection_kinds( + struct dds_security_cryptography_impl * impl, + DDS_Security_ProtectionKind rtps_protection_kind, + DDS_Security_ProtectionKind metadata_protection_kind, + DDS_Security_BasicProtectionKind payload_protection_kind); +SECURITY_EXPORT void set_encrypted_secret(struct dds_security_cryptography_impl * impl, const char * secret); +SECURITY_EXPORT void set_disc_protection_kinds( + struct dds_security_cryptography_impl * impl, + DDS_Security_ProtectionKind disc_protection_kind, + DDS_Security_ProtectionKind liveliness_protection_kind); +SECURITY_EXPORT void set_entity_data_secret(struct dds_security_cryptography_impl * impl, const char * pp_secret, const char * groupdata_secret, const char * ep_secret); +SECURITY_EXPORT void set_force_plain_data(struct dds_security_cryptography_impl * impl, DDS_Security_DatawriterCryptoHandle wr_handle, bool plain_rtps, bool plain_submsg, bool plain_payload); + +SECURITY_EXPORT const char *get_crypto_token_type_str (enum crypto_tokens_type type); +SECURITY_EXPORT struct ddsrt_circlist * get_crypto_tokens (struct dds_security_cryptography_impl * impl); +SECURITY_EXPORT struct crypto_token_data * find_crypto_token (struct dds_security_cryptography_impl * impl, enum crypto_tokens_type type, unsigned char * data, size_t data_len); +SECURITY_EXPORT struct crypto_encode_decode_data * get_encode_decode_log (struct dds_security_cryptography_impl * impl, enum crypto_encode_decode_fn function, DDS_Security_long_long handle); + +/* Init in all-ok mode: all functions return success without calling the actual plugin */ +SECURITY_EXPORT int init_test_cryptography_all_ok(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_cryptography_all_ok(void *context); + +/* Init in missing function mode: one of the function pointers is null */ +SECURITY_EXPORT int init_test_cryptography_missing_func(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_cryptography_missing_func(void *context); + +/* Init in wrapper mode */ +SECURITY_EXPORT int init_test_cryptography_wrapped(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_cryptography_wrapped(void *context); + +/* Init in store-token mode (stores all exchanged security tokens) */ +SECURITY_EXPORT int32_t init_test_cryptography_store_tokens(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int32_t finalize_test_cryptography_store_tokens(void *context); + +/* Init in plain-data mode (force plain data for payload, submsg and/or rtps) */ +SECURITY_EXPORT int init_test_cryptography_plain_data(const char *argument, void **context, struct ddsi_domaingv *gv); +SECURITY_EXPORT int finalize_test_cryptography_plain_data(void *context); + +#endif /* SECURITY_CORE_TEST_CRYPTO_WRAPPER_H_ */ diff --git a/src/security/core/tests/common/etc/create_p7s b/src/security/core/tests/common/etc/create_p7s new file mode 100755 index 0000000..904e7bd --- /dev/null +++ b/src/security/core/tests/common/etc/create_p7s @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +# Argument +if [ -z "$1" ] +then + echo "This script can be used for signing Permissions and Governance file list. Can be called from any directory" + echo "Expected a filename list with or without the .xml extension" + echo "PERMISSION_CA_CERT and PERMISSION_CA_KEY environment variables are used for signing if they are set" + exit +fi + +# Location of the pem files is the same as this script location. +PEM_LOCATION="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" +if [ -v PERMISSION_CA_CERT ] && [ -v PERMISSION_CA_KEY ] ; then + echo "Using custom permission key and certificate" + echo "PERMISSION_CA_CERT: $PERMISSION_CA_CERT" + echo "PERMISSION_CA_KEY: $PERMISSION_CA_KEY" +else + PERMISSION_CA_CERT=${PEM_LOCATION}/default_permissions_ca.pem + PERMISSION_CA_KEY=${PEM_LOCATION}/default_permissions_ca_key.pem +fi + +# Do all given files. +for filename in "$@" +do + if [ ${filename:${#filename}-4:4} == ".xml" ] ; then + BASE_FILE_NAME=${filename:0:-4} + echo $BASE_FILE_NAME + else + BASE_FILE_NAME=$filename + fi + + # Create the p7s file(s) + openssl smime -sign -in "${BASE_FILE_NAME}.xml" -text -out "${BASE_FILE_NAME}.p7s" -signer "$PERMISSION_CA_CERT" -inkey "$PERMISSION_CA_KEY" +done + diff --git a/src/security/core/tests/common/etc/default_governance.p7s b/src/security/core/tests/common/etc/default_governance.p7s new file mode 100644 index 0000000..0fae1eb --- /dev/null +++ b/src/security/core/tests/common/etc/default_governance.p7s @@ -0,0 +1,120 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----53BB1E1533C543713994C321F5A9998F" + +This is an S/MIME signed message + +------53BB1E1533C543713994C321F5A9998F +Content-Type: text/plain + + + + + + + + + 0 + 230 + + + + + false + + + true + + + ENCRYPT + + + ENCRYPT + + + ENCRYPT + + + + + * + + + true + + + true + + + true + + + true + + + ENCRYPT + + + ENCRYPT + + + + + + +------53BB1E1533C543713994C321F5A9998F +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIHoQYJKoZIhvcNAQcCoIIHkjCCB44CAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggRzMIIEbzCCA1egAwIBAgIUfoby6818hlJQ+41KUHiM6BZll/0w +DQYJKoZIhvcNAQELBQAwgcYxCzAJBgNVBAYTAk5MMQswCQYDVQQIDAJPVjEWMBQG +A1UEBwwNTG9jYWxpdHkgTmFtZTETMBEGA1UECwwKRXhhbXBsZSBPVTEgMB4GA1UE +CgwXRXhhbXBsZSBDQSBPcmdhbml6YXRpb24xHzAdBgNVBAMMFkV4YW1wbGUgUGVy +bWlzc2lvbnMgQ0ExOjA4BgkqhkiG9w0BCQEWK2F1dGhvcml0eUBjeWNsb25lZGRz +c2VjdXJpdHkuYWRsaW5rdGVjaC5jb20wHhcNMjAwMjI3MTM0ODA5WhcNMzAwMjI0 +MTM0ODA5WjCBxjELMAkGA1UEBhMCTkwxCzAJBgNVBAgMAk9WMRYwFAYDVQQHDA1M +b2NhbGl0eSBOYW1lMRMwEQYDVQQLDApFeGFtcGxlIE9VMSAwHgYDVQQKDBdFeGFt +cGxlIENBIE9yZ2FuaXphdGlvbjEfMB0GA1UEAwwWRXhhbXBsZSBQZXJtaXNzaW9u +cyBDQTE6MDgGCSqGSIb3DQEJARYrYXV0aG9yaXR5QGN5Y2xvbmVkZHNzZWN1cml0 +eS5hZGxpbmt0ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANNWwyrW3J+TCyaZH77q+29GGqFsYP5rv9cpcL/TMDNccsPYY+1RA1K+zMRYo1LG +8VdJNtJlhxE+tmEbKxsVUTtoj8zbLVU4P4g0gIh6U7LMv5lUEZ3XYKWvYrbZTFMo +f2rXQYGXPO7pFnvbNAbnMiLmagRKxKJ91kq4utuMG3U6rkCA7i2S8cEISNO3gIpF +a0IZJ8yS8wDlKa/LGxL90BYasLsSA6tw/69OIiUUYqpMRD+xxyyTkMO37VjmdiFL +Ha/dxO8HH0t3Q0U0AgZP9uwYTgZpN+2UEFnjv3BDIydc3Wa0UaSdxLtHXMPvg3sR +uH9CTqr4Le7/3uTYehYKgd0CAwEAAaNTMFEwHQYDVR0OBBYEFFi4pK986ZSB0BLi +Mm8ivu6AUxYPMB8GA1UdIwQYMBaAFFi4pK986ZSB0BLiMm8ivu6AUxYPMA8GA1Ud +EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHYLaJVWrLHg+62jC8yIz9db +ECIroX9Gb7Ll937HMum6Hj4wlImrifMVV3iORWBrBLvtTtn0Zno3mwfjLRQtkjOi +h71eJT+6//B7CT7noULJYVq8IRGErbKtmXULnxTajFApzO0v4hSu7rWj/Jfhil0T +X7QgKNpgKzjYodWz3oGGtchxvw3+v9wdIWD5Cj0bk/VMCQCaBV0anvyga7d4k8/z +PF7nW2Z9jNfKsVD1piFa+Yd4zN6XOPPKiFXfLD7ht9i2gG25iS+d95tKg1DfjnRD +7u0BJSOAPerxGtN/wf43qY1XzUoE2FBJ9QJGOA/02ffaUMOwSzICF/ShctH+Knkx +ggLyMIIC7gIBATCB3zCBxjELMAkGA1UEBhMCTkwxCzAJBgNVBAgMAk9WMRYwFAYD +VQQHDA1Mb2NhbGl0eSBOYW1lMRMwEQYDVQQLDApFeGFtcGxlIE9VMSAwHgYDVQQK +DBdFeGFtcGxlIENBIE9yZ2FuaXphdGlvbjEfMB0GA1UEAwwWRXhhbXBsZSBQZXJt +aXNzaW9ucyBDQTE6MDgGCSqGSIb3DQEJARYrYXV0aG9yaXR5QGN5Y2xvbmVkZHNz +ZWN1cml0eS5hZGxpbmt0ZWNoLmNvbQIUfoby6818hlJQ+41KUHiM6BZll/0wDQYJ +YIZIAWUDBAIBBQCggeQwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG +9w0BCQUxDxcNMjAwMjI3MTM0ODM0WjAvBgkqhkiG9w0BCQQxIgQgEOdJRhNPEiPV +hgGuWuTP8V074cDixAzQ31XymGEq0asweQYJKoZIhvcNAQkPMWwwajALBglghkgB +ZQMEASowCwYJYIZIAWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggq +hkiG9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwIC +ASgwDQYJKoZIhvcNAQEBBQAEggEAKGHnKKHlTdyGgbduE/dvtq4CteGtJJFE1z/Y +aG5xKd8NeInFIvMtGEoxp+hum1uh0819XRyHbOA5FUSB8y1HXNqqnfe6YwscD6Ds +Ux/nYtUrDuckZp+F1ulzsHe/lq7khtVaweck9YHt0iKUszn2fea774bR/ZjdZ0Fr ++6DBKLBR8XOlYK7m0HOjlOoN4O0qTCh100001884C0O75KXnOEGA6saf9epOwL0Z +LitRo9Evh20IvYlOzzDS5ddQqtOPgMDhq1dO8Mra4KKmYc6vj2gsNzQag0l0LkQa +lRQ/3YFTD0vAt09DzqUehNOZbr9pOYZYbP/z/Ov7zrb0+kPGzQ== + +------53BB1E1533C543713994C321F5A9998F-- + diff --git a/src/security/core/tests/common/etc/default_governance.xml b/src/security/core/tests/common/etc/default_governance.xml new file mode 100644 index 0000000..7d3e314 --- /dev/null +++ b/src/security/core/tests/common/etc/default_governance.xml @@ -0,0 +1,62 @@ + + + + + + + + 0 + 230 + + + + + false + + + true + + + ENCRYPT + + + ENCRYPT + + + ENCRYPT + + + + + * + + + true + + + true + + + true + + + true + + + ENCRYPT + + + ENCRYPT + + + + + diff --git a/src/security/core/tests/common/etc/default_permissions.p7s b/src/security/core/tests/common/etc/default_permissions.p7s new file mode 100644 index 0000000..4c8985b --- /dev/null +++ b/src/security/core/tests/common/etc/default_permissions.p7s @@ -0,0 +1,163 @@ +MIME-Version: 1.0 +Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha-256"; boundary="----82330497FB128B8C3833F86AA2902BC0" + +This is an S/MIME signed message + +------82330497FB128B8C3833F86AA2902BC0 +Content-Type: text/plain + + + + + + emailAddress=alice@cycloneddssecurity.adlinktech.com,CN=Alice Example,O=Example Organization,OU=Organizational Unit Name,L=Locality Name,ST=OV,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + * + + + + + * + + + * + + + + DENY + + + emailAddress=bob@cycloneddssecurity.adlinktech.com,CN=Bob Example,O=Example Organization,OU=Organizational Unit Name,L=Locality Name,ST=OV,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + * + + + + + * + + + * + + + + DENY + + + emailAddress=carol@cycloneddssecurity.adlinktech.com,CN=Carol Example,O=Example Organization,OU=Organizational Unit Name,L=Locality Name,ST=OV,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + * + + + + + * + + + * + + + + DENY + + + + +------82330497FB128B8C3833F86AA2902BC0 +Content-Type: application/x-pkcs7-signature; name="smime.p7s" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; filename="smime.p7s" + +MIIHoQYJKoZIhvcNAQcCoIIHkjCCB44CAQExDzANBglghkgBZQMEAgEFADALBgkq +hkiG9w0BBwGgggRzMIIEbzCCA1egAwIBAgIUfoby6818hlJQ+41KUHiM6BZll/0w +DQYJKoZIhvcNAQELBQAwgcYxCzAJBgNVBAYTAk5MMQswCQYDVQQIDAJPVjEWMBQG +A1UEBwwNTG9jYWxpdHkgTmFtZTETMBEGA1UECwwKRXhhbXBsZSBPVTEgMB4GA1UE +CgwXRXhhbXBsZSBDQSBPcmdhbml6YXRpb24xHzAdBgNVBAMMFkV4YW1wbGUgUGVy +bWlzc2lvbnMgQ0ExOjA4BgkqhkiG9w0BCQEWK2F1dGhvcml0eUBjeWNsb25lZGRz +c2VjdXJpdHkuYWRsaW5rdGVjaC5jb20wHhcNMjAwMjI3MTM0ODA5WhcNMzAwMjI0 +MTM0ODA5WjCBxjELMAkGA1UEBhMCTkwxCzAJBgNVBAgMAk9WMRYwFAYDVQQHDA1M +b2NhbGl0eSBOYW1lMRMwEQYDVQQLDApFeGFtcGxlIE9VMSAwHgYDVQQKDBdFeGFt +cGxlIENBIE9yZ2FuaXphdGlvbjEfMB0GA1UEAwwWRXhhbXBsZSBQZXJtaXNzaW9u +cyBDQTE6MDgGCSqGSIb3DQEJARYrYXV0aG9yaXR5QGN5Y2xvbmVkZHNzZWN1cml0 +eS5hZGxpbmt0ZWNoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +ANNWwyrW3J+TCyaZH77q+29GGqFsYP5rv9cpcL/TMDNccsPYY+1RA1K+zMRYo1LG +8VdJNtJlhxE+tmEbKxsVUTtoj8zbLVU4P4g0gIh6U7LMv5lUEZ3XYKWvYrbZTFMo +f2rXQYGXPO7pFnvbNAbnMiLmagRKxKJ91kq4utuMG3U6rkCA7i2S8cEISNO3gIpF +a0IZJ8yS8wDlKa/LGxL90BYasLsSA6tw/69OIiUUYqpMRD+xxyyTkMO37VjmdiFL +Ha/dxO8HH0t3Q0U0AgZP9uwYTgZpN+2UEFnjv3BDIydc3Wa0UaSdxLtHXMPvg3sR +uH9CTqr4Le7/3uTYehYKgd0CAwEAAaNTMFEwHQYDVR0OBBYEFFi4pK986ZSB0BLi +Mm8ivu6AUxYPMB8GA1UdIwQYMBaAFFi4pK986ZSB0BLiMm8ivu6AUxYPMA8GA1Ud +EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHYLaJVWrLHg+62jC8yIz9db +ECIroX9Gb7Ll937HMum6Hj4wlImrifMVV3iORWBrBLvtTtn0Zno3mwfjLRQtkjOi +h71eJT+6//B7CT7noULJYVq8IRGErbKtmXULnxTajFApzO0v4hSu7rWj/Jfhil0T +X7QgKNpgKzjYodWz3oGGtchxvw3+v9wdIWD5Cj0bk/VMCQCaBV0anvyga7d4k8/z +PF7nW2Z9jNfKsVD1piFa+Yd4zN6XOPPKiFXfLD7ht9i2gG25iS+d95tKg1DfjnRD +7u0BJSOAPerxGtN/wf43qY1XzUoE2FBJ9QJGOA/02ffaUMOwSzICF/ShctH+Knkx +ggLyMIIC7gIBATCB3zCBxjELMAkGA1UEBhMCTkwxCzAJBgNVBAgMAk9WMRYwFAYD +VQQHDA1Mb2NhbGl0eSBOYW1lMRMwEQYDVQQLDApFeGFtcGxlIE9VMSAwHgYDVQQK +DBdFeGFtcGxlIENBIE9yZ2FuaXphdGlvbjEfMB0GA1UEAwwWRXhhbXBsZSBQZXJt +aXNzaW9ucyBDQTE6MDgGCSqGSIb3DQEJARYrYXV0aG9yaXR5QGN5Y2xvbmVkZHNz +ZWN1cml0eS5hZGxpbmt0ZWNoLmNvbQIUfoby6818hlJQ+41KUHiM6BZll/0wDQYJ +YIZIAWUDBAIBBQCggeQwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG +9w0BCQUxDxcNMjAwMzI3MTMyMzM3WjAvBgkqhkiG9w0BCQQxIgQgZQWM3IUTViCR +9e+lYi65rV0rszQ5ZMG9iWStIWhT3UQweQYJKoZIhvcNAQkPMWwwajALBglghkgB +ZQMEASowCwYJYIZIAWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggq +hkiG9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwIC +ASgwDQYJKoZIhvcNAQEBBQAEggEAaZ687ayhsPnVPmsrPM4ECEU9/+PZAuFFV094 +Cqa9YLmsnO0jFElZLu2XRx1oNVp8TxG6OVckDINAxQjMO15+k0oqsAqdJFbgFLA/ +YidfEpuhFUjOy938Y46X6tbFj527GfLS8m3vIoYX+E+db1QcGv22RHb/KKSk6Htc +rbgEFV0pmyNK2foHp9ruBdu/nD7mXRo7h/xZdch60zDyeG40bsoKL63wC62sxQ/X +Mjxc1gmyXXr6AAEVzCVGIr9XHgaTNrThLfoWSRGcrLJI4cwevJ+jLJBBj347FmXi +x8nk6a09p7r9fSASX4vRiLDmDbuFwXolfNLS7Op3UKgkhJBm/A== + +------82330497FB128B8C3833F86AA2902BC0-- + diff --git a/src/security/core/tests/common/etc/default_permissions.xml b/src/security/core/tests/common/etc/default_permissions.xml new file mode 100644 index 0000000..d59a629 --- /dev/null +++ b/src/security/core/tests/common/etc/default_permissions.xml @@ -0,0 +1,105 @@ + + + + + emailAddress=alice@cycloneddssecurity.adlinktech.com,CN=Alice Example,O=Example Organization,OU=Organizational Unit Name,L=Locality Name,ST=OV,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + * + + + + + * + + + * + + + + DENY + + + emailAddress=bob@cycloneddssecurity.adlinktech.com,CN=Bob Example,O=Example Organization,OU=Organizational Unit Name,L=Locality Name,ST=OV,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + * + + + + + * + + + * + + + + DENY + + + emailAddress=carol@cycloneddssecurity.adlinktech.com,CN=Carol Example,O=Example Organization,OU=Organizational Unit Name,L=Locality Name,ST=OV,C=NL + + + 2015-09-15T01:00:00 + 2115-09-15T01:00:00 + + + + + 0 + 230 + + + + + * + + + * + + + + + * + + + * + + + + DENY + + + diff --git a/src/security/core/tests/common/etc/default_permissions_ca.pem b/src/security/core/tests/common/etc/default_permissions_ca.pem new file mode 100644 index 0000000..377a1e5 --- /dev/null +++ b/src/security/core/tests/common/etc/default_permissions_ca.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEbzCCA1egAwIBAgIUfoby6818hlJQ+41KUHiM6BZll/0wDQYJKoZIhvcNAQEL +BQAwgcYxCzAJBgNVBAYTAk5MMQswCQYDVQQIDAJPVjEWMBQGA1UEBwwNTG9jYWxp +dHkgTmFtZTETMBEGA1UECwwKRXhhbXBsZSBPVTEgMB4GA1UECgwXRXhhbXBsZSBD +QSBPcmdhbml6YXRpb24xHzAdBgNVBAMMFkV4YW1wbGUgUGVybWlzc2lvbnMgQ0Ex +OjA4BgkqhkiG9w0BCQEWK2F1dGhvcml0eUBjeWNsb25lZGRzc2VjdXJpdHkuYWRs +aW5rdGVjaC5jb20wHhcNMjAwMjI3MTM0ODA5WhcNMzAwMjI0MTM0ODA5WjCBxjEL +MAkGA1UEBhMCTkwxCzAJBgNVBAgMAk9WMRYwFAYDVQQHDA1Mb2NhbGl0eSBOYW1l +MRMwEQYDVQQLDApFeGFtcGxlIE9VMSAwHgYDVQQKDBdFeGFtcGxlIENBIE9yZ2Fu +aXphdGlvbjEfMB0GA1UEAwwWRXhhbXBsZSBQZXJtaXNzaW9ucyBDQTE6MDgGCSqG +SIb3DQEJARYrYXV0aG9yaXR5QGN5Y2xvbmVkZHNzZWN1cml0eS5hZGxpbmt0ZWNo +LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANNWwyrW3J+TCyaZ +H77q+29GGqFsYP5rv9cpcL/TMDNccsPYY+1RA1K+zMRYo1LG8VdJNtJlhxE+tmEb +KxsVUTtoj8zbLVU4P4g0gIh6U7LMv5lUEZ3XYKWvYrbZTFMof2rXQYGXPO7pFnvb +NAbnMiLmagRKxKJ91kq4utuMG3U6rkCA7i2S8cEISNO3gIpFa0IZJ8yS8wDlKa/L +GxL90BYasLsSA6tw/69OIiUUYqpMRD+xxyyTkMO37VjmdiFLHa/dxO8HH0t3Q0U0 +AgZP9uwYTgZpN+2UEFnjv3BDIydc3Wa0UaSdxLtHXMPvg3sRuH9CTqr4Le7/3uTY +ehYKgd0CAwEAAaNTMFEwHQYDVR0OBBYEFFi4pK986ZSB0BLiMm8ivu6AUxYPMB8G +A1UdIwQYMBaAFFi4pK986ZSB0BLiMm8ivu6AUxYPMA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQELBQADggEBAHYLaJVWrLHg+62jC8yIz9dbECIroX9Gb7Ll937H +Mum6Hj4wlImrifMVV3iORWBrBLvtTtn0Zno3mwfjLRQtkjOih71eJT+6//B7CT7n +oULJYVq8IRGErbKtmXULnxTajFApzO0v4hSu7rWj/Jfhil0TX7QgKNpgKzjYodWz +3oGGtchxvw3+v9wdIWD5Cj0bk/VMCQCaBV0anvyga7d4k8/zPF7nW2Z9jNfKsVD1 +piFa+Yd4zN6XOPPKiFXfLD7ht9i2gG25iS+d95tKg1DfjnRD7u0BJSOAPerxGtN/ +wf43qY1XzUoE2FBJ9QJGOA/02ffaUMOwSzICF/ShctH+Knk= +-----END CERTIFICATE----- diff --git a/src/security/core/tests/common/etc/default_permissions_ca_key.pem b/src/security/core/tests/common/etc/default_permissions_ca_key.pem new file mode 100644 index 0000000..e68bae1 --- /dev/null +++ b/src/security/core/tests/common/etc/default_permissions_ca_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA01bDKtbcn5MLJpkfvur7b0YaoWxg/mu/1ylwv9MwM1xyw9hj +7VEDUr7MxFijUsbxV0k20mWHET62YRsrGxVRO2iPzNstVTg/iDSAiHpTssy/mVQR +nddgpa9ittlMUyh/atdBgZc87ukWe9s0BucyIuZqBErEon3WSri624wbdTquQIDu +LZLxwQhI07eAikVrQhknzJLzAOUpr8sbEv3QFhqwuxIDq3D/r04iJRRiqkxEP7HH +LJOQw7ftWOZ2IUsdr93E7wcfS3dDRTQCBk/27BhOBmk37ZQQWeO/cEMjJ1zdZrRR +pJ3Eu0dcw++DexG4f0JOqvgt7v/e5Nh6FgqB3QIDAQABAoIBABFHMKGZ+2OYc/rt +3eiP8YqBYr/7ylpCmOaQXsVwEKrCTiew00qdqvXi337V+FRWK3kFZVQCNO61/9ck +j3uhXIjM3aTT7nrfJGKQWEnQJnOhxbBVbTNIXoBtPFbSoSjTUMd9Xb+oi7TEna/2 +leRSloi/6b78FeNrAlANlklIxR3qTjRSxjGYVfukCWsKq3uFfWM4Wp9N1B1gsyRo +/SH2jOu0XTLNdajggtBKcFoqxVIiaetERKVRRid7pW0zwuYS5Zwv5Wtl3XMbUuAn +VGesMeCKAGpwkLjmvXKBE5setnd7cWBKdVKddYDkzbDvU7X6QEHFnac6m6OQ2P62 +QfkO94ECgYEA70tV55AreDnPQEpf698ZjA8pYvF90GfGx/Y4oYWU/s0IlD6Pfbsr +qkRu+1I+SUNZWARhirXmJzuOmJYUQRteCEq+6RPJzn5Jl9MtipOBAjI0h589dbAB +8m/BRk+bEZKCXLgVa0TyZ/gd/wDBxB+qd+bPep8nAl4krMWK9W1+DLECgYEA4hfP +EwUPMwHrGlq0oRUA08ssQ8XxVCKWeS3cLAJjO6EdJyIUm/8S/UZPBPeSkGyZeld+ +fY7z9ZV0HA338p5BYYDCqgJC6b5Ud5UV0yLkq01v6b0H3nSjTPcbA61l9laN0vhm +QJ/xTiAHgsGBbOx2VtwDoE8T1AbAaamcapqNYu0CgYAXCiPdRc5JpxdDU2Xk6fgl +uhf8BNBeTn+fJR/SvW/ZEJiw3U0nh+vuWuRsokCJAUkK5nEVz+m3AU77dgfBNQda +uQeknVki3pnrWlPaMdWMBpV0MWrTd/zYANaVFHkTug1/K+I0D9FfHU6WDNabMYlS +PhDf947j9XiGggadFsu6IQKBgQC6dgpIVFbZqU5cuMvZQToicaA68Kd7zN6uZ7z5 +6qouRkyFtpyqnq3pha+rmAYe6AGXnUrrgBcAxdYxQO/o/s1K/WcN0LmgjmCZErIi +I9fU0xNmAIjZ1PXMhsqXuMyrYWyrvkKOL5pR5SZsluwHieh68A5pim3+4eaT/dbL +MFVEbQKBgQDfkeApSfKATXJpYIV/tiGjmRkkYoZ6NVar92npjlb72jaA4V0gHmuD +9ttypXOJPB/5zMa5uL6drp3CLv/GcWekUiUUXuyKQpcxZWqxf/leh9gTgGDAH/k4 +4+zX4HLEzTmoOc0cqzi4w6pTIj29BOV5QpnnyUGyvj8NGNSdFvZFSQ== +-----END RSA PRIVATE KEY----- diff --git a/src/security/core/tests/common/plugin_wrapper_msg_q.c b/src/security/core/tests/common/plugin_wrapper_msg_q.c new file mode 100644 index 0000000..0b03ded --- /dev/null +++ b/src/security/core/tests/common/plugin_wrapper_msg_q.c @@ -0,0 +1,135 @@ +/* + * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include "dds/dds.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/security/dds_security_api.h" +#include "dds/security/core/dds_security_utils.h" +#include "plugin_wrapper_msg_q.h" + +void insert_message(struct message_queue *queue, struct message *msg) +{ + ddsrt_mutex_lock(&queue->lock); + if (!queue->head) + queue->head = msg; + else + queue->tail->next = msg; + queue->tail = msg; + + ddsrt_cond_signal(&queue->cond); + ddsrt_mutex_unlock(&queue->lock); +} + +void add_message(struct message_queue *queue, message_kind_t kind, DDS_Security_IdentityHandle lidHandle, DDS_Security_IdentityHandle ridHandle, DDS_Security_IdentityHandle hsHandle, + const DDS_Security_GUID_t *lguid, const DDS_Security_GUID_t *rguid, DDS_Security_ValidationResult_t result, const char * err_msg, + const DDS_Security_DataHolder *token, void *instance) +{ + struct message *msg = ddsrt_malloc(sizeof(*msg)); + memset(msg, 0, sizeof(*msg)); + msg->kind = kind; + msg->lidHandle = lidHandle; + msg->ridHandle = ridHandle; + msg->hsHandle = hsHandle; + msg->result = result; + msg->err_msg = ddsrt_strdup (err_msg ? err_msg : ""); + if (lguid) + memcpy(&msg->lguid, lguid, sizeof(msg->lguid)); + if (rguid) + memcpy(&msg->rguid, rguid, sizeof(msg->rguid)); + if (token) + DDS_Security_DataHolder_copy(&msg->token, token); + msg->instance = instance; + + insert_message(queue, msg); +} + +void delete_message(struct message *msg) +{ + if (msg) + { + DDS_Security_DataHolder_deinit(&msg->token); + ddsrt_free(msg->err_msg); + ddsrt_free(msg); + } +} + +void init_message_queue(struct message_queue *queue) +{ + queue->head = NULL; + queue->tail = NULL; + ddsrt_mutex_init(&queue->lock); + ddsrt_cond_init(&queue->cond); +} + +void deinit_message_queue(struct message_queue *queue) +{ + struct message *msg = queue->head; + while (msg) + { + queue->head = msg->next; + delete_message(msg); + msg = queue->head; + } + ddsrt_cond_destroy(&queue->cond); + ddsrt_mutex_destroy(&queue->lock); +} + +int message_matched(struct message *msg, message_kind_t kind, DDS_Security_IdentityHandle lidHandle, DDS_Security_IdentityHandle ridHandle, DDS_Security_IdentityHandle hsHandle) +{ + return msg->kind == kind && + (!lidHandle || msg->lidHandle == lidHandle) && + (!ridHandle || msg->ridHandle == ridHandle) && + (!hsHandle || msg->hsHandle == hsHandle); +} + +enum take_message_result take_message(struct message_queue *queue, message_kind_t kind, DDS_Security_IdentityHandle lidHandle, DDS_Security_IdentityHandle ridHandle, DDS_Security_IdentityHandle hsHandle, dds_time_t abstimeout, struct message **msg) +{ + struct message *cur, *prev; + enum take_message_result ret = TAKE_MESSAGE_OK; + *msg = NULL; + ddsrt_mutex_lock(&queue->lock); + do + { + cur = queue->head; + prev = NULL; + while (cur && *msg == NULL) + { + if (message_matched(cur, kind, lidHandle, ridHandle, hsHandle)) + { + *msg = cur; + if (prev) + prev->next = cur->next; + else + queue->head = cur->next; + if (queue->tail == cur) + queue->tail = prev; + } + else + { + prev = cur; + cur = cur->next; + } + } + if (*msg == NULL) + { + if (!ddsrt_cond_waituntil(&queue->cond, &queue->lock, abstimeout)) + ret = queue->head ? TAKE_MESSAGE_TIMEOUT_NONEMPTY : TAKE_MESSAGE_TIMEOUT_EMPTY; + } + } while (ret == TAKE_MESSAGE_OK && *msg == NULL); + + ddsrt_mutex_unlock(&queue->lock); + return ret; +} diff --git a/src/security/core/tests/common/plugin_wrapper_msg_q.h b/src/security/core/tests/common/plugin_wrapper_msg_q.h new file mode 100644 index 0000000..c70e5f2 --- /dev/null +++ b/src/security/core/tests/common/plugin_wrapper_msg_q.h @@ -0,0 +1,68 @@ +/* + * Copyright(c) 2006 to 2020 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 SECURITY_CORE_PLUGIN_WRAPPER_MSG_Q_H_ +#define SECURITY_CORE_PLUGIN_WRAPPER_MSG_Q_H_ + +#include "dds/dds.h" +#include "dds/ddsrt/sync.h" + +#include "dds/security/dds_security_api.h" + +typedef enum { + MESSAGE_KIND_VALIDATE_LOCAL_IDENTITY, + MESSAGE_KIND_VALIDATE_REMOTE_IDENTITY, + MESSAGE_KIND_BEGIN_HANDSHAKE_REQUEST, + MESSAGE_KIND_BEGIN_HANDSHAKE_REPLY, + MESSAGE_KIND_PROCESS_HANDSHAKE +} message_kind_t; + +struct message { + message_kind_t kind; + DDS_Security_IdentityHandle lidHandle; + DDS_Security_IdentityHandle ridHandle; + DDS_Security_IdentityHandle hsHandle; + DDS_Security_GUID_t lguid; + DDS_Security_GUID_t rguid; + DDS_Security_ValidationResult_t result; + char * err_msg; + DDS_Security_DataHolder token; + void *instance; + struct message *next; +}; + +struct message_queue { + ddsrt_mutex_t lock; + ddsrt_cond_t cond; + struct message *head; + struct message *tail; +}; + +enum take_message_result { + TAKE_MESSAGE_OK, /* message found */ + TAKE_MESSAGE_TIMEOUT_EMPTY, /* no message found, queue is empty */ + TAKE_MESSAGE_TIMEOUT_NONEMPTY /* no message found, queue is not empty */ +}; + +struct dds_security_authentication_impl; + +void insert_message(struct message_queue *queue, struct message *msg); +void add_message(struct message_queue *queue, message_kind_t kind, DDS_Security_IdentityHandle lidHandle, DDS_Security_IdentityHandle ridHandle, DDS_Security_IdentityHandle hsHandle, + const DDS_Security_GUID_t *lguid, const DDS_Security_GUID_t *rguid, DDS_Security_ValidationResult_t result, const char * err_msg, + const DDS_Security_DataHolder *token, void *instance); +void delete_message(struct message *msg); +void init_message_queue(struct message_queue *queue); +void deinit_message_queue(struct message_queue *queue); +int message_matched(struct message *msg, message_kind_t kind, DDS_Security_IdentityHandle lidHandle, DDS_Security_IdentityHandle ridHandle, DDS_Security_IdentityHandle hsHandle); +enum take_message_result take_message(struct message_queue *queue, message_kind_t kind, DDS_Security_IdentityHandle lidHandle, DDS_Security_IdentityHandle ridHandle, DDS_Security_IdentityHandle hsHandle, dds_time_t abstimeout, struct message **msg); + + +#endif /* SECURITY_CORE_PLUGIN_WRAPPER_MSG_Q_H_ */ diff --git a/src/security/core/tests/common/security_config_test_utils.c b/src/security/core/tests/common/security_config_test_utils.c new file mode 100644 index 0000000..bde2eee --- /dev/null +++ b/src/security/core/tests/common/security_config_test_utils.c @@ -0,0 +1,379 @@ +/* + * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#include +#include + +#include "CUnit/Test.h" +#include "dds/dds.h" +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/expand_vars.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/io.h" +#include "dds/security/openssl_support.h" +#include "common/config_env.h" +#include "common/test_utils.h" +#include "security_config_test_utils.h" + +static const char *topic_rule = + " " + " ${TOPIC_EXPRESSION}" + " ${ENABLE_DISC_PROTECTION}" + " ${ENABLE_LIVELINESS_PROTECTION}" + " ${ENABLE_READ_AC}" + " ${ENABLE_WRITE_AC}" + " ${METADATA_PROTECTION_KIND}" + " ${DATA_PROTECTION_KIND}" + " "; + +static const char *governance_xml = + "" + "" + " " + " " + " " + " " + " 0" + " 230" + " " + " " + " ${ALLOW_UNAUTH_PP:-false}" + " ${ENABLE_JOIN_AC:-false}" + " ${DISCOVERY_PROTECTION_KIND:-NONE}" + " ${LIVELINESS_PROTECTION_KIND:-NONE}" + " ${RTPS_PROTECTION_KIND:-NONE}" + " " + " ${TOPIC_RULES}" + " " + " " + " " + ""; + +static const char *permissions_xml_pub = + " " + " ${TOPIC_NAME}" + " *" + " "; + +static const char *permissions_xml_sub = + " " + " ${TOPIC_NAME}" + " *" + " "; + +static const char *permissions_xml_allow_rule = + " " + " ${DOMAIN_ID:+}${DOMAIN_ID:-0230}${DOMAIN_ID:+}" + " ${PUBLISH}" + " ${SUBSCRIBE}" + " "; + +static const char *permissions_xml_deny_rule = + " " + " ${DOMAIN_ID:+}${DOMAIN_ID:-0230}${DOMAIN_ID:+}" + " ${PUBLISH}" + " ${SUBSCRIBE}" + " "; + +static const char *permissions_xml_grant = + " " + " ${SUBJECT_NAME}" + " ${NOT_BEFORE:-2015-09-15T01:00:00}${NOT_AFTER:-2115-09-15T01:00:00}" + " ${RULES}" + " ${DEFAULT_POLICY:-DENY}" + " "; + +static const char *permissions_xml = + "" + "" + " " + " ${GRANTS}" + " " + ""; + + +const char * expand_lookup_vars(const char *name, void * data) +{ + struct kvp *vars = (struct kvp *)data; + for (uint32_t i = 0; vars[i].key != NULL; i++) + { + if (!strcmp(vars[i].key, name)) + { + vars[i].count--; + return vars[i].value; + } + } + return NULL; +} + +const char * expand_lookup_vars_env(const char *name, void * data) +{ + const char *env; + if ((env = expand_lookup_vars (name, data))) + return env; + return ((ddsrt_getenv(name, &env)) == DDS_RETCODE_OK) ? env : NULL; +} + +int32_t expand_lookup_unmatched (const struct kvp * lookup_table) +{ + int32_t unmatched = 0; + for (uint32_t i = 0; lookup_table[i].key != NULL; i++) + { + int32_t c = lookup_table[i].count; + if (c > 0 && unmatched >= INT32_MAX - c) + return INT32_MAX; + if (c < 0 && unmatched <= INT32_MIN - c) + return INT32_MIN; + unmatched += c; + } + return unmatched; +} + +static char * get_xml_datetime(dds_time_t t, char * buf, size_t len) +{ + struct tm tm; + time_t sec = (time_t)(t / DDS_NSECS_IN_SEC); +#if _WIN32 + (void)gmtime_s(&tm, &sec); +#else + (void)gmtime_r(&sec, &tm); +#endif /* _WIN32 */ + + strftime(buf, len, "%FT%TZ", &tm); + return buf; +} + +static char * smime_sign(char * ca_cert_path, char * ca_priv_key_path, const char * data) +{ + dds_openssl_init (); + + // Read CA certificate + BIO *ca_cert_bio = BIO_new (BIO_s_file ()); + if (BIO_read_filename (ca_cert_bio, ca_cert_path) <= 0) + { + printf ("Error reading CA certificate file %s\n", ca_cert_path); + CU_ASSERT_FATAL (false); + } + + // Read CA private key + BIO *ca_priv_key_bio = BIO_new (BIO_s_file ()); + if (BIO_read_filename (ca_priv_key_bio, ca_priv_key_path) <= 0) + { + printf ("Error reading CA private key file %s\n", ca_priv_key_path); + CU_ASSERT_FATAL (false); + } + + // Create Openssl certificate and private key from the BIO's + X509 *ca_cert = PEM_read_bio_X509_AUX (ca_cert_bio, NULL, NULL, NULL); + EVP_PKEY* ca_priv_key = PEM_read_bio_PrivateKey (ca_priv_key_bio, NULL, 0, NULL); + + // Read the data + BIO *data_bio = BIO_new (BIO_s_mem ()); + if (BIO_puts (data_bio, data) <= 0) { + printf ("Error getting configuration data for signing\n"); + CU_ASSERT_FATAL (false); + } + + // Create the data signing object + PKCS7 *signed_data = PKCS7_sign (ca_cert, ca_priv_key, NULL, data_bio, PKCS7_DETACHED | PKCS7_STREAM | PKCS7_TEXT); + if (!signed_data) { + printf ("Error signing configuration data\n"); + CU_ASSERT_FATAL (false); + } + + // Create BIO for writing output + BIO *output_bio = BIO_new (BIO_s_mem ()); + if (!SMIME_write_PKCS7 (output_bio, signed_data, data_bio, PKCS7_DETACHED | PKCS7_STREAM | PKCS7_TEXT)) { + printf ("Error writing signed XML configuration\n"); + CU_ASSERT_FATAL (false); + } + + // Get string + char *output_tmp = NULL; + size_t output_sz = (size_t)BIO_get_mem_data (output_bio, &output_tmp); + char * output = ddsrt_malloc(output_sz + 1); + memcpy(output, output_tmp, output_sz); + output[output_sz] = 0; + + BIO_free (output_bio); + PKCS7_free (signed_data); + BIO_free (data_bio); + EVP_PKEY_free (ca_priv_key); + X509_free (ca_cert); + BIO_free (ca_priv_key_bio); + BIO_free (ca_cert_bio); + + return output; +} + +static char *get_signed_data(const char *data) +{ + return smime_sign ( + COMMON_ETC_PATH("default_permissions_ca.pem"), + COMMON_ETC_PATH("default_permissions_ca_key.pem"), + data); +} + +static char * prefix_data (char * config_signed, bool add_prefix) +{ + if (add_prefix) + { + char * tmp = config_signed; + ddsrt_asprintf (&config_signed, "data:,%s", tmp); + ddsrt_free (tmp); + } + return config_signed; +} + +static void print_config_vars(struct kvp *vars) +{ + for (uint32_t i = 0; vars[i].key != NULL; i++) + printf("%s=%s; ", vars[i].key, vars[i].value); +} + +char * get_governance_topic_rule(const char * topic_expr, bool discovery_protection, bool liveliness_protection, + bool read_ac, bool write_ac, DDS_Security_ProtectionKind metadata_protection_kind, DDS_Security_BasicProtectionKind data_protection_kind) +{ + struct kvp vars[] = { + { "TOPIC_EXPRESSION", topic_expr != NULL ? topic_expr : "*", 1 }, + { "ENABLE_DISC_PROTECTION", discovery_protection ? "true" : "false", 1 }, + { "ENABLE_LIVELINESS_PROTECTION", liveliness_protection ? "true" : "false", 1 }, + { "ENABLE_READ_AC", read_ac ? "true" : "false", 1 }, + { "ENABLE_WRITE_AC", write_ac ? "true" : "false", 1 }, + { "METADATA_PROTECTION_KIND", pk_to_str (metadata_protection_kind), 1 }, + { "DATA_PROTECTION_KIND", bpk_to_str (data_protection_kind), 1 }, + { NULL, NULL, 0 } + }; + return ddsrt_expand_vars (topic_rule, &expand_lookup_vars, vars); +} + +char * get_governance_config (bool allow_unauth_pp, bool enable_join_ac, DDS_Security_ProtectionKind discovery_protection_kind, DDS_Security_ProtectionKind liveliness_protection_kind, + DDS_Security_ProtectionKind rtps_protection_kind, const char * topic_rules, bool add_prefix) +{ + struct kvp vars[] = { + { "ALLOW_UNAUTH_PP", allow_unauth_pp ? "true" : "false", 1 }, + { "ENABLE_JOIN_AC", enable_join_ac ? "true" : "false", 1 }, + { "DISCOVERY_PROTECTION_KIND", pk_to_str (discovery_protection_kind), 1 }, + { "LIVELINESS_PROTECTION_KIND", pk_to_str (liveliness_protection_kind), 1 }, + { "RTPS_PROTECTION_KIND", pk_to_str (rtps_protection_kind), 1 }, + { "TOPIC_RULES", topic_rules != NULL ? topic_rules : get_governance_topic_rule (NULL, false, false, false, false, PK_N, BPK_N), 1 }, + { NULL, NULL, 0 } + }; + char * config = ddsrt_expand_vars (governance_xml, &expand_lookup_vars, vars); + char * config_signed = get_signed_data (config); + ddsrt_free (config); + + print_test_msg ("governance configuration: "); + print_config_vars (vars); + printf("\n"); + + return prefix_data (config_signed, add_prefix); +} + +static char * expand_permissions_pubsub (const char * template, const char * topic_name) +{ + struct kvp vars[] = { + { "TOPIC_NAME", topic_name, 1 }, + { NULL, NULL, 0 } + }; + return ddsrt_expand_vars (template, &expand_lookup_vars, vars); +} + +static char * expand_permissions_rule (const char * template, const char * domain_id, const char * pub_xml, const char * sub_xml) +{ + struct kvp vars[] = { + { "DOMAIN_ID", domain_id, 3 }, + { "PUBLISH", pub_xml, 1 }, + { "SUBSCRIBE", sub_xml, 1 }, + { NULL, NULL, 0 } + }; + return ddsrt_expand_vars (template, &expand_lookup_vars, vars); +} + +char * get_permissions_rules (const char * domain_id, const char * allow_pub_topic, const char * allow_sub_topic, const char * deny_pub_topic, const char * deny_sub_topic) +{ + char * allow_pub_xml = NULL, * allow_sub_xml = NULL, * deny_pub_xml = NULL, * deny_sub_xml = NULL; + char * allow_rule_xml = NULL, * deny_rule_xml = NULL, * rules_xml; + + if (allow_pub_topic != NULL) allow_pub_xml = expand_permissions_pubsub (permissions_xml_pub, allow_pub_topic); + if (allow_sub_topic != NULL) allow_sub_xml = expand_permissions_pubsub (permissions_xml_sub, allow_sub_topic); + if (deny_pub_topic != NULL) deny_pub_xml = expand_permissions_pubsub (permissions_xml_pub, deny_pub_topic); + if (deny_sub_topic != NULL) deny_sub_xml = expand_permissions_pubsub (permissions_xml_sub, deny_sub_topic); + + if (allow_pub_xml != NULL || allow_sub_xml != NULL) + { + allow_rule_xml = expand_permissions_rule (permissions_xml_allow_rule, domain_id, allow_pub_xml, allow_sub_xml); + if (allow_pub_xml != NULL) ddsrt_free (allow_pub_xml); + if (allow_sub_xml != NULL) ddsrt_free (allow_sub_xml); + } + if (deny_pub_xml != NULL || deny_sub_xml != NULL) + { + deny_rule_xml = expand_permissions_rule (permissions_xml_deny_rule, domain_id, deny_pub_xml, deny_sub_xml); + if (deny_pub_xml != NULL) ddsrt_free (deny_pub_xml); + if (deny_sub_xml != NULL) ddsrt_free (deny_sub_xml); + } + ddsrt_asprintf (&rules_xml, "%s%s", allow_rule_xml != NULL ? allow_rule_xml : "", deny_rule_xml != NULL ? deny_rule_xml : ""); + if (allow_rule_xml != NULL) ddsrt_free (allow_rule_xml); + if (deny_rule_xml != NULL) ddsrt_free (deny_rule_xml); + return rules_xml; +} + +char * get_permissions_grant (const char * grant_name, const char * subject_name, dds_time_t not_before, dds_time_t not_after, const char * rules_xml, const char * default_policy) +{ + char not_before_str[] = "0000-00-00T00:00:00Z"; + char not_after_str[] = "0000-00-00T00:00:00Z"; + get_xml_datetime (not_before, not_before_str, sizeof(not_before_str)); + get_xml_datetime (not_after, not_after_str, sizeof(not_after_str)); + + struct kvp vars[] = { + { "GRANT_NAME", grant_name, 1 }, + { "SUBJECT_NAME", subject_name, 1 }, + { "NOT_BEFORE", not_before_str, 1 }, + { "NOT_AFTER", not_after_str, 1 }, + { "RULES", rules_xml, 1 }, + { "DEFAULT_POLICY", default_policy, 1 }, + { NULL, NULL, 0 } + }; + char * res = ddsrt_expand_vars (permissions_xml_grant, &expand_lookup_vars, vars); + CU_ASSERT_FATAL (expand_lookup_unmatched (vars) == 0); + return res; +} + +char * get_permissions_default_grant (const char * grant_name, const char * subject_name, const char * topic_name) +{ + dds_time_t now = dds_time (); + char * rules_xml = get_permissions_rules (NULL, topic_name, topic_name, NULL, NULL); + char * grant_xml = get_permissions_grant (grant_name, subject_name, now, now + DDS_SECS(3600), rules_xml, "DENY"); + ddsrt_free (rules_xml); + return grant_xml; +} + +char * get_permissions_config(char * grants[], size_t ngrants, bool add_prefix) +{ + char *grants_str = NULL; + for (size_t n = 0; n < ngrants; n++) + { + char * tmp = grants_str; + ddsrt_asprintf (&grants_str, "%s%s", grants_str ? grants_str : "", grants[n]); + ddsrt_free (tmp); + } + struct kvp vars[] = { + { "GRANTS", grants_str, 1 }, + { NULL, NULL, 0} + }; + char *config = ddsrt_expand_vars (permissions_xml, &expand_lookup_vars, vars); + char *config_signed = get_signed_data (config); + ddsrt_free (grants_str); + ddsrt_free (config); + return prefix_data (config_signed, add_prefix); +} diff --git a/src/security/core/tests/common/security_config_test_utils.h b/src/security/core/tests/common/security_config_test_utils.h new file mode 100644 index 0000000..eaac17b --- /dev/null +++ b/src/security/core/tests/common/security_config_test_utils.h @@ -0,0 +1,40 @@ +/* + * Copyright(c) 2006 to 2020 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 SECURITY_CORE_TEST_SECURITY_CONFIG_TEST_UTILS_H_ +#define SECURITY_CORE_TEST_SECURITY_CONFIG_TEST_UTILS_H_ + +#include +#include "dds/ddsrt/environ.h" + +struct kvp { + const char *key; + const char *value; + int32_t count; +}; + +const char * expand_lookup_vars (const char *name, void * data); +const char * expand_lookup_vars_env (const char *name, void * data); +int32_t expand_lookup_unmatched (const struct kvp * lookup_table); + +char * get_governance_topic_rule (const char * topic_expr, bool discovery_protection, bool liveliness_protection, + bool read_ac, bool write_ac, DDS_Security_ProtectionKind metadata_protection_kind, DDS_Security_BasicProtectionKind data_protection_kind); +char * get_governance_config (bool allow_unauth_pp, bool enable_join_ac, DDS_Security_ProtectionKind discovery_protection_kind, DDS_Security_ProtectionKind liveliness_protection_kind, + DDS_Security_ProtectionKind rtps_protection_kind, const char * topic_rules, bool add_prefix); + +char * get_permissions_rules (const char * domain_id, const char * allow_pub_topic, const char * allow_sub_topic, + const char * deny_pub_topic, const char * deny_sub_topic); +char * get_permissions_grant (const char * grant_name, const char * subject_name, dds_time_t not_before, dds_time_t not_after, + const char * rules_xml, const char * default_policy); +char * get_permissions_default_grant (const char * grant_name, const char * subject_name, const char * topic_name); +char * get_permissions_config (char * grants[], size_t ngrants, bool add_prefix); + +#endif /* SECURITY_CORE_TEST_SECURITY_CONFIG_TEST_UTILS_H_ */ diff --git a/src/security/core/tests/common/test_identity.h b/src/security/core/tests/common/test_identity.h new file mode 100644 index 0000000..30bb916 --- /dev/null +++ b/src/security/core/tests/common/test_identity.h @@ -0,0 +1,354 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef PLUGIN_SECURITY_CORE_TEST_IDENTITY_H_ +#define PLUGIN_SECURITY_CORE_TEST_IDENTITY_H_ + +#define TEST_IDENTITY_CERTIFICATE_DUMMY "testtext_IdentityCertificate_testtext" +#define TEST_IDENTITY_PRIVATE_KEY_DUMMY "testtext_PrivateKey_testtext" +#define TEST_IDENTITY_CA_CERTIFICATE_DUMMY "testtext_IdentityCA_testtext" + +// Identity CAs +#define TEST_IDENTITY_CA1_CERTIFICATE "-----BEGIN CERTIFICATE-----\n\ +MIIEYzCCA0ugAwIBAgIUOp5yaGGuh0vaQTZHVPkX5jHoc/4wDQYJKoZIhvcNAQEL\n\ +BQAwgcAxCzAJBgNVBAYTAk5MMQswCQYDVQQIDAJPVjEWMBQGA1UEBwwNTG9jYWxp\n\ +dHkgTmFtZTETMBEGA1UECwwKRXhhbXBsZSBPVTEjMCEGA1UECgwaRXhhbXBsZSBJ\n\ +RCBDQSBPcmdhbml6YXRpb24xFjAUBgNVBAMMDUV4YW1wbGUgSUQgQ0ExOjA4Bgkq\n\ +hkiG9w0BCQEWK2F1dGhvcml0eUBjeWNsb25lZGRzc2VjdXJpdHkuYWRsaW5rdGVj\n\ +aC5jb20wHhcNMjAwMjI3MTkyMjA1WhcNMzAwMjI0MTkyMjA1WjCBwDELMAkGA1UE\n\ +BhMCTkwxCzAJBgNVBAgMAk9WMRYwFAYDVQQHDA1Mb2NhbGl0eSBOYW1lMRMwEQYD\n\ +VQQLDApFeGFtcGxlIE9VMSMwIQYDVQQKDBpFeGFtcGxlIElEIENBIE9yZ2FuaXph\n\ +dGlvbjEWMBQGA1UEAwwNRXhhbXBsZSBJRCBDQTE6MDgGCSqGSIb3DQEJARYrYXV0\n\ +aG9yaXR5QGN5Y2xvbmVkZHNzZWN1cml0eS5hZGxpbmt0ZWNoLmNvbTCCASIwDQYJ\n\ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALKhk7JXUpqJphyOC6oOI00LH49WTtO2\n\ +GCgDyJhcRYYAm7APMtmEDH+zptvd34N4eSu03Dc65cB/XN4Lbi2TjolVvKz0hHjz\n\ +tzmQT5jTgb1UkJX4NjKGw+RrYe9Ls0kfoAL2kvb12kmd1Oj4TIKMZP9TCrz7Vw8m\n\ +cZKQxZ56bLys6cU2XdiTp3v+Ef/vMll4+DINj4ZAMWL3CkT+q1G6ZxHRpFlsIyhc\n\ +Q1wX6gxUoY6cQdBA7TehKCCEWz4L1KM1A18ZmCHmjTniU0ssLoiAzsQs4b6Fnw8Z\n\ +MLFj8ocwzN5g66gJJWGofakXqX/V24KbGl54WX2X7FYU0tGzR234DXcCAwEAAaNT\n\ +MFEwHQYDVR0OBBYEFGeCcK8B74QWCuuCjlSUzOBBUTF5MB8GA1UdIwQYMBaAFGeC\n\ +cK8B74QWCuuCjlSUzOBBUTF5MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL\n\ +BQADggEBAJQeMc4XzMFnpQKCb58rzRs3Wt9FmZZS4O596sHxMEewTkEHm5gLYMzF\n\ +9JYEdUiLoTurQuIr0KgPi+Q3kliQdLfrVPbdWTmlUDZARR5ir5d1gGHST6qnb3Xi\n\ +mG+7nwle9R/hLrtPio+gYRgwJEiS55f6p0/E1wDcc+6numvjCRQ/CGIiJfwD/R+d\n\ +pv93YLEfuliZttfBc/apIu6OL4chxF+3QgSw1ltV5nXXqDTGHMRZENkp3Yiolumc\n\ +6smL4uA7Q812pVcENi3MLjdJgBS/8DcSBQHspVuXugaKKPDMkJnD0IyLWc8vLXh4\n\ +O7JdDrmusJAZA9RsTkinl3DuPfF34Sk=\n\ +-----END CERTIFICATE-----" + +#define TEST_IDENTITY_CA1_PRIVATE_KEY "-----BEGIN RSA PRIVATE KEY-----\n\ +MIIEowIBAAKCAQEAsqGTsldSmommHI4Lqg4jTQsfj1ZO07YYKAPImFxFhgCbsA8y\n\ +2YQMf7Om293fg3h5K7TcNzrlwH9c3gtuLZOOiVW8rPSEePO3OZBPmNOBvVSQlfg2\n\ +MobD5Gth70uzSR+gAvaS9vXaSZ3U6PhMgoxk/1MKvPtXDyZxkpDFnnpsvKzpxTZd\n\ +2JOne/4R/+8yWXj4Mg2PhkAxYvcKRP6rUbpnEdGkWWwjKFxDXBfqDFShjpxB0EDt\n\ +N6EoIIRbPgvUozUDXxmYIeaNOeJTSywuiIDOxCzhvoWfDxkwsWPyhzDM3mDrqAkl\n\ +Yah9qRepf9XbgpsaXnhZfZfsVhTS0bNHbfgNdwIDAQABAoIBAAylo+9cf1yxojEj\n\ +XXAM0DMENpfPZIVYvx0WJ32iCsoSAPPWH6OG1du0vHuUmd6VCP8vLug6I0odulV+\n\ +Oa7AY7cVeuZD6Z0mpDJPJVOMpgLhmdsEV9H7+KKTd7uZgHgM5SdQjdcuUOYlZo2Y\n\ +BtK3Xe810ezPXrqT3jaiSVuPD2PMO/LH3S+MSynHUZdou+NEr0S5FyX7HT2SUvPg\n\ +nEG5KUSE32/1Rnho9BacWKQ/HAoBiS+jMRHOPwu1Q/qS/QLw8HRDEuEoXlVYoNMc\n\ +il0r3M25COZVJVJecBqXHAWZqCBsqmNXs2hU1bh8VVKl/CMkG3W+IAR7XzMmw6bi\n\ +ZYAvgQECgYEA3pIeB8WptYv7hU0I1FZMfyhwLZDRSTZMlObTIXXsdSVKEllBwKAW\n\ +N0G84cyl7q+tOio63tbk1rQRi21O0wTrt16j+0SqDIYy59QhqXhiKAko+nf7cSpy\n\ +8h+k+HF5HpxsxcwYPiwO1SywPJ4TuDLIRHXXqschRzNtATrqCBtNeBsCgYEAzXX5\n\ +cQfMORsg0Z/K0d/U8JLdK0dnqsjwKt+9L7BAGOSv9Xxf4OT+vK3AlzkTUUOztXy7\n\ +3YzpSrHy1Dzu57Dv83BgCFPJxa7jKX4/n+SFYjqxcQVSziQAJjyaa0JsxYkxWC0K\n\ +IXg8MXYcgwHL6k/PYblQCJw8Lgtf8J2DtXhZTdUCgYAvt/4uRmfLX7bObqS8+b+u\n\ +55mde1YTr0ueBRsxKlpHB3apFm/tf6UjtblsY/cThKDMPq+ehU5M5hB45zemMIDl\n\ +MKpRvfgDdWZGpAmPjxrkYIpjoQPM0IASf0xcY9/G+1yqz8ZG1iVb+RfT90RdEq4z\n\ +V1yk5cqxvEnboKj6kff7DwKBgQCXnqbcVZ/MyIs4ho4awO4YNpkGNiR3cN9jFEc9\n\ +aPh0Jlb/drAee37M6AAG2LS7tJVqqcjNXw5N8/G509mNmxIH+Pa1TnfI7R1v4l27\n\ +dd1EtwF44S/RNdnyXaiq3JL+VxbV9i7SsjLhYUL7HplHqWvltuYr5He4luZO3z5x\n\ +7YUhnQKBgHmjhmSEPPxZLjPcYJ/z2opXalPJ5OObJ6nM6X4T5LvfhSnANdeeM6yj\n\ +gigRY8UlnNYzC5iSt17/VuMeta7I8GaVNUu7WU72Q7sYYlrXevdgl/0OFYayXHlB\n\ +sSo6yb9za+C2+5olHEZvs7dIzwDcveoEatds/X4VNrULEwaGbZR0\n\ +-----END RSA PRIVATE KEY-----" + +#define TEST_IDENTITY_CA2_CERTIFICATE "-----BEGIN CERTIFICATE-----\n\ +MIIEbTCCA1WgAwIBAgIUL0mSpPRgzveYTJ8UHSmOIwkIjjYwDQYJKoZIhvcNAQEL\n\ +BQAwgcUxCzAJBgNVBAYTAk5MMQswCQYDVQQIDAJPVjEWMBQGA1UEBwwNTG9jYWxp\n\ +dHkgTmFtZTETMBEGA1UECwwKRXhhbXBsZSBPVTElMCMGA1UECgwcRXhhbXBsZSBJ\n\ +RCBDQSAyIE9yZ2FuaXphdGlvbjEYMBYGA1UEAwwPRXhhbXBsZSBJRCBDQSAyMTsw\n\ +OQYJKoZIhvcNAQkBFixhdXRob3JpdHkyQGN5Y2xvbmVkZHNzZWN1cml0eS5hZGxp\n\ +bmt0ZWNoLmNvbTAeFw0yMDAyMjcxNjI3MjRaFw0zMDAyMjQxNjI3MjRaMIHFMQsw\n\ +CQYDVQQGEwJOTDELMAkGA1UECAwCT1YxFjAUBgNVBAcMDUxvY2FsaXR5IE5hbWUx\n\ +EzARBgNVBAsMCkV4YW1wbGUgT1UxJTAjBgNVBAoMHEV4YW1wbGUgSUQgQ0EgMiBP\n\ +cmdhbml6YXRpb24xGDAWBgNVBAMMD0V4YW1wbGUgSUQgQ0EgMjE7MDkGCSqGSIb3\n\ +DQEJARYsYXV0aG9yaXR5MkBjeWNsb25lZGRzc2VjdXJpdHkuYWRsaW5rdGVjaC5j\n\ +b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDk+ewDf871kPgBqXkm\n\ +UEXdf/vqWWoKx3KfJ4N3Gq4vt/cDOMs0xakpqr5uxm787AvbOui4P8QmT8naLhAA\n\ +TvHtNGg2LV0ZQtLcVVFsXXsBYDUEbLJYmCBtJU8zSfLLzgtN+z9nVqLthAcVyGhZ\n\ +iEkCfXKS4XzwjFUxgrXUM1VSiHHz8DbreQFDTF8mVavZ75HjieuHz1OcSaoIHCIF\n\ +mhPDlxRR/qZpc3Y52NZMNRHVPj4Tmc3N4H2eneeoG7nVn0MgNuqbssezeQtUOOoH\n\ +DgPGp3xzd8XQxaF5hVIM9E7aL77kw5v4gwccjL5xWC72zzxC3c1ltmbaEcwhHGsu\n\ +MR4lAgMBAAGjUzBRMB0GA1UdDgQWBBTTpmGTY5teWrZBA8Sd7kL5Lg/JmjAfBgNV\n\ +HSMEGDAWgBTTpmGTY5teWrZBA8Sd7kL5Lg/JmjAPBgNVHRMBAf8EBTADAQH/MA0G\n\ +CSqGSIb3DQEBCwUAA4IBAQCbelDJr9sVsYgQSp4yzSOSop5DSOWCweBF56NatcbY\n\ +3HUYc4iaH4NcB04WFkUl2XmqVCAM0zbmV0q4HoQikTK5PBHmwxuuD2HhPDWtMeFR\n\ +W96BjzGVpV27yaNIPvLwjTVV+A72r4vRvufiFhrMCovRwlWgHY6+gXKfrtyljTZ0\n\ +m1mENHOJOQWDXFAXP5yiehSMKy/izKvQ1G1hLErYMMc+sdgF/9X2KaudnTakTW0d\n\ +44kXUFKSU7mqV44D12unxCNODclznd31tiJ+70U39AXlR2BzwBzyFzPCh5JYtMog\n\ +TwbdLY3LN40gpkDUxIIH115D7ujUKNd8s2gmSHOCm1ar\n\ +-----END CERTIFICATE-----" + +#define TEST_IDENTITY_CA2_PRIVATE_KEY "-----BEGIN RSA PRIVATE KEY-----\n\ +MIIEogIBAAKCAQEA5PnsA3/O9ZD4Aal5JlBF3X/76llqCsdynyeDdxquL7f3AzjL\n\ +NMWpKaq+bsZu/OwL2zrouD/EJk/J2i4QAE7x7TRoNi1dGULS3FVRbF17AWA1BGyy\n\ +WJggbSVPM0nyy84LTfs/Z1ai7YQHFchoWYhJAn1ykuF88IxVMYK11DNVUohx8/A2\n\ +63kBQ0xfJlWr2e+R44nrh89TnEmqCBwiBZoTw5cUUf6maXN2OdjWTDUR1T4+E5nN\n\ +zeB9np3nqBu51Z9DIDbqm7LHs3kLVDjqBw4Dxqd8c3fF0MWheYVSDPRO2i++5MOb\n\ ++IMHHIy+cVgu9s88Qt3NZbZm2hHMIRxrLjEeJQIDAQABAoIBABBUirKNMPNujWGA\n\ +9rT20KTFde/2xItUQiZ7qPKbooSguCswp71xw2jHVqGL4WqEYywVfXd2hMS+uASp\n\ +eFatSq/CJxSGE7ezflpcc1wpJpaoh99y6R1MbDOcj5N22KwUW9YJ7zGtih0qZ170\n\ +VgzcnWhiDgPPtRtqxsCrM9CYgKNMGU6M9CFPX3PKDudKVU5fmi9bhtCqQaLhImbs\n\ +aQO3y4yI0af4KSQSur+eqeB/z7V39BEo1LfqaVQd1e9ItEYnTg8TaSaCshS4H8UG\n\ +Yx/pGhnxgn8+5LFL2K635Mb99OLb0hUwIOAbuoAuTlKijit0uGEJe/+DjbkcgZ5d\n\ +VB9I8UECgYEA/56Em8M6N6mTUN3WN+U8NSLltjSIL8kemK30dJ56aUsTiy4h0jNa\n\ +Jda7BeRPQcf9pnQpgFkV7XoKIbfTIqOhqD8XAvJL4//+VMmH2q/R2Xf6e0/CIEUe\n\ +3K74QyRVazx+tt+NOafCwjU9bA7ebjwQVsb+dPAS6kOWxTCZFzCgFk0CgYEA5VE+\n\ +U/C8D9zmJjL1uc4XkBNAg/dQNybQ9DX2Ku5dKME6yg4u7Lxnl3X9asvtQAsUeOPa\n\ +dKGkQ8NZfnSvXYd04n/FTRohFCaYz3RWIbo/q4KCsnJk6uAUM9YFeQGqZdEjO3Mu\n\ +Yk1uhHFl+C4Q/InzYEs+QwtMOS7XVMa5vm6OQzkCgYAR+xKU6ly0AaetLo2dDPD5\n\ +Q+UotfVGdz1BvCrP8T3nHjLXvXz/jkEvHDW3qmGw3OKIzO8Gaj3SoJ0J1iZx71S1\n\ +wwpZWLXh6eX4DN0Tkv6N75SdC/U50+Lh3yTzhCDGFFFNh9glUBmxE5Gogjs/QdZc\n\ +ZE8N5r1N4Uc/w7VhHjiEmQKBgHMA2pQ4P+horRdtKSTEwbZkoU9NYXI3SkWfJlSD\n\ +dD7zISuiD1B0cDNaXfwIR3R92geCpdUmF35QYvpzRFtQioLo9ybiusIjVTF9M5D4\n\ +mePGsQsTKZ9NP3R7mgUEm9MyHkw7SIDOOmW7hRsA503vVRnuwkvXR6PJ5P3EJ/Tj\n\ +9v6pAoGAfVTCJkf0aZ7KjV5GQ33l8uH9dEBzRJ4xOjGpeVBTm+L5N4ejcrQ4p9t0\n\ +JQr8hQHEp7tnHZ9H8DuIIQVDUJdrRa1qO+TNQiOdPLRNofXHuFDNIoj4+bP5ISnL\n\ +dImrEylWjCLbiiOpIbBmAQLb55xYsFzkdRCW3AlmldSVUW96yfU=\n\ +-----END RSA PRIVATE KEY-----" + +// Permissions CAs +#define TEST_PERMISSIONS_CA_CERTIFICATE "-----BEGIN CERTIFICATE-----\n\ +MIIEbzCCA1egAwIBAgIUfoby6818hlJQ+41KUHiM6BZll/0wDQYJKoZIhvcNAQEL\n\ +BQAwgcYxCzAJBgNVBAYTAk5MMQswCQYDVQQIDAJPVjEWMBQGA1UEBwwNTG9jYWxp\n\ +dHkgTmFtZTETMBEGA1UECwwKRXhhbXBsZSBPVTEgMB4GA1UECgwXRXhhbXBsZSBD\n\ +QSBPcmdhbml6YXRpb24xHzAdBgNVBAMMFkV4YW1wbGUgUGVybWlzc2lvbnMgQ0Ex\n\ +OjA4BgkqhkiG9w0BCQEWK2F1dGhvcml0eUBjeWNsb25lZGRzc2VjdXJpdHkuYWRs\n\ +aW5rdGVjaC5jb20wHhcNMjAwMjI3MTM0ODA5WhcNMzAwMjI0MTM0ODA5WjCBxjEL\n\ +MAkGA1UEBhMCTkwxCzAJBgNVBAgMAk9WMRYwFAYDVQQHDA1Mb2NhbGl0eSBOYW1l\n\ +MRMwEQYDVQQLDApFeGFtcGxlIE9VMSAwHgYDVQQKDBdFeGFtcGxlIENBIE9yZ2Fu\n\ +aXphdGlvbjEfMB0GA1UEAwwWRXhhbXBsZSBQZXJtaXNzaW9ucyBDQTE6MDgGCSqG\n\ +SIb3DQEJARYrYXV0aG9yaXR5QGN5Y2xvbmVkZHNzZWN1cml0eS5hZGxpbmt0ZWNo\n\ +LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANNWwyrW3J+TCyaZ\n\ +H77q+29GGqFsYP5rv9cpcL/TMDNccsPYY+1RA1K+zMRYo1LG8VdJNtJlhxE+tmEb\n\ +KxsVUTtoj8zbLVU4P4g0gIh6U7LMv5lUEZ3XYKWvYrbZTFMof2rXQYGXPO7pFnvb\n\ +NAbnMiLmagRKxKJ91kq4utuMG3U6rkCA7i2S8cEISNO3gIpFa0IZJ8yS8wDlKa/L\n\ +GxL90BYasLsSA6tw/69OIiUUYqpMRD+xxyyTkMO37VjmdiFLHa/dxO8HH0t3Q0U0\n\ +AgZP9uwYTgZpN+2UEFnjv3BDIydc3Wa0UaSdxLtHXMPvg3sRuH9CTqr4Le7/3uTY\n\ +ehYKgd0CAwEAAaNTMFEwHQYDVR0OBBYEFFi4pK986ZSB0BLiMm8ivu6AUxYPMB8G\n\ +A1UdIwQYMBaAFFi4pK986ZSB0BLiMm8ivu6AUxYPMA8GA1UdEwEB/wQFMAMBAf8w\n\ +DQYJKoZIhvcNAQELBQADggEBAHYLaJVWrLHg+62jC8yIz9dbECIroX9Gb7Ll937H\n\ +Mum6Hj4wlImrifMVV3iORWBrBLvtTtn0Zno3mwfjLRQtkjOih71eJT+6//B7CT7n\n\ +oULJYVq8IRGErbKtmXULnxTajFApzO0v4hSu7rWj/Jfhil0TX7QgKNpgKzjYodWz\n\ +3oGGtchxvw3+v9wdIWD5Cj0bk/VMCQCaBV0anvyga7d4k8/zPF7nW2Z9jNfKsVD1\n\ +piFa+Yd4zN6XOPPKiFXfLD7ht9i2gG25iS+d95tKg1DfjnRD7u0BJSOAPerxGtN/\n\ +wf43qY1XzUoE2FBJ9QJGOA/02ffaUMOwSzICF/ShctH+Knk=\n\ +-----END CERTIFICATE-----" + +#define TEST_PERMISSIONS_CA_PRIVATE_KEY "-----BEGIN RSA PRIVATE KEY-----\n\ +MIIEpAIBAAKCAQEA01bDKtbcn5MLJpkfvur7b0YaoWxg/mu/1ylwv9MwM1xyw9hj\n\ +7VEDUr7MxFijUsbxV0k20mWHET62YRsrGxVRO2iPzNstVTg/iDSAiHpTssy/mVQR\n\ +nddgpa9ittlMUyh/atdBgZc87ukWe9s0BucyIuZqBErEon3WSri624wbdTquQIDu\n\ +LZLxwQhI07eAikVrQhknzJLzAOUpr8sbEv3QFhqwuxIDq3D/r04iJRRiqkxEP7HH\n\ +LJOQw7ftWOZ2IUsdr93E7wcfS3dDRTQCBk/27BhOBmk37ZQQWeO/cEMjJ1zdZrRR\n\ +pJ3Eu0dcw++DexG4f0JOqvgt7v/e5Nh6FgqB3QIDAQABAoIBABFHMKGZ+2OYc/rt\n\ +3eiP8YqBYr/7ylpCmOaQXsVwEKrCTiew00qdqvXi337V+FRWK3kFZVQCNO61/9ck\n\ +j3uhXIjM3aTT7nrfJGKQWEnQJnOhxbBVbTNIXoBtPFbSoSjTUMd9Xb+oi7TEna/2\n\ +leRSloi/6b78FeNrAlANlklIxR3qTjRSxjGYVfukCWsKq3uFfWM4Wp9N1B1gsyRo\n\ +/SH2jOu0XTLNdajggtBKcFoqxVIiaetERKVRRid7pW0zwuYS5Zwv5Wtl3XMbUuAn\n\ +VGesMeCKAGpwkLjmvXKBE5setnd7cWBKdVKddYDkzbDvU7X6QEHFnac6m6OQ2P62\n\ +QfkO94ECgYEA70tV55AreDnPQEpf698ZjA8pYvF90GfGx/Y4oYWU/s0IlD6Pfbsr\n\ +qkRu+1I+SUNZWARhirXmJzuOmJYUQRteCEq+6RPJzn5Jl9MtipOBAjI0h589dbAB\n\ +8m/BRk+bEZKCXLgVa0TyZ/gd/wDBxB+qd+bPep8nAl4krMWK9W1+DLECgYEA4hfP\n\ +EwUPMwHrGlq0oRUA08ssQ8XxVCKWeS3cLAJjO6EdJyIUm/8S/UZPBPeSkGyZeld+\n\ +fY7z9ZV0HA338p5BYYDCqgJC6b5Ud5UV0yLkq01v6b0H3nSjTPcbA61l9laN0vhm\n\ +QJ/xTiAHgsGBbOx2VtwDoE8T1AbAaamcapqNYu0CgYAXCiPdRc5JpxdDU2Xk6fgl\n\ +uhf8BNBeTn+fJR/SvW/ZEJiw3U0nh+vuWuRsokCJAUkK5nEVz+m3AU77dgfBNQda\n\ +uQeknVki3pnrWlPaMdWMBpV0MWrTd/zYANaVFHkTug1/K+I0D9FfHU6WDNabMYlS\n\ +PhDf947j9XiGggadFsu6IQKBgQC6dgpIVFbZqU5cuMvZQToicaA68Kd7zN6uZ7z5\n\ +6qouRkyFtpyqnq3pha+rmAYe6AGXnUrrgBcAxdYxQO/o/s1K/WcN0LmgjmCZErIi\n\ +I9fU0xNmAIjZ1PXMhsqXuMyrYWyrvkKOL5pR5SZsluwHieh68A5pim3+4eaT/dbL\n\ +MFVEbQKBgQDfkeApSfKATXJpYIV/tiGjmRkkYoZ6NVar92npjlb72jaA4V0gHmuD\n\ +9ttypXOJPB/5zMa5uL6drp3CLv/GcWekUiUUXuyKQpcxZWqxf/leh9gTgGDAH/k4\n\ +4+zX4HLEzTmoOc0cqzi4w6pTIj29BOV5QpnnyUGyvj8NGNSdFvZFSQ==\n\ +-----END RSA PRIVATE KEY-----" + + +// Identities + +// created with TEST_IDENTITY_CA1_CERTIFICATE +#define TEST_IDENTITY1_CERTIFICATE "-----BEGIN CERTIFICATE-----\n\ +MIIEDTCCAvUCFHZ4yXyk/9yeMxgHs6Ib0bLKhXYuMA0GCSqGSIb3DQEBCwUAMIHA\n\ +MQswCQYDVQQGEwJOTDELMAkGA1UECAwCT1YxFjAUBgNVBAcMDUxvY2FsaXR5IE5h\n\ +bWUxEzARBgNVBAsMCkV4YW1wbGUgT1UxIzAhBgNVBAoMGkV4YW1wbGUgSUQgQ0Eg\n\ +T3JnYW5pemF0aW9uMRYwFAYDVQQDDA1FeGFtcGxlIElEIENBMTowOAYJKoZIhvcN\n\ +AQkBFithdXRob3JpdHlAY3ljbG9uZWRkc3NlY3VyaXR5LmFkbGlua3RlY2guY29t\n\ +MB4XDTIwMDIyNzE5MjQwMVoXDTMwMDIyNDE5MjQwMVowgcQxCzAJBgNVBAYTAk5M\n\ +MQswCQYDVQQIDAJPVjEWMBQGA1UEBwwNTG9jYWxpdHkgTmFtZTEhMB8GA1UECwwY\n\ +T3JnYW5pemF0aW9uYWwgVW5pdCBOYW1lMR0wGwYDVQQKDBRFeGFtcGxlIE9yZ2Fu\n\ +aXphdGlvbjEWMBQGA1UEAwwNQWxpY2UgRXhhbXBsZTE2MDQGCSqGSIb3DQEJARYn\n\ +YWxpY2VAY3ljbG9uZWRkc3NlY3VyaXR5LmFkbGlua3RlY2guY29tMIIBIjANBgkq\n\ +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5mEhLZIP2ko1bRJyJCwbnvhIpXFv6GOh\n\ +nvuS5v8tsTju40O62NNQmKT/my1QVKiUu7OoWZtLNBebgxgJ851eQ4TBRXy/f2jG\n\ +kLPYM22dohLTblVCpGutn+Itw3QRM3nkne7Sk8O6FP6NH6Y+7gkjxy5kI3GvhuIC\n\ +uBIzAV4dHK+hPlCn/Z+W33W71/ZAmnmI+2GaWiu5tjAQyFcmqWbi0BD7TWqBqidZ\n\ +2n7LTImUtp8NrYLfhzvgNLr9BZe7uf+T3mgdwcHtfi98GA94Lo6lqGeygiwig746\n\ +Y5uW4c6whsbd6riJ8FG1l8O86Ump4bSKChxjeoTLj4M4KX615kYa4QIDAQABMA0G\n\ +CSqGSIb3DQEBCwUAA4IBAQAM2g7v3FaA+d1zDkvDF5emCRL+R9H8pgimEOENrZTV\n\ +iK/kl8Hm7xkO7/LZ3y/kXpQpth8FtFS6LsZBAXPYabfADeDFVImnOD6UbWewwHQR\n\ +01gxkmYL/1nco/g3AsX/Ledh2ihwClGp+d6vNm5xF+Gw8Ux0YvH/aHy4RKg7mE/S\n\ +nonfHWRlT2tw1OtohTVhmBn00Jvj0IzSAiNvpmZHVRLYL9JRb5awYSX5XGetpoFM\n\ +VwzWIaZ06idvCtPKTfP71jJypV3+I2g5PNqranbuMv5nNAKZq1QlSB07f2Z1VIu6\n\ +6jeSZSADfm73qnE2Kj1PiZkPn0Wu+K24GXCvdILATcUS\n\ +-----END CERTIFICATE-----" + +#define TEST_IDENTITY1_PRIVATE_KEY "-----BEGIN RSA PRIVATE KEY-----\n\ +MIIEpQIBAAKCAQEA5mEhLZIP2ko1bRJyJCwbnvhIpXFv6GOhnvuS5v8tsTju40O6\n\ +2NNQmKT/my1QVKiUu7OoWZtLNBebgxgJ851eQ4TBRXy/f2jGkLPYM22dohLTblVC\n\ +pGutn+Itw3QRM3nkne7Sk8O6FP6NH6Y+7gkjxy5kI3GvhuICuBIzAV4dHK+hPlCn\n\ +/Z+W33W71/ZAmnmI+2GaWiu5tjAQyFcmqWbi0BD7TWqBqidZ2n7LTImUtp8NrYLf\n\ +hzvgNLr9BZe7uf+T3mgdwcHtfi98GA94Lo6lqGeygiwig746Y5uW4c6whsbd6riJ\n\ +8FG1l8O86Ump4bSKChxjeoTLj4M4KX615kYa4QIDAQABAoIBAAtNMoJ4ytxLjaln\n\ +IUBTBZvb1DyBfxroYFJbRw6b8BLklxuBBBaE70w9s+hZ5bnxdzJqEtUqgBrzGYbp\n\ +0/smeixXw99zyjUm367Tk8SaGQSNZd/gwN8uBRt1zgbrl7htv2BcCeqDzIohHq0x\n\ +y56DxkSMKw9uEU1NoxKCmgv0IPt6LlvjCwFhDv8iLu4lvu61F+ovVYIM6UXJJH0G\n\ +bHcJ1XnFBj5jCJFAWZRq7KxBgc4K3DlG+J7JcGEz89ZnZfGwcIiLqJ4rbU7E0ZE8\n\ +LslIHOwodtMDReIRWl6wEYmvd3mQizTXj2EWlRywQ/P3yFlxuHsGxPtRxdWoyXDc\n\ +Ii7GZK0CgYEA9KA+uEAMA5jZK0h1EMFoTiOIRe0x8CjlrHg4l0zU0ElcMeUXwoci\n\ +XqM0sjARiNgqkcMaONCb5bKgyxncWyWcamUxgp+bi2FUQIlBKHb56TCioPP0zzc6\n\ +yCiQ2cA8QW9PjL0WScJz3bCzeXrQceGZenDpPyphYE7SIUaRAOlMTMMCgYEA8RdP\n\ +QfYbOrcwgZB8ZycFE7lpZibe7Wh4UI1b/ipNZKcncr2pOZR+gVNv6eDQbV4z9xZY\n\ +5K6oU3rUcFHf0ZAi9xIpNzcq9q4+qOGO2OCEZX5tewXjKw9rwyDPUbv3yToFyZ9w\n\ +YwEKLfUgnYzpd5qn2NXa/pAZIoTh5ILF+EezD4sCgYEAr2lg0BoNA19NCn5wg01M\n\ +kAtmok3Nq1qIJr4mRkfvqlOQaq7N9M2V1arOFJ/nUus+yzrNyMO9pl4Kctjea/Vy\n\ +TdC2SeZNUQq/sW86a9u0pIQdebC1cQk3e2OrSplQG9PHhTHpk4Z+Mw+MAqYQZjjR\n\ +Jz1j48lt/fNHNlk1jSO9dKUCgYEAuYkJuqZuMBJ4Zs1Nn4ic1KAUp8N0Pdnu9XbD\n\ +++aMJtCogBnLWH+Zl2chsigL3o7niNiO0nZDHfNh94pap4i4D9HPHCn9i1du60Ki\n\ +Tu8BlKXmFQ3j0+iLMuBWC/2O5DId8BseP2K2dcW2MukVZrEDSNDTNqKoZTNEMDof\n\ +pkFvYJ8CgYEA6du9DFFZzIp5tuSIfVqCq5oxiNrRGJ/EpJEneBexrX56cC90sqLM\n\ +ecxDkgEVC592b004K1mjak3w6O0jYozQM1uvve38nZyMgtbMo3ORCtAO6Xszj8Oj\n\ +yNw1+km1Zy6EWdFEMciEFlbRwWVmDfE/um9LZsSWbmuWAOTww9GBDhc=\n\ +-----END RSA PRIVATE KEY-----" + + +// created with TEST_IDENTITY_CA2_CERTIFICATE +#define TEST_IDENTITY2_CERTIFICATE "-----BEGIN CERTIFICATE-----\n\ +MIIEDjCCAvYCFDEZQzcfGKK8IKNyH+AdNSjdyVgnMA0GCSqGSIb3DQEBCwUAMIHF\n\ +MQswCQYDVQQGEwJOTDELMAkGA1UECAwCT1YxFjAUBgNVBAcMDUxvY2FsaXR5IE5h\n\ +bWUxEzARBgNVBAsMCkV4YW1wbGUgT1UxJTAjBgNVBAoMHEV4YW1wbGUgSUQgQ0Eg\n\ +MiBPcmdhbml6YXRpb24xGDAWBgNVBAMMD0V4YW1wbGUgSUQgQ0EgMjE7MDkGCSqG\n\ +SIb3DQEJARYsYXV0aG9yaXR5MkBjeWNsb25lZGRzc2VjdXJpdHkuYWRsaW5rdGVj\n\ +aC5jb20wHhcNMjAwMjI3MTkyNjIwWhcNMzAwMjI0MTkyNjIwWjCBwDELMAkGA1UE\n\ +BhMCTkwxCzAJBgNVBAgMAk9WMRYwFAYDVQQHDA1Mb2NhbGl0eSBOYW1lMSEwHwYD\n\ +VQQLDBhPcmdhbml6YXRpb25hbCBVbml0IE5hbWUxHTAbBgNVBAoMFEV4YW1wbGUg\n\ +T3JnYW5pemF0aW9uMRQwEgYDVQQDDAtCb2IgRXhhbXBsZTE0MDIGCSqGSIb3DQEJ\n\ +ARYlYm9iQGN5Y2xvbmVkZHNzZWN1cml0eS5hZGxpbmt0ZWNoLmNvbTCCASIwDQYJ\n\ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMAQM9eN0zjTTdZALCTijog0oqx/kqnW\n\ +VtVWjV/c34OyPvUuH/DNRH6Cr0fI76UiooLD9nfvHe52X8oZH8WqNW7m7g7dMliu\n\ +DJD3yVpdLRmTTgl40ES8MTqmdb2y8ut70MJf5nUz0EQs9lXvnT0ru0B2CfyubiPt\n\ +aLSfyDoVBkRLbfzeqaNEQe7Ta6mQKZOckb6BHcaInb9GYEsU+OyOHuf2tCVNnRIH\n\ +ALiTPbA7rRS/J7ICS904/qz7w6km9Ta/oYQI5n0np64L+HqgtYZgIlVURW9grg2p\n\ +BuaX+xnJdRZbLQ0YYs+Gpmc1Vnykd+c2b0KP7zyHf8WFk9vV5W1ah2sCAwEAATAN\n\ +BgkqhkiG9w0BAQsFAAOCAQEA1RHDhLZf/UOR+azuH2lvD7ioSGRtdaOdJchSPdMk\n\ +v1q74PsHgm4/QAadVPdzvaIVV9kDfo6kGMzh+dCtq69EqVOavw1WUDo/NfuVSbgA\n\ +W7yeA39o3ROMO9UgbE5T3BPLq/XSXdIisP9OA4uXCnt22JELJaSv4m59FHg5gnQ7\n\ +2qOWRM7hi/+cQwescE+lDRw7PUzW8SS1HkQA1DmdtIIpWVuvYj7EPUNQX3jIetn8\n\ +AuPUgPJObxJhxJSC4p5qy37pYZHiNH1wG/+BDHgZo3wNwFsWqxabKziGB8XU3INc\n\ +USI3GDWM2jjElMSnDCj4ChM5wFbwWrqwdOEzeGWBWbo3hQ==\n\ +-----END CERTIFICATE-----" + +#define TEST_IDENTITY2_PRIVATE_KEY "-----BEGIN RSA PRIVATE KEY-----\n\ +MIIEpQIBAAKCAQEAwBAz143TONNN1kAsJOKOiDSirH+SqdZW1VaNX9zfg7I+9S4f\n\ +8M1EfoKvR8jvpSKigsP2d+8d7nZfyhkfxao1bubuDt0yWK4MkPfJWl0tGZNOCXjQ\n\ +RLwxOqZ1vbLy63vQwl/mdTPQRCz2Ve+dPSu7QHYJ/K5uI+1otJ/IOhUGREtt/N6p\n\ +o0RB7tNrqZApk5yRvoEdxoidv0ZgSxT47I4e5/a0JU2dEgcAuJM9sDutFL8nsgJL\n\ +3Tj+rPvDqSb1Nr+hhAjmfSenrgv4eqC1hmAiVVRFb2CuDakG5pf7Gcl1FlstDRhi\n\ +z4amZzVWfKR35zZvQo/vPId/xYWT29XlbVqHawIDAQABAoIBAFNm9cw15zI2+AcA\n\ +yOqfgzt8d+OmZl7gF8b+lde6B0meHp7Dj9U2nfa98zWd+QrhtmZIiH/eU0YZG1Gc\n\ +hWKFnjxxhZDo1xMRSZ2uLD7UVWBUyj9suiwO+OW6IUjmK3y8wJOXp3DftiHU0IfS\n\ +zJoiombEm2Ohr2xkjOJavE0UkisXQauc3K5AKv9coW9W6hzZf330Sm4sokmC5D3B\n\ +GcO/Keof2k2sFuv56wXPi9eGuXCEB2trhHhrxqncvb/fbRwpG1ELQsvZBnyuNNnY\n\ +FQcLYl52gkttP6EGvRPw1DFbQwsAJKnXBC7ddJaAl+JoKYAcGTt0+mRm0Z8ltzWl\n\ +c6uZQsECgYEA4NGiUMNq9kSn/6tQyPcsrphJ5uobu/svLaBipZ0vv2yQP3wQ5NPA\n\ +06KjwSm8gg8BLi0LCKplSxY09TwgUsc9unRkDTQ/eflgjdGA76lFKOjvLQdutxn7\n\ +eYNbx81WMY6E6n4y6K+2szpqW+Ds1At4ORRvweJWdFyc01bTqWNeuYsCgYEA2rOO\n\ +Ye6H2VixUfXzXwevBd4QyFJITW46WqnbYDFcUzf9pYBZfZoHU0YJqolDIhHhtHnG\n\ +soRi0Uk5P9D7Lvu+ZHAGQJrdmNELOMoqMNOqXcAdvK44qLLMwaLC8PS2zDIATrhZ\n\ +nc0TbeZJC8MynfIpxDsBVVMOa8u4eHRFdpk8ZaECgYEAlzuuCtJKQ7vPn2dpAqdz\n\ +gUekfxeA7KV+CR1Y/ruMgSLQrkQRQT1I+5Tuv2QKERty2dMnFv85AJfBrC50N/sb\n\ +hTAClfdNtAmTcBM8vvuJMInxSsMzMSzjQ8yfkvqIPvH2a5/VMz3wkwR6w6+84K+O\n\ +gidDPpO5QLGENY6097+G2x0CgYEAk7cdX0YGGaZPNiWiOLhu3c6slTEGRs5BucTq\n\ +OGF+k3LI7kTvrOchNXyjwLyvTE65nPV3YFIMkIEdmt3jGkvMv/fuMSqoq7PeGYBq\n\ +2MnOUz4Ul8Ew4bjKlasCck9HPEo1bPYVCYFfMyaMhdZU1NugnDqiXugXYHWb5jfa\n\ +Rw2e/qECgYEA3PvLLHklsRts6P37iSwUmDnkiopSSPfVdGXpDDGD/RbLpG6cSLRm\n\ +uh5n9+nxa2YXi0+LMLQvGpCSWk2k2qaRPpe2mahy9yAYrLhfDDcuGpSvw5BBJ3qw\n\ +mi1HgIUzXZTRBNamYCltJWYnN0hOlSL6vcHgeJ9y1gSDh0QqB2BG8HY=\n\ +-----END RSA PRIVATE KEY-----" + + +// created with TEST_IDENTITY_CA1_CERTIFICATE +#define TEST_IDENTITY3_CERTIFICATE "-----BEGIN CERTIFICATE-----\n\ +MIIEDTCCAvUCFHZ4yXyk/9yeMxgHs6Ib0bLKhXYvMA0GCSqGSIb3DQEBCwUAMIHA\n\ +MQswCQYDVQQGEwJOTDELMAkGA1UECAwCT1YxFjAUBgNVBAcMDUxvY2FsaXR5IE5h\n\ +bWUxEzARBgNVBAsMCkV4YW1wbGUgT1UxIzAhBgNVBAoMGkV4YW1wbGUgSUQgQ0Eg\n\ +T3JnYW5pemF0aW9uMRYwFAYDVQQDDA1FeGFtcGxlIElEIENBMTowOAYJKoZIhvcN\n\ +AQkBFithdXRob3JpdHlAY3ljbG9uZWRkc3NlY3VyaXR5LmFkbGlua3RlY2guY29t\n\ +MB4XDTIwMDMwNTEzMTczN1oXDTMwMDMwMzEzMTczN1owgcQxCzAJBgNVBAYTAk5M\n\ +MQswCQYDVQQIDAJPVjEWMBQGA1UEBwwNTG9jYWxpdHkgTmFtZTEhMB8GA1UECwwY\n\ +T3JnYW5pemF0aW9uYWwgVW5pdCBOYW1lMR0wGwYDVQQKDBRFeGFtcGxlIE9yZ2Fu\n\ +aXphdGlvbjEWMBQGA1UEAwwNQ2Fyb2wgRXhhbXBsZTE2MDQGCSqGSIb3DQEJARYn\n\ +Y2Fyb2xAY3ljbG9uZWRkc3NlY3VyaXR5LmFkbGlua3RlY2guY29tMIIBIjANBgkq\n\ +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0QduVwXptfjiwkvbn5aXuIpwZ9aWOqmj\n\ +e36qNknnS0mng1zPhzi4RLAl6CUxa6E5bkfjGZxFfYefDNk3ynzerEotFa1f5++b\n\ +aY73hs2ecfz+9ofjqR2fsroxOFwFF9JLbeWTDPS2mf5yE0Ci2+ctq6Ep4jDeHNui\n\ +WpSOY8OoIEWq4PD/R/VGJSiHSG+OjOUN7gwuxta0yglFeyHBdzr8mDZiejj1KYBD\n\ +AzuQrtaibHNtGBo3VGFvPKs85mK/Swv1GoXxcy1uBU1Yup9JLq3Ds8R5YYecSlXk\n\ +77EmZl4dgoScbt4NKTPuo8t803Ph3PYQCggILhlaEwjpfd1YTFLxOQIDAQABMA0G\n\ +CSqGSIb3DQEBCwUAA4IBAQAtV57Zc5dV9+z51zTOtghNZrFGJ48xJhnXddMVJ1Yh\n\ +08uoODRSRJHXNxMrlSRMeZ+CNkvd/QmqzOYvok3EqusOXFNU9qfmc3DToU/DDqkf\n\ +PMEpc9lPLTjmm6MfQgjyT5pDDNPUV9Io1s2o492ozr87ULyVf6I2bNu2NnVv2IzE\n\ +j9Mz/L7TkcgJgbdDl+21CR3NRA1PpxFB/PcM+zy4C2XoFv/qcF5pkcBpkyNjva9m\n\ +xmjSJWMoIVzXk6apPsRGCJLFJ3uuj+9K6POo/xgAkrbgvZF0i0yAJSTvSQmg6x2S\n\ +FMxE89kC7Npg+fQF15aaNEn4tuQiz0WW9pq1wSTXjoqj\n\ +-----END CERTIFICATE-----" + +#define TEST_IDENTITY3_PRIVATE_KEY "-----BEGIN RSA PRIVATE KEY-----\n\ +MIIEpAIBAAKCAQEA0QduVwXptfjiwkvbn5aXuIpwZ9aWOqmje36qNknnS0mng1zP\n\ +hzi4RLAl6CUxa6E5bkfjGZxFfYefDNk3ynzerEotFa1f5++baY73hs2ecfz+9ofj\n\ +qR2fsroxOFwFF9JLbeWTDPS2mf5yE0Ci2+ctq6Ep4jDeHNuiWpSOY8OoIEWq4PD/\n\ +R/VGJSiHSG+OjOUN7gwuxta0yglFeyHBdzr8mDZiejj1KYBDAzuQrtaibHNtGBo3\n\ +VGFvPKs85mK/Swv1GoXxcy1uBU1Yup9JLq3Ds8R5YYecSlXk77EmZl4dgoScbt4N\n\ +KTPuo8t803Ph3PYQCggILhlaEwjpfd1YTFLxOQIDAQABAoIBAGSpyHh+L3vj/QgG\n\ +0iB7vFsxyEopbDWaBlHtwPjeBFYchWBcrNB4/zyM++RdLPyhKvAyDGsD9+8pBe6B\n\ +GT4Zfn7IRgf/c4VVvalLIWc41IoehYaiEIAb9RF0W0nB/u3m505oVbXSj7F/eN5O\n\ +rV9raHIT7gCw+fY5y2kFy8C9s9S9+VzzYOzIZPWSh6Plc/eI2niSVt+MDufDeVOR\n\ +Ug6Z54lpXkwqv0Pz8F7ELyRGBvUW5UAvgyprvXgSYz1VNeHr3fmLX/O4rGktk02x\n\ +bAFxvaNV/JEK1fLFWLZ8TJVGsni+uYu/zkvXdxw7gphdoM77UKeZ00udg7orYUhW\n\ +6MwsuRUCgYEA7KzanZVPfbL4TMCpS6EJUO8H9lebH0srzqKNJD3/NL2JPebRNjZA\n\ +niH6vXD773/8IYlFTAXe0npVApZETKVzP4LNvsSVtjNvqXKdRM0cT47Dc4Y16kn/\n\ +X9Pd/ff+HH93T8Pcpguovw8QU7nxlf5dCvlnWrCj84Dw1ZToS2NLWAcCgYEA4hiy\n\ +nz6xvbkkUc5oHWxJIHxSLrOvMsyLMNp9UlUxgrxGqth0yQsFZwinPzs/y8aUVKyi\n\ +bHJlL35fpHeuna0V054E5vyeOOM7eLLFToDITS1m91hsl6amMW8iup/HTZhSemt7\n\ +tEn4mWlINXyP47MWfOr4oQ1KDzDCA3JFfzjInL8CgYBRulL3zcKYbn/tyS3s7twP\n\ +taszNwdbJBMplNpWZI5HQRguZxFhvhRMRwGV/3kQOErxrbxfRzutxQ6sCQXmzc9h\n\ +ZCL2OF5Wf6aUhf6m7olTM8JslzDxCcKE7d2fwM5gOugRhFoigK4x49rIftJc8Gxi\n\ +yMMW/x5ujN0ddAFPXyd6awKBgQCypX8lsnzwgsR+2w+LCA+z2md5PULWaaYlgM36\n\ +6xPG0AsqXQPSAqJPKhg0LxWWZp63VPy1oaHv5/OcWXCgZ63SWo5XEQ3Xtzw7f03F\n\ +XJ5n1NMB511Oaj/w2XZgbXUmC5BH6HuDFduXJAgJMxXifZPsOiEf6Ac3f3gdDwJ4\n\ +pp5kswKBgQDNUI3uzqw8J3e81tTAn2U8eyHuQxi8swv6K4Dx+sqCKpxkFcYvDLQl\n\ +qI+v234hvmZN3CmGPCY01aZl3NUUFKx9fvwweYG/vicCsA2XKwnmaSWTTrT62vlY\n\ +S1cWlJlUjw59ZhAqgD1pe4r0suRQ6e1OT/pByTKz1BxE/lwZftpauA==\n\ +-----END RSA PRIVATE KEY-----" + +#endif /* PLUGIN_SECURITY_CORE_TEST_IDENTITY_H_ */ diff --git a/src/security/core/tests/common/test_utils.c b/src/security/core/tests/common/test_utils.c new file mode 100644 index 0000000..39c0489 --- /dev/null +++ b/src/security/core/tests/common/test_utils.c @@ -0,0 +1,642 @@ +/* + * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include + +#include "CUnit/Test.h" +#include "dds/dds.h" +#include "dds/ddsrt/process.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/threads.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsi/q_entity.h" +#include "dds/ddsi/ddsi_entity_index.h" +#include "dds/ddsi/ddsi_security_omg.h" +#include "dds__entity.h" +#include "dds/security/dds_security_api.h" +#include "authentication_wrapper.h" +#include "test_utils.h" +#include "SecurityCoreTests.h" + +struct Identity localIdentityList[MAX_LOCAL_IDENTITIES]; +int numLocal = 0; + +struct Identity remoteIdentityList[MAX_REMOTE_IDENTITIES]; +int numRemote = 0; + +struct Handshake handshakeList[MAX_HANDSHAKES]; +int numHandshake = 0; + +const char * g_pk_none = "NONE"; +const char * g_pk_sign = "SIGN"; +const char * g_pk_encrypt = "ENCRYPT"; +const char * g_pk_sign_oa = "SIGN_WITH_ORIGIN_AUTHENTICATION"; +const char * g_pk_encrypt_oa = "ENCRYPT_WITH_ORIGIN_AUTHENTICATION"; + +static char * get_validation_result_str (DDS_Security_ValidationResult_t result) +{ + switch (result) + { + case DDS_SECURITY_VALIDATION_OK: return "OK"; + case DDS_SECURITY_VALIDATION_PENDING_RETRY: return "PENDING_RETRY"; + case DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST: return "PENDING_HANDSHAKE_REQUEST"; + case DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE: return "PENDING_HANDSHAKE_MESSAGE"; + case DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE: return "OK_FINAL_MESSAGE"; + case DDS_SECURITY_VALIDATION_FAILED: return "FAILED"; + } + abort (); + return ""; +} + +static char * get_node_type_str (enum hs_node_type node_type) +{ + switch (node_type) + { + case HSN_UNDEFINED: return "UNDEFINED"; + case HSN_REQUESTER: return "REQUESTER"; + case HSN_REPLIER: return "REPLIER"; + } + abort (); + return ""; +} + +void print_test_msg (const char *msg, ...) +{ + va_list args; + dds_time_t t = dds_time (); + printf ("%d.%06d ", (int32_t) (t / DDS_NSECS_IN_SEC), (int32_t) (t % DDS_NSECS_IN_SEC) / 1000); + va_start (args, msg); + vprintf (msg, args); + va_end (args); +} + +static void add_local_identity (DDS_Security_IdentityHandle handle, DDS_Security_GUID_t *guid) +{ + print_test_msg ("add local identity %"PRId64"\n", handle); + localIdentityList[numLocal].handle = handle; + memcpy (&localIdentityList[numLocal].guid, guid, sizeof(DDS_Security_GUID_t)); + numLocal++; +} + +static int find_local_identity (DDS_Security_IdentityHandle handle) +{ + for (int i = 0; i < (int) numLocal; i++) + { + if (localIdentityList[i].handle == handle) + return i; + } + return -1; +} + +static int find_remote_identity (DDS_Security_IdentityHandle handle) +{ + for (int i = 0; i < numRemote; i++) + { + if (remoteIdentityList[i].handle == handle) + return i; + } + return -1; +} + +static void add_remote_identity (DDS_Security_IdentityHandle handle, DDS_Security_GUID_t *guid) +{ + if (find_remote_identity (handle) < 0) + { + print_test_msg ("add remote identity %"PRId64"\n", handle); + remoteIdentityList[numRemote].handle = handle; + memcpy (&remoteIdentityList[numRemote].guid, guid, sizeof(DDS_Security_GUID_t)); + numRemote++; + } +} + +static void clear_stores(void) +{ + numLocal = 0; + numRemote = 0; + numHandshake = 0; +} + +static struct Handshake *add_handshake (enum hs_node_type node_type, DDS_Security_IdentityHandle lHandle, DDS_Security_IdentityHandle rHandle) +{ + print_test_msg ("add handshake %"PRId64"-%"PRId64"\n", lHandle, rHandle); + handshakeList[numHandshake].handle = -1; + handshakeList[numHandshake].node_type = node_type; + handshakeList[numHandshake].handshakeResult = DDS_SECURITY_VALIDATION_FAILED; + handshakeList[numHandshake].lidx = find_local_identity (lHandle); + handshakeList[numHandshake].ridx = find_remote_identity (rHandle); + handshakeList[numHandshake].finalResult = DDS_SECURITY_VALIDATION_FAILED; + handshakeList[numHandshake].err_msg = NULL; + numHandshake++; + return &handshakeList[numHandshake - 1]; +} + +static int find_handshake (DDS_Security_HandshakeHandle handle) +{ + for (int i = 0; i < numHandshake; i++) + { + if (handshakeList[i].handle == handle) + return i; + } + return -1; +} + +static void handle_process_message (dds_domainid_t domain_id, DDS_Security_IdentityHandle handshake, dds_time_t abstimeout) +{ + struct message *msg; + switch (test_authentication_plugin_take_msg (domain_id, MESSAGE_KIND_PROCESS_HANDSHAKE, 0, 0, handshake, abstimeout, &msg)) + { + case TAKE_MESSAGE_OK: { + int idx; + if ((idx = find_handshake (msg->hsHandle)) >= 0) + { + print_test_msg ("set handshake %"PRId64" final result to '%s' (errmsg: %s)\n", msg->hsHandle, get_validation_result_str (msg->result), msg->err_msg); + handshakeList[idx].finalResult = msg->result; + handshakeList[idx].err_msg = ddsrt_strdup (msg->err_msg); + } + test_authentication_plugin_release_msg (msg); + break; + } + case TAKE_MESSAGE_TIMEOUT_EMPTY: { + print_test_msg ("handle_process_message: timed out on empty queue\n"); + break; + } + case TAKE_MESSAGE_TIMEOUT_NONEMPTY: { + print_test_msg ("handle_process_message: timed out on non-empty queue\n"); + break; + } + } +} + +static void handle_begin_handshake_request (dds_domainid_t domain_id, struct Handshake *hs, DDS_Security_IdentityHandle lid, DDS_Security_IdentityHandle rid, dds_time_t abstimeout) +{ + struct message *msg; + print_test_msg ("handle begin handshake request %"PRId64"<->%"PRId64"\n", lid, rid); + switch (test_authentication_plugin_take_msg (domain_id, MESSAGE_KIND_BEGIN_HANDSHAKE_REQUEST, lid, rid, 0, abstimeout, &msg)) + { + case TAKE_MESSAGE_OK: { + hs->handle = msg->hsHandle; + hs->handshakeResult = msg->result; + if (msg->result != DDS_SECURITY_VALIDATION_FAILED) + handle_process_message (domain_id, msg->hsHandle, abstimeout); + else + hs->err_msg = ddsrt_strdup (msg->err_msg); + test_authentication_plugin_release_msg (msg); + break; + } + case TAKE_MESSAGE_TIMEOUT_EMPTY: { + print_test_msg ("handle_begin_handshake_request: timed out on empty queue\n"); + break; + } + case TAKE_MESSAGE_TIMEOUT_NONEMPTY: { + print_test_msg ("handle_begin_handshake_request: timed out on non-empty queue\n"); + break; + } + } +} + +static void handle_begin_handshake_reply (dds_domainid_t domain_id, struct Handshake *hs, DDS_Security_IdentityHandle lid, DDS_Security_IdentityHandle rid, dds_time_t abstimeout) +{ + struct message *msg; + print_test_msg ("handle begin handshake reply %"PRId64"<->%"PRId64"\n", lid, rid); + switch (test_authentication_plugin_take_msg (domain_id, MESSAGE_KIND_BEGIN_HANDSHAKE_REPLY, lid, rid, 0, abstimeout, &msg)) + { + case TAKE_MESSAGE_OK: { + hs->handle = msg->hsHandle; + hs->handshakeResult = msg->result; + if (msg->result != DDS_SECURITY_VALIDATION_FAILED) + handle_process_message (domain_id, msg->hsHandle, abstimeout); + else + hs->err_msg = ddsrt_strdup (msg->err_msg); + test_authentication_plugin_release_msg (msg); + break; + } + case TAKE_MESSAGE_TIMEOUT_EMPTY: { + print_test_msg ("handle_begin_handshake_reply: timed out on empty queue\n"); + break; + } + case TAKE_MESSAGE_TIMEOUT_NONEMPTY: { + print_test_msg ("handle_begin_handshake_reply: timed out on non-empty queue\n"); + break; + } + } +} + +static void handle_validate_remote_identity (dds_domainid_t domain_id, DDS_Security_IdentityHandle lid, int count, dds_time_t abstimeout) +{ + enum take_message_result res = TAKE_MESSAGE_OK; + struct message *msg; + while (count-- > 0 && (res = test_authentication_plugin_take_msg (domain_id, MESSAGE_KIND_VALIDATE_REMOTE_IDENTITY, lid, 0, 0, abstimeout, &msg)) == TAKE_MESSAGE_OK) + { + struct Handshake *hs; + add_remote_identity (msg->ridHandle, &msg->rguid); + hs = add_handshake (HSN_UNDEFINED, lid, msg->ridHandle); + if (msg->result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_REQUEST) + { + hs->node_type = HSN_REQUESTER; + handle_begin_handshake_request (domain_id, hs, lid, msg->ridHandle, abstimeout); + } + else if (msg->result == DDS_SECURITY_VALIDATION_PENDING_HANDSHAKE_MESSAGE) + { + hs->node_type = HSN_REPLIER; + handle_begin_handshake_reply (domain_id, hs, lid, msg->ridHandle, abstimeout); + } + else + { + print_test_msg ("validate remote failed\n"); + } + test_authentication_plugin_release_msg (msg); + } + + switch (res) + { + case TAKE_MESSAGE_OK: + break; + case TAKE_MESSAGE_TIMEOUT_EMPTY: + print_test_msg ("handle_validate_remote_identity: timed out on empty queue\n"); + break; + case TAKE_MESSAGE_TIMEOUT_NONEMPTY: + print_test_msg ("handle_validate_remote_identity: timed out on non-empty queue\n"); + break; + } +} + +static void handle_validate_local_identity (dds_domainid_t domain_id, bool exp_localid_fail, const char * exp_localid_msg, dds_time_t abstimeout) +{ + struct message *msg; + switch (test_authentication_plugin_take_msg (domain_id, MESSAGE_KIND_VALIDATE_LOCAL_IDENTITY, 0, 0, 0, abstimeout, &msg)) + { + case TAKE_MESSAGE_OK: + break; + case TAKE_MESSAGE_TIMEOUT_EMPTY: + print_test_msg ("handle_validate_local_identity: timed out on empty queue\n"); + break; + case TAKE_MESSAGE_TIMEOUT_NONEMPTY: + print_test_msg ("handle_validate_local_identity: timed out on non-empty queue\n"); + break; + } + CU_ASSERT_FATAL (msg != NULL); + CU_ASSERT_FATAL ((msg->result == DDS_SECURITY_VALIDATION_OK) != exp_localid_fail); + if (exp_localid_fail && exp_localid_msg) + { + print_test_msg ("validate_local_identity failed as expected (msg: %s)\n", msg->err_msg); + CU_ASSERT_FATAL (msg->err_msg && strstr (msg->err_msg, exp_localid_msg) != NULL); + } + else + { + add_local_identity (msg->lidHandle, &msg->lguid); + } + test_authentication_plugin_release_msg (msg); +} + +void validate_handshake (dds_domainid_t domain_id, bool exp_localid_fail, const char * exp_localid_msg, struct Handshake *hs_list[], int *nhs, dds_duration_t timeout) +{ + dds_time_t abstimeout = dds_time() + timeout; + clear_stores (); + + if (nhs) + *nhs = 0; + if (hs_list) + *hs_list = NULL; + + handle_validate_local_identity (domain_id, exp_localid_fail, exp_localid_msg, abstimeout); + if (!exp_localid_fail) + { + handle_validate_remote_identity (domain_id, localIdentityList[0].handle, 1, abstimeout); + for (int n = 0; n < numHandshake; n++) + { + struct Handshake *hs = &handshakeList[n]; + print_test_msg ("Result: hs %"PRId64", node type %s, final result %s\n", hs->handle, get_node_type_str (hs->node_type), get_validation_result_str (hs->finalResult)); + if (hs->err_msg && strlen (hs->err_msg)) + print_test_msg ("- err_msg: %s\n", hs->err_msg); + } + if (nhs) + *nhs = numHandshake; + if (hs_list) + *hs_list = handshakeList; + else + handshake_list_fini (handshakeList, numHandshake); + } + print_test_msg ("finished validate handshake for domain %d\n\n", domain_id); +} + +void validate_handshake_nofail (dds_domainid_t domain_id, dds_duration_t timeout) +{ + struct Handshake *hs_list; + int nhs; + validate_handshake (domain_id, false, NULL, &hs_list, &nhs, timeout); + for (int n = 0; n < nhs; n++) + { + struct Handshake hs = hs_list[n]; + DDS_Security_ValidationResult_t exp_result = hs.node_type == HSN_REQUESTER ? DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE : DDS_SECURITY_VALIDATION_OK; + CU_ASSERT_EQUAL_FATAL (hs.finalResult, exp_result); + } + handshake_list_fini (hs_list, nhs); +} + +void validate_handshake_result(struct Handshake *hs, bool exp_fail_hs_req, const char * fail_hs_req_msg, bool exp_fail_hs_reply, const char * fail_hs_reply_msg) +{ + DDS_Security_ValidationResult_t exp_result = hs->node_type == HSN_REQUESTER ? DDS_SECURITY_VALIDATION_OK_FINAL_MESSAGE : DDS_SECURITY_VALIDATION_OK; + if (hs->node_type == HSN_REQUESTER) + { + CU_ASSERT_EQUAL_FATAL (hs->finalResult, exp_fail_hs_req ? DDS_SECURITY_VALIDATION_FAILED : exp_result); + if (exp_fail_hs_req) + { + if (fail_hs_req_msg == NULL) + { + CU_ASSERT_EQUAL_FATAL (hs->err_msg, NULL); + } + else + { + CU_ASSERT_FATAL (hs->err_msg != NULL); + CU_ASSERT_FATAL (strstr(hs->err_msg, fail_hs_req_msg) != NULL); + } + } + } + else if (hs->node_type == HSN_REPLIER) + { + CU_ASSERT_EQUAL_FATAL (hs->finalResult, exp_fail_hs_reply ? DDS_SECURITY_VALIDATION_FAILED : exp_result); + if (exp_fail_hs_reply) + { + if (fail_hs_reply_msg == NULL) + { + CU_ASSERT_EQUAL_FATAL (hs->err_msg, NULL); + } + else + { + CU_ASSERT_FATAL (hs->err_msg != NULL); + CU_ASSERT_FATAL (strstr(hs->err_msg, fail_hs_reply_msg) != NULL); + } + } + } +} + +void handshake_list_fini (struct Handshake *hs_list, int nhs) +{ + for (int n = 0; n < nhs; n++) + { + struct Handshake hs = hs_list[n]; + ddsrt_free (hs.err_msg); + } +} + +void sync_writer_to_readers (dds_entity_t pp_wr, dds_entity_t wr, uint32_t exp_count, dds_duration_t timeout) +{ + dds_time_t abstimeout = dds_time() + timeout; + dds_attach_t triggered; + dds_entity_t ws = dds_create_waitset (pp_wr); + CU_ASSERT_FATAL (ws > 0); + dds_publication_matched_status_t pub_matched; + + dds_return_t ret = dds_waitset_attach (ws, wr, wr); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + while (true) + { + ret = dds_waitset_wait_until (ws, &triggered, 1, abstimeout); + CU_ASSERT_EQUAL_FATAL (exp_count > 0, ret >= 1); + if (exp_count > 0) + CU_ASSERT_EQUAL_FATAL (wr, (dds_entity_t)(intptr_t) triggered); + ret = dds_get_publication_matched_status (wr, &pub_matched); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + if (pub_matched.total_count >= exp_count) + break; + }; + dds_delete (ws); + CU_ASSERT_EQUAL_FATAL (pub_matched.total_count, exp_count); +} + +void sync_reader_to_writers (dds_entity_t pp_rd, dds_entity_t rd, uint32_t exp_count, dds_duration_t timeout) +{ + dds_time_t abstimeout = dds_time() + timeout; + dds_attach_t triggered; + dds_entity_t ws = dds_create_waitset (pp_rd); + CU_ASSERT_FATAL (ws > 0); + dds_subscription_matched_status_t sub_matched; + + dds_return_t ret = dds_waitset_attach (ws, rd, rd); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + while (true) + { + ret = dds_waitset_wait_until (ws, &triggered, 1, abstimeout); + CU_ASSERT_EQUAL_FATAL (exp_count > 0, ret >= 1); + if (exp_count > 0) + CU_ASSERT_EQUAL_FATAL (rd, (dds_entity_t)(intptr_t) triggered); + ret = dds_get_subscription_matched_status (rd, &sub_matched); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + if (sub_matched.total_count >= exp_count) + break; + }; + dds_delete (ws); + CU_ASSERT_EQUAL_FATAL (sub_matched.total_count, exp_count); +} + +char *create_topic_name (const char *prefix, uint32_t nr, char *name, size_t size) +{ + ddsrt_pid_t pid = ddsrt_getpid (); + ddsrt_tid_t tid = ddsrt_gettid (); + (void)snprintf(name, size, "%s%d_pid%" PRIdPID "_tid%" PRIdTID "", prefix, nr, pid, tid); + return name; +} + +bool reader_wait_for_data (dds_entity_t pp, dds_entity_t rd, dds_duration_t dur) +{ + dds_attach_t triggered; + dds_entity_t ws = dds_create_waitset (pp); + CU_ASSERT_FATAL (ws > 0); + dds_return_t ret = dds_waitset_attach (ws, rd, rd); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + ret = dds_waitset_wait (ws, &triggered, 1, dur); + if (ret > 0) + CU_ASSERT_EQUAL_FATAL (rd, (dds_entity_t)(intptr_t)triggered); + dds_delete (ws); + return ret > 0; +} + +dds_qos_t * get_default_test_qos (void) +{ + dds_qos_t * qos = dds_create_qos (); + CU_ASSERT_FATAL (qos != NULL); + dds_qset_history (qos, DDS_HISTORY_KEEP_ALL, -1); + dds_qset_durability (qos, DDS_DURABILITY_TRANSIENT_LOCAL); + dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_INFINITY); + return qos; +} + +void rd_wr_init_fail( + dds_entity_t pp_wr, dds_entity_t *pub, dds_entity_t *pub_tp, dds_entity_t *wr, + dds_entity_t pp_rd, dds_entity_t *sub, dds_entity_t *sub_tp, dds_entity_t *rd, + const char * topic_name, + bool exp_pubtp_fail, bool exp_wr_fail, + bool exp_subtp_fail, bool exp_rd_fail) +{ + dds_qos_t * qos = get_default_test_qos (); + *pub = dds_create_publisher (pp_wr, NULL, NULL); + CU_ASSERT_FATAL (*pub > 0); + *sub = dds_create_subscriber (pp_rd, NULL, NULL); + CU_ASSERT_FATAL (*sub > 0); + *pub_tp = dds_create_topic (pp_wr, &SecurityCoreTests_Type1_desc, topic_name, NULL, NULL); + CU_ASSERT_EQUAL_FATAL (exp_pubtp_fail, *pub_tp <= 0); + *sub_tp = dds_create_topic (pp_rd, &SecurityCoreTests_Type1_desc, topic_name, NULL, NULL); + CU_ASSERT_EQUAL_FATAL (exp_subtp_fail, *sub_tp <= 0); + if (!exp_pubtp_fail) + { + *wr = dds_create_writer (*pub, *pub_tp, qos, NULL); + CU_ASSERT_EQUAL_FATAL (exp_wr_fail, *wr <= 0); + if (exp_wr_fail) + goto fail; + dds_set_status_mask (*wr, DDS_PUBLICATION_MATCHED_STATUS); + } + if (!exp_subtp_fail) + { + *rd = dds_create_reader (*sub, *sub_tp, qos, NULL); + CU_ASSERT_EQUAL_FATAL (exp_rd_fail, *rd <= 0); + if (exp_rd_fail) + goto fail; + dds_set_status_mask (*rd, DDS_SUBSCRIPTION_MATCHED_STATUS); + } +fail: + dds_delete_qos (qos); +} + +void rd_wr_init( + dds_entity_t pp_wr, dds_entity_t *pub, dds_entity_t *pub_tp, dds_entity_t *wr, + dds_entity_t pp_rd, dds_entity_t *sub, dds_entity_t *sub_tp, dds_entity_t *rd, + const char * topic_name) +{ + rd_wr_init_fail (pp_wr, pub, pub_tp, wr, pp_rd, sub, sub_tp, rd, topic_name, false, false, false, false); +} + +void write_read_for(dds_entity_t wr, dds_entity_t pp_rd, dds_entity_t rd, dds_duration_t dur, bool exp_write_fail, bool exp_read_fail) +{ + SecurityCoreTests_Type1 sample = { 1, 1 }; + SecurityCoreTests_Type1 rd_sample; + void * samples[] = { &rd_sample }; + dds_sample_info_t info[1]; + dds_return_t ret; + dds_time_t tend = dds_time () + dur; + bool write_fail = false, read_fail = false; + + dds_set_status_mask (rd, DDS_DATA_AVAILABLE_STATUS); + do + { + print_test_msg ("write\n"); + if (dds_write (wr, &sample) != DDS_RETCODE_OK) + write_fail = true; + + while (!write_fail) + { + if ((ret = dds_take (rd, samples, info, 1, 1)) > 0) + { + print_test_msg ("take sample\n"); + if (info[0].instance_state != DDS_IST_ALIVE || !info[0].valid_data) + { + print_test_msg ("invalid sample instance_state=%d valid_data=%d\n", info[0].instance_state, info[0].valid_data); + read_fail = true; + } + else + CU_ASSERT_EQUAL_FATAL (rd_sample.value, 1); + CU_ASSERT_EQUAL_FATAL (ret, 1); + break; + } + if (ret < 0 || !reader_wait_for_data (pp_rd, rd, DDS_MSECS (1000))) + { + print_test_msg ("take no sample\n"); + read_fail = true; + break; + } + } + if (write_fail || read_fail) + break; + dds_sleepfor (DDS_MSECS (100)); + } + while (dds_time () < tend); + CU_ASSERT_EQUAL_FATAL (write_fail, exp_write_fail); + CU_ASSERT_EQUAL_FATAL (read_fail, exp_read_fail); +} + +#define GET_SECURITY_PLUGIN_CONTEXT(name_) \ + struct dds_security_##name_##_impl * get_##name_##_context(dds_entity_t participant) \ + { \ + struct dds_entity *pp_entity = NULL; \ + dds_return_t ret = dds_entity_lock (participant, DDS_KIND_PARTICIPANT, &pp_entity); \ + CU_ASSERT_EQUAL_FATAL (ret, 0); \ + thread_state_awake (lookup_thread_state(), &pp_entity->m_domain->gv); \ + struct participant *pp = entidx_lookup_participant_guid (pp_entity->m_domain->gv.entity_index, &pp_entity->m_guid); \ + CU_ASSERT_FATAL (pp != NULL); \ + struct dds_security_##name_##_impl *context = (struct dds_security_##name_##_impl *) q_omg_participant_get_##name_ (pp); \ + thread_state_asleep (lookup_thread_state ()); \ + dds_entity_unlock (pp_entity); \ + return context; \ + } + +GET_SECURITY_PLUGIN_CONTEXT(access_control) +GET_SECURITY_PLUGIN_CONTEXT(authentication) +GET_SECURITY_PLUGIN_CONTEXT(cryptography) + +const char * pk_to_str(DDS_Security_ProtectionKind pk) +{ + switch (pk) + { + case DDS_SECURITY_PROTECTION_KIND_NONE: return g_pk_none; + case DDS_SECURITY_PROTECTION_KIND_SIGN: return g_pk_sign; + case DDS_SECURITY_PROTECTION_KIND_ENCRYPT: return g_pk_encrypt; + case DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION: return g_pk_sign_oa; + case DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION: return g_pk_encrypt_oa; + } + assert (false); + return NULL; +} + +const char * bpk_to_str(DDS_Security_BasicProtectionKind bpk) +{ + switch (bpk) + { + case DDS_SECURITY_BASICPROTECTION_KIND_NONE: return g_pk_none; + case DDS_SECURITY_BASICPROTECTION_KIND_SIGN: return g_pk_sign; + case DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT: return g_pk_encrypt; + } + assert (false); + return NULL; +} + +DDS_Security_DatawriterCryptoHandle get_builtin_writer_crypto_handle(dds_entity_t participant, unsigned entityid) +{ + DDS_Security_DatawriterCryptoHandle crypto_handle; + struct dds_entity *pp_entity; + struct participant *pp; + struct writer *wr; + CU_ASSERT_EQUAL_FATAL(dds_entity_pin(participant, &pp_entity), 0); + thread_state_awake(lookup_thread_state(), &pp_entity->m_domain->gv); + pp = entidx_lookup_participant_guid(pp_entity->m_domain->gv.entity_index, &pp_entity->m_guid); + wr = get_builtin_writer(pp, entityid); + CU_ASSERT_FATAL(wr != NULL); + assert(wr != NULL); /* for Clang's static analyzer */ + crypto_handle = wr->sec_attr->crypto_handle; + thread_state_asleep(lookup_thread_state()); + dds_entity_unpin(pp_entity); + return crypto_handle; +} + +DDS_Security_DatawriterCryptoHandle get_writer_crypto_handle(dds_entity_t writer) +{ + DDS_Security_DatawriterCryptoHandle crypto_handle; + struct dds_entity *wr_entity; + struct writer *wr; + CU_ASSERT_EQUAL_FATAL(dds_entity_pin(writer, &wr_entity), 0); + thread_state_awake(lookup_thread_state(), &wr_entity->m_domain->gv); + wr = entidx_lookup_writer_guid(wr_entity->m_domain->gv.entity_index, &wr_entity->m_guid); + CU_ASSERT_FATAL(wr != NULL); + assert(wr != NULL); /* for Clang's static analyzer */ + crypto_handle = wr->sec_attr->crypto_handle; + thread_state_asleep(lookup_thread_state()); + dds_entity_unpin(wr_entity); + return crypto_handle; +} diff --git a/src/security/core/tests/common/test_utils.h b/src/security/core/tests/common/test_utils.h new file mode 100644 index 0000000..b2dfff5 --- /dev/null +++ b/src/security/core/tests/common/test_utils.h @@ -0,0 +1,98 @@ +/* + * Copyright(c) 2006 to 2020 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 SECURITY_CORE_TEST_UTILS_H_ +#define SECURITY_CORE_TEST_UTILS_H_ + +#include "dds/dds.h" +#include "dds/ddsrt/sync.h" + +#include "dds/security/dds_security_api.h" + +#define PK_N DDS_SECURITY_PROTECTION_KIND_NONE +#define PK_S DDS_SECURITY_PROTECTION_KIND_SIGN +#define PK_SOA DDS_SECURITY_PROTECTION_KIND_SIGN_WITH_ORIGIN_AUTHENTICATION +#define PK_E DDS_SECURITY_PROTECTION_KIND_ENCRYPT +#define PK_EOA DDS_SECURITY_PROTECTION_KIND_ENCRYPT_WITH_ORIGIN_AUTHENTICATION +#define BPK_N DDS_SECURITY_BASICPROTECTION_KIND_NONE +#define BPK_S DDS_SECURITY_BASICPROTECTION_KIND_SIGN +#define BPK_E DDS_SECURITY_BASICPROTECTION_KIND_ENCRYPT + +#define PF_F "file:" +#define PF_D "data:," + +#define MAX_LOCAL_IDENTITIES 8 +#define MAX_REMOTE_IDENTITIES 8 +#define MAX_HANDSHAKES 32 + +union guid { + DDS_Security_GUID_t g; + unsigned u[4]; +}; + +enum hs_node_type +{ + HSN_UNDEFINED, + HSN_REQUESTER, + HSN_REPLIER +}; + +struct Identity +{ + DDS_Security_IdentityHandle handle; + union guid guid; +}; + +struct Handshake +{ + DDS_Security_HandshakeHandle handle; + enum hs_node_type node_type; + int lidx; + int ridx; + DDS_Security_ValidationResult_t handshakeResult; + DDS_Security_ValidationResult_t finalResult; + char * err_msg; +}; + +void print_test_msg (const char *msg, ...); +void validate_handshake (dds_domainid_t domain_id, bool exp_localid_fail, const char * exp_localid_msg, struct Handshake *hs_list[], int *nhs, dds_duration_t timeout); +void validate_handshake_nofail (dds_domainid_t domain_id, dds_duration_t timeout); +void validate_handshake_result (struct Handshake *hs, bool exp_fail_hs_req, const char * fail_hs_req_msg, bool exp_fail_hs_reply, const char * fail_hs_reply_msg); +void handshake_list_fini (struct Handshake *hs_list, int nhs); +char *create_topic_name (const char *prefix, uint32_t nr, char *name, size_t size); +void sync_writer_to_readers (dds_entity_t pp_wr, dds_entity_t wr, uint32_t exp_count, dds_duration_t timeout); +void sync_reader_to_writers (dds_entity_t pp_rd, dds_entity_t rd, uint32_t exp_count, dds_duration_t timeout); +bool reader_wait_for_data (dds_entity_t pp, dds_entity_t rd, dds_duration_t dur); +dds_qos_t * get_default_test_qos (void); +void rd_wr_init ( + dds_entity_t pp_wr, dds_entity_t *pub, dds_entity_t *pub_tp, dds_entity_t *wr, + dds_entity_t pp_rd, dds_entity_t *sub, dds_entity_t *sub_tp, dds_entity_t *rd, + const char * topic_name); +void rd_wr_init_fail ( + dds_entity_t pp_wr, dds_entity_t *pub, dds_entity_t *pub_tp, dds_entity_t *wr, + dds_entity_t pp_rd, dds_entity_t *sub, dds_entity_t *sub_tp, dds_entity_t *rd, + const char * topic_name, + bool exp_pubtp_fail, bool exp_wr_fail, + bool exp_subtp_fail, bool exp_rd_fail); +void write_read_for (dds_entity_t wr, dds_entity_t pp_rd, dds_entity_t rd, dds_duration_t dur, bool exp_write_fail, bool exp_read_fail); +const char * pk_to_str (DDS_Security_ProtectionKind pk); +const char * bpk_to_str (DDS_Security_BasicProtectionKind bpk); +DDS_Security_DatawriterCryptoHandle get_builtin_writer_crypto_handle(dds_entity_t participant, unsigned entityid); +DDS_Security_DatawriterCryptoHandle get_writer_crypto_handle(dds_entity_t writer); + +#define GET_SECURITY_PLUGIN_CONTEXT_DECL(name_) \ + struct dds_security_##name_##_impl * get_##name_##_context(dds_entity_t participant); +GET_SECURITY_PLUGIN_CONTEXT_DECL(access_control) +GET_SECURITY_PLUGIN_CONTEXT_DECL(authentication) +GET_SECURITY_PLUGIN_CONTEXT_DECL(cryptography) + + +#endif /* SECURITY_CORE_TEST_UTILS_H_ */ diff --git a/src/security/core/tests/config.c b/src/security/core/tests/config.c new file mode 100644 index 0000000..6cb404d --- /dev/null +++ b/src/security/core/tests/config.c @@ -0,0 +1,672 @@ +/* + * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include + +#include "dds/dds.h" +#include "CUnit/Test.h" +#include "dds/version.h" +#include "dds/ddsrt/cdtors.h" +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsi/q_misc.h" +#include "dds/ddsi/ddsi_xqos.h" +#include "dds/security/dds_security_api_defs.h" +#include "common/config_env.h" +#include "common/test_identity.h" + +#define PROPLIST(init_auth, fin_auth, init_crypto, fin_crypto, init_ac, fin_ac, perm_ca, gov, perm, pre_str, post_str, binprops) \ + "property_list={" pre_str \ + "0:\"dds.sec.auth.library.path\":\""WRAPPERLIB_PATH("dds_security_authentication_wrapper")"\"," \ + "0:\"dds.sec.auth.library.init\":\""init_auth"\"," \ + "0:\"dds.sec.auth.library.finalize\":\""fin_auth"\"," \ + "0:\"dds.sec.crypto.library.path\":\""WRAPPERLIB_PATH("dds_security_cryptography_wrapper")"\"," \ + "0:\"dds.sec.crypto.library.init\":\""init_crypto"\"," \ + "0:\"dds.sec.crypto.library.finalize\":\""fin_crypto"\"," \ + "0:\"dds.sec.access.library.path\":\""WRAPPERLIB_PATH("dds_security_access_control_wrapper")"\"," \ + "0:\"dds.sec.access.library.init\":\""init_ac"\"," \ + "0:\"dds.sec.access.library.finalize\":\""fin_ac"\"," \ + "0:\"dds.sec.auth.identity_ca\":\"" TEST_IDENTITY_CA_CERTIFICATE_DUMMY "\"," \ + "0:\"dds.sec.auth.private_key\":\"" TEST_IDENTITY_PRIVATE_KEY_DUMMY "\"," \ + "0:\"dds.sec.auth.identity_certificate\":\"" TEST_IDENTITY_CERTIFICATE_DUMMY "\"," \ + "0:\"dds.sec.access.permissions_ca\":\""perm_ca"\"," \ + "0:\"dds.sec.access.governance\":\""gov"\"," \ + "0:\"dds.sec.access.permissions\":\""perm"\"" \ + post_str "}:{" binprops "}" +#define PARTICIPANT_QOS(init_auth, fin_auth, init_crypto, fin_crypto, init_ac, fin_ac, perm_ca, gov, perm, pre_str, post_str, binprops) \ + "PARTICIPANT * QOS={*" PROPLIST (init_auth, fin_auth, init_crypto, fin_crypto, init_ac, fin_ac, perm_ca, gov, perm, pre_str, post_str, binprops) "*" +#define PARTICIPANT_QOS_ALL_OK(pre_str, post_str, binprops) \ + PARTICIPANT_QOS ("init_test_authentication_all_ok", "finalize_test_authentication_all_ok", \ + "init_test_cryptography_all_ok", "finalize_test_cryptography_all_ok", \ + "init_test_access_control_all_ok", "finalize_test_access_control_all_ok", \ + "file:Permissions_CA.pem", "file:Governance.p7s", "file:Permissions.p7s", \ + pre_str, post_str, binprops) + +static const char *default_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " finest" + ""; + + +/* + * The 'found' variable will contain flags related to the expected log + * messages that were received. + * Using flags will allow to show that when message isn't received, + * which one it was. + */ +static uint32_t found; + +static void logger(void *ptr, const dds_log_data_t *data) +{ + char **expected = (char**)ptr; + fputs (data->message, stdout); + for (uint32_t i = 0; expected[i] != NULL; i++) { + if (ddsi2_patmatch(expected[i], data->message)) { + found |= (uint32_t)(1 << i); + } + } +} + +static void set_logger_exp(const void * log_expected) +{ + found = 0; + dds_set_log_mask(DDS_LC_FATAL|DDS_LC_ERROR|DDS_LC_WARNING|DDS_LC_CONFIG); + dds_set_log_sink(&logger, (void*)log_expected); + dds_set_trace_sink(&logger, (void*)log_expected); +} + +static void reset_logger() +{ + dds_set_log_sink(NULL, NULL); + dds_set_trace_sink(NULL, NULL); +} + +/* Expected traces when creating domain with an empty security element. We need to + test this one here to be sure that it refuses to start when security is configured + but the implementation doesn't include support for it. */ +CU_Test(ddssec_config, empty, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain; + const char *log_expected[] = { + "config: //CycloneDDS/Domain/DDSSecurity/Authentication/IdentityCertificate/#text: element missing in configuration*", + "config: //CycloneDDS/Domain/DDSSecurity/Authentication/IdentityCA/#text: element missing in configuration*", + "config: //CycloneDDS/Domain/DDSSecurity/Authentication/PrivateKey/#text: element missing in configuration*", + NULL + }; + + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " config" + " " + ""; + + set_logger_exp(log_expected); + domain = dds_create_domain(0, sec_config); + CU_ASSERT_EQUAL_FATAL(domain, DDS_RETCODE_ERROR); + reset_logger(); + + /* All traces should have been provided. */ + CU_ASSERT_FATAL(found == 0x7); +} + +/* Create domain without security element, there shouldn't + be traces that mention security. */ +CU_Test(ddssec_config, non, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain; + const char *log_expected[] = { + "*Security*", + NULL + }; + + set_logger_exp(log_expected); + domain = dds_create_domain(0, default_config); + CU_ASSERT_FATAL(domain > 0); + dds_delete(domain); + reset_logger(); + + /* No security traces should have been provided. */ + CU_ASSERT_FATAL(found == 0x0); +} + +/* Expected traces when creating domain with the security elements. */ +CU_Test(ddssec_config, missing, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain; + const char *log_expected[] = { + "config: //CycloneDDS/Domain/DDSSecurity/Authentication/IdentityCertificate/#text: element missing in configuration*", + "config: //CycloneDDS/Domain/DDSSecurity/Authentication/IdentityCA/#text: element missing in configuration*", + "config: //CycloneDDS/Domain/DDSSecurity/Authentication/PrivateKey/#text: element missing in configuration*", + NULL + }; + + /* IdentityCertificate, IdentityCA and PrivateKey values or elements are missing. */ + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " finest" + " " + " " + " " + " " + " " + " testtext_Password_testtext" + " " + " " + ""; + + set_logger_exp(log_expected); + domain = dds_create_domain(0, sec_config); + CU_ASSERT_EQUAL_FATAL(domain, DDS_RETCODE_ERROR); + reset_logger(); + + /* All traces should have been provided. */ + CU_ASSERT_FATAL(found == 0x7); +} + +/* Expected traces when creating domain with the security elements. */ +CU_Test(ddssec_config, all, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + const char *log_expected[] = { + "config: Domain/DDSSecurity/Authentication/Library/#text: "WRAPPERLIB_PATH("dds_security_authentication_wrapper")"*", + "config: Domain/DDSSecurity/Authentication/Library[@path]: "WRAPPERLIB_PATH("dds_security_authentication_wrapper")"*", + "config: Domain/DDSSecurity/Authentication/Library[@initFunction]: init_test_authentication_all_ok*", + "config: Domain/DDSSecurity/Authentication/Library[@finalizeFunction]: finalize_test_authentication_all_ok*", + "config: Domain/DDSSecurity/Authentication/IdentityCertificate/#text: "TEST_IDENTITY_CERTIFICATE_DUMMY"*", + "config: Domain/DDSSecurity/Authentication/IdentityCA/#text: "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"*", + "config: Domain/DDSSecurity/Authentication/PrivateKey/#text: "TEST_IDENTITY_PRIVATE_KEY_DUMMY"*", + "config: Domain/DDSSecurity/Authentication/Password/#text: testtext_Password_testtext*", + "config: Domain/DDSSecurity/Authentication/TrustedCADirectory/#text: testtext_Dir_testtext*", + "config: Domain/DDSSecurity/AccessControl/Library/#text: "WRAPPERLIB_PATH("dds_security_access_control_wrapper")"*", + "config: Domain/DDSSecurity/AccessControl/Library[@path]: "WRAPPERLIB_PATH("dds_security_access_control_wrapper")"*", + "config: Domain/DDSSecurity/AccessControl/Library[@initFunction]: init_test_access_control_all_ok*", + "config: Domain/DDSSecurity/AccessControl/Library[@finalizeFunction]: finalize_test_access_control_all_ok*", + "config: Domain/DDSSecurity/AccessControl/PermissionsCA/#text: file:Permissions_CA.pem*", + "config: Domain/DDSSecurity/AccessControl/Governance/#text: file:Governance.p7s*", + "config: Domain/DDSSecurity/AccessControl/Permissions/#text: file:Permissions.p7s*", + "config: Domain/DDSSecurity/Cryptographic/Library/#text: "WRAPPERLIB_PATH("dds_security_cryptography_wrapper")"*", + "config: Domain/DDSSecurity/Cryptographic/Library[@path]: "WRAPPERLIB_PATH("dds_security_cryptography_wrapper")"*", + "config: Domain/DDSSecurity/Cryptographic/Library[@initFunction]: init_test_cryptography_all_ok*", + "config: Domain/DDSSecurity/Cryptographic/Library[@finalizeFunction]: finalize_test_cryptography_all_ok*", + /* The config should have been parsed into the participant QoS. */ + PARTICIPANT_QOS_ALL_OK ("", ",0:\"dds.sec.auth.password\":\"testtext_Password_testtext\",0:\"dds.sec.auth.trusted_ca_dir\":\"testtext_Dir_testtext\"", ""), + NULL + }; + + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " finest" + " " + " " + " " + " "TEST_IDENTITY_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_PRIVATE_KEY_DUMMY"" + " testtext_Password_testtext" + " testtext_Dir_testtext" + " " + " " + " " + " " + " " + " " + " file:Governance.p7s" + " file:Permissions_CA.pem" + " file:Permissions.p7s" + " " + " " + ""; + + set_logger_exp(log_expected); + domain = dds_create_domain(0, sec_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, NULL, NULL); + CU_ASSERT_FATAL(participant > 0); + dds_delete(participant); + dds_delete(domain); + reset_logger(); + + /* All traces should have been provided. */ + printf("found: %x\n", found); + CU_ASSERT_FATAL(found == 0x1fffff); +} + +/* Expected traces when creating participant with the security elements. */ +CU_Test(ddssec_config, security, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + const char *log_expected[] = { + "config: Domain/DDSSecurity/Authentication/Library/#text: "WRAPPERLIB_PATH("dds_security_authentication_wrapper")"*", + "config: Domain/DDSSecurity/Authentication/Library[@path]: "WRAPPERLIB_PATH("dds_security_authentication_wrapper")"*", + "config: Domain/DDSSecurity/Authentication/Library[@initFunction]: init_test_authentication_all_ok*", + "config: Domain/DDSSecurity/Authentication/Library[@finalizeFunction]: finalize_test_authentication_all_ok*", + "config: Domain/DDSSecurity/Authentication/IdentityCertificate/#text: "TEST_IDENTITY_CERTIFICATE_DUMMY"*", + "config: Domain/DDSSecurity/Authentication/IdentityCA/#text: "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"*", + "config: Domain/DDSSecurity/Authentication/PrivateKey/#text: "TEST_IDENTITY_PRIVATE_KEY_DUMMY"*", + "config: Domain/DDSSecurity/Authentication/Password/#text: {}*", + "config: Domain/DDSSecurity/Authentication/TrustedCADirectory/#text: {}*", + "config: Domain/DDSSecurity/AccessControl/Library/#text: "WRAPPERLIB_PATH("dds_security_access_control_wrapper")"*", + "config: Domain/DDSSecurity/AccessControl/Library[@path]: "WRAPPERLIB_PATH("dds_security_access_control_wrapper")"*", + "config: Domain/DDSSecurity/AccessControl/Library[@initFunction]: init_test_access_control_all_ok*", + "config: Domain/DDSSecurity/AccessControl/Library[@finalizeFunction]: finalize_test_access_control_all_ok*", + "config: Domain/DDSSecurity/AccessControl/PermissionsCA/#text: file:Permissions_CA.pem*", + "config: Domain/DDSSecurity/AccessControl/Governance/#text: file:Governance.p7s*", + "config: Domain/DDSSecurity/AccessControl/Permissions/#text: file:Permissions.p7s*", + "config: Domain/DDSSecurity/Cryptographic/Library/#text: "WRAPPERLIB_PATH("dds_security_cryptography_wrapper")"*", + "config: Domain/DDSSecurity/Cryptographic/Library[@path]: "WRAPPERLIB_PATH("dds_security_cryptography_wrapper")"*", + "config: Domain/DDSSecurity/Cryptographic/Library[@initFunction]: init_test_cryptography_all_ok*", + "config: Domain/DDSSecurity/Cryptographic/Library[@finalizeFunction]: finalize_test_cryptography_all_ok*", + /* The config should have been parsed into the participant QoS. */ + PARTICIPANT_QOS_ALL_OK ("", ",0:\"dds.sec.auth.password\":\"\",0:\"dds.sec.auth.trusted_ca_dir\":\"\"", ""), + NULL + }; + + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " finest" + " " + " " + " " + " "TEST_IDENTITY_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_PRIVATE_KEY_DUMMY"" + " " + " " + " " + " " + " " + " " + " file:Governance.p7s" + " file:Permissions_CA.pem" + " file:Permissions.p7s" + " " + " " + ""; + + set_logger_exp(log_expected); + domain = dds_create_domain(0, sec_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, NULL, NULL); + CU_ASSERT_FATAL(participant > 0); + dds_delete(participant); + dds_delete(domain); + reset_logger(); + + /* All traces should have been provided. */ + CU_ASSERT_FATAL(found == 0x1fffff); +} + +/* Expected traces when creating domain with the security elements. */ +CU_Test(ddssec_config, deprecated, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + const char *log_expected[] = { + "config: Domain/DDSSecurity/Authentication/Library/#text: "WRAPPERLIB_PATH("dds_security_authentication_wrapper")"*", + "config: Domain/DDSSecurity/Authentication/Library[@path]: "WRAPPERLIB_PATH("dds_security_authentication_wrapper")"*", + "config: Domain/DDSSecurity/Authentication/Library[@initFunction]: init_test_authentication_all_ok*", + "config: Domain/DDSSecurity/Authentication/Library[@finalizeFunction]: finalize_test_authentication_all_ok*", + "config: Domain/DDSSecurity/Authentication/IdentityCertificate/#text: "TEST_IDENTITY_CERTIFICATE_DUMMY"*", + "config: Domain/DDSSecurity/Authentication/IdentityCA/#text: "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"*", + "config: Domain/DDSSecurity/Authentication/PrivateKey/#text: "TEST_IDENTITY_PRIVATE_KEY_DUMMY"*", + "config: Domain/DDSSecurity/Authentication/Password/#text: testtext_Password_testtext*", + "config: Domain/DDSSecurity/Authentication/TrustedCADirectory/#text: testtext_Dir_testtext*", + "config: Domain/DDSSecurity/AccessControl/Library/#text: "WRAPPERLIB_PATH("dds_security_access_control_wrapper")"*", + "config: Domain/DDSSecurity/AccessControl/Library[@path]: "WRAPPERLIB_PATH("dds_security_access_control_wrapper")"*", + "config: Domain/DDSSecurity/AccessControl/Library[@initFunction]: init_test_access_control_all_ok*", + "config: Domain/DDSSecurity/AccessControl/Library[@finalizeFunction]: finalize_test_access_control_all_ok*", + "config: Domain/DDSSecurity/AccessControl/PermissionsCA/#text: file:Permissions_CA.pem*", + "config: Domain/DDSSecurity/AccessControl/Governance/#text: file:Governance.p7s*", + "config: Domain/DDSSecurity/AccessControl/Permissions/#text: file:Permissions.p7s*", + "config: Domain/DDSSecurity/Cryptographic/Library/#text: "WRAPPERLIB_PATH("dds_security_cryptography_wrapper")"*", + "config: Domain/DDSSecurity/Cryptographic/Library[@path]: "WRAPPERLIB_PATH("dds_security_cryptography_wrapper")"*", + "config: Domain/DDSSecurity/Cryptographic/Library[@initFunction]: init_test_cryptography_all_ok*", + "config: Domain/DDSSecurity/Cryptographic/Library[@finalizeFunction]: finalize_test_cryptography_all_ok*", + /* The config should have been parsed into the participant QoS. */ + PARTICIPANT_QOS_ALL_OK ("", ",0:\"dds.sec.auth.password\":\"testtext_Password_testtext\",0:\"dds.sec.auth.trusted_ca_dir\":\"testtext_Dir_testtext\"", ""), + NULL + }; + + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " finest" + " " + " " + " " + " "TEST_IDENTITY_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_PRIVATE_KEY_DUMMY"" + " testtext_Password_testtext" + " testtext_Dir_testtext" + " " + " " + " " + " " + " " + " " + " file:Governance.p7s" + " file:Permissions_CA.pem" + " file:Permissions.p7s" + " " + " " + ""; + + set_logger_exp(log_expected); + domain = dds_create_domain(0, sec_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, NULL, NULL); + CU_ASSERT_FATAL(participant > 0); + dds_delete(participant); + dds_delete(domain); + reset_logger(); + + /* All traces should have been provided. */ + CU_ASSERT_FATAL(found == 0x1fffff); +} + +/* Expected traces when creating participant with the security elements. */ +CU_Test(ddssec_config, qos, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + dds_qos_t * qos; + const char *log_expected[] = { + /* The config should have been parsed into the participant QoS. */ + PARTICIPANT_QOS_ALL_OK ("", ",0:\"dds.sec.auth.password\":\"testtext_Password_testtext\",0:\"dds.sec.auth.trusted_ca_dir\":\"file:/test/dir\"", ""), + NULL + }; + + /* Create the qos */ + CU_ASSERT_FATAL((qos = dds_create_qos()) != NULL); + dds_qset_prop(qos, "dds.sec.auth.library.path", ""WRAPPERLIB_PATH("dds_security_authentication_wrapper")""); + dds_qset_prop(qos, "dds.sec.auth.library.init", "init_test_authentication_all_ok"); + dds_qset_prop(qos, "dds.sec.auth.library.finalize", "finalize_test_authentication_all_ok"); + dds_qset_prop(qos, "dds.sec.crypto.library.path", ""WRAPPERLIB_PATH("dds_security_cryptography_wrapper")""); + dds_qset_prop(qos, "dds.sec.crypto.library.init", "init_test_cryptography_all_ok"); + dds_qset_prop(qos, "dds.sec.crypto.library.finalize", "finalize_test_cryptography_all_ok"); + dds_qset_prop(qos, "dds.sec.access.library.path", ""WRAPPERLIB_PATH("dds_security_access_control_wrapper")""); + dds_qset_prop(qos, "dds.sec.access.library.init", "init_test_access_control_all_ok"); + dds_qset_prop(qos, "dds.sec.access.library.finalize", "finalize_test_access_control_all_ok"); + dds_qset_prop(qos, "dds.sec.auth.identity_ca", ""TEST_IDENTITY_CA_CERTIFICATE_DUMMY""); + dds_qset_prop(qos, "dds.sec.auth.private_key", ""TEST_IDENTITY_PRIVATE_KEY_DUMMY""); + dds_qset_prop(qos, "dds.sec.auth.identity_certificate", ""TEST_IDENTITY_CERTIFICATE_DUMMY""); + 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"); + dds_qset_prop(qos, "dds.sec.auth.password", "testtext_Password_testtext"); + dds_qset_prop(qos, "dds.sec.auth.trusted_ca_dir", "file:/test/dir"); + + set_logger_exp(log_expected); + domain = dds_create_domain(0, default_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, qos, NULL); + CU_ASSERT_FATAL(participant > 0); + dds_delete(participant); + dds_delete_qos(qos); + dds_delete(domain); + reset_logger(); + + /* All traces should have been provided. */ + CU_ASSERT_FATAL(found == 0x1); +} + +/* Expected traces when creating participant with the security elements. */ +CU_Test(ddssec_config, qos_props, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + dds_qos_t * qos; + const char *log_expected[] = { + /* The config should have been parsed into the participant QoS. */ + PARTICIPANT_QOS_ALL_OK ("", ",0:\"dds.sec.auth.password\":\"testtext_Password_testtext\",0:\"dds.sec.auth.trusted_ca_dir\":\"file:/test/dir\",0:\"test.prop1\":\"testtext_value1_testtext\",0:\"test.prop2\":\"testtext_value2_testtext\"", + "0:\"test.bprop1\":3<1,2,3>"), + NULL + }; + + /* Create the qos */ + unsigned char bvalue[3] = { 0x01, 0x02, 0x03 }; + CU_ASSERT_FATAL((qos = dds_create_qos()) != NULL); + dds_qset_prop(qos, "dds.sec.auth.library.path", ""WRAPPERLIB_PATH("dds_security_authentication_wrapper")""); + dds_qset_prop(qos, "dds.sec.auth.library.init", "init_test_authentication_all_ok"); + dds_qset_prop(qos, "dds.sec.auth.library.finalize", "finalize_test_authentication_all_ok"); + dds_qset_prop(qos, "dds.sec.crypto.library.path", ""WRAPPERLIB_PATH("dds_security_cryptography_wrapper")""); + dds_qset_prop(qos, "dds.sec.crypto.library.init", "init_test_cryptography_all_ok"); + dds_qset_prop(qos, "dds.sec.crypto.library.finalize", "finalize_test_cryptography_all_ok"); + dds_qset_prop(qos, "dds.sec.access.library.path", ""WRAPPERLIB_PATH("dds_security_access_control_wrapper")""); + dds_qset_prop(qos, "dds.sec.access.library.init", "init_test_access_control_all_ok"); + dds_qset_prop(qos, "dds.sec.access.library.finalize", "finalize_test_access_control_all_ok"); + dds_qset_prop(qos, "dds.sec.auth.identity_ca", TEST_IDENTITY_CA_CERTIFICATE_DUMMY); + dds_qset_prop(qos, "dds.sec.auth.private_key", TEST_IDENTITY_PRIVATE_KEY_DUMMY); + dds_qset_prop(qos, "dds.sec.auth.identity_certificate", TEST_IDENTITY_CERTIFICATE_DUMMY); + 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"); + dds_qset_prop(qos, "dds.sec.auth.password", "testtext_Password_testtext"); + dds_qset_prop(qos, "dds.sec.auth.trusted_ca_dir", "file:/test/dir"); + 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); + + set_logger_exp(log_expected); + domain = dds_create_domain(0, default_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, qos, NULL); + CU_ASSERT_FATAL(participant > 0); + dds_delete(participant); + dds_delete_qos(qos); + dds_delete(domain); + reset_logger(); + + /* All traces should have been provided. */ + CU_ASSERT_FATAL(found == 0x1); +} + +/* Expect qos settings used when creating participant with config security elements and qos. */ +CU_Test(ddssec_config, config_qos, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + dds_qos_t * qos; + const char *log_expected[] = { + /* The security settings from qos properties should have been parsed into the participant QoS. */ + "new_participant(*): using security settings from QoS*", + PARTICIPANT_QOS ("init_test_authentication_all_ok", "finalize_test_authentication_all_ok", \ + "init_test_cryptography_all_ok", "finalize_test_cryptography_all_ok", \ + "init_test_access_control_all_ok", "finalize_test_access_control_all_ok", \ + "file:QOS_Permissions_CA.pem", "file:QOS_Governance.p7s", "file:QOS_Permissions.p7s", \ + "", "", ""), + NULL + }; + + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " finest" + " " + " " + " "TEST_IDENTITY_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_PRIVATE_KEY_DUMMY"" + " " + " " + " file:Governance.p7s" + " file:Permissions_CA.pem" + " file:Permissions.p7s" + " " + " " + ""; + + CU_ASSERT_FATAL((qos = dds_create_qos()) != NULL); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_PATH, WRAPPERLIB_PATH("dds_security_authentication_wrapper")); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_INIT, "init_test_authentication_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_FINALIZE, "finalize_test_authentication_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_PATH, WRAPPERLIB_PATH("dds_security_cryptography_wrapper")); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_INIT, "init_test_cryptography_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_FINALIZE, "finalize_test_cryptography_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_PATH, WRAPPERLIB_PATH("dds_security_access_control_wrapper")); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_INIT, "init_test_access_control_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_FINALIZE, "finalize_test_access_control_all_ok"); + dds_qset_prop(qos, "dds.sec.auth.identity_ca", TEST_IDENTITY_CA_CERTIFICATE_DUMMY); + dds_qset_prop(qos, "dds.sec.auth.private_key", TEST_IDENTITY_PRIVATE_KEY_DUMMY); + dds_qset_prop(qos, "dds.sec.auth.identity_certificate", TEST_IDENTITY_CERTIFICATE_DUMMY); + dds_qset_prop(qos, "dds.sec.access.permissions_ca", "file:QOS_Permissions_CA.pem"); + dds_qset_prop(qos, "dds.sec.access.governance", "file:QOS_Governance.p7s"); + dds_qset_prop(qos, "dds.sec.access.permissions", "file:QOS_Permissions.p7s"); + + set_logger_exp(log_expected); + domain = dds_create_domain(0, sec_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, qos, NULL); + CU_ASSERT_FATAL (participant > 0); + dds_delete(participant); + dds_delete_qos(qos); + dds_delete(domain); + reset_logger(); + + /* All traces should have been provided. */ + CU_ASSERT_FATAL(found == 0x3); +} + +/* Expect config used when creating participant with config security elements and + qos containing only non-security properties. */ +CU_Test(ddssec_config, other_prop, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + dds_qos_t * qos; + const char *log_expected[] = { + /* The security settings from config should have been parsed into the participant QoS. */ + PARTICIPANT_QOS_ALL_OK ("0:\"test.dds.sec.prop1\":\"testtext_value1_testtext\",", ",0:\"dds.sec.auth.password\":\"testtext_Password_testtext\",0:\"dds.sec.auth.trusted_ca_dir\":\"testtext_Dir_testtext\"", ""), + NULL + }; + + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " finest" + " " + " " + " " + " "TEST_IDENTITY_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_PRIVATE_KEY_DUMMY"" + " testtext_Password_testtext" + " testtext_Dir_testtext" + " " + " " + " " + " " + " " + " " + " file:Governance.p7s" + " file:Permissions_CA.pem" + " file:Permissions.p7s" + " " + " " + ""; + + CU_ASSERT_FATAL((qos = dds_create_qos()) != NULL); + dds_qset_prop(qos, "test.dds.sec.prop1", "testtext_value1_testtext"); + + set_logger_exp(log_expected); + domain = dds_create_domain(0, sec_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, qos, NULL); + CU_ASSERT_FATAL (participant > 0); + dds_delete(participant); + dds_delete_qos(qos); + dds_delete(domain); + reset_logger(); + + /* All traces should have been provided. */ + CU_ASSERT_FATAL(found == 0x1); +} + +/* Expected traces when creating participant with the security elements. */ +CU_Test(ddssec_config, qos_invalid, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + dds_qos_t * qos; + const char *log_expected[] = { + /* The config should have been parsed into the participant QoS. */ + "new_participant(*): using security settings from QoS*", + "new_participant(*): required security property dds.sec.auth.identity_ca missing in Property QoS*", + "new_participant(*): required security property dds.sec.auth.private_key missing in Property QoS*", + "new_participant(*): required security property dds.sec.auth.identity_certificate missing in Property QoS*", + "new_participant(*): required security property dds.sec.access.permissions_ca missing in Property QoS*", + "new_participant(*): required security property dds.sec.access.governance missing in Property QoS*", + "new_participant(*): required security property dds.sec.access.permissions missing in Property QoS*", + "new_participant(*): required security property dds.sec.auth.library.path missing in Property QoS*", + "new_participant(*): required security property dds.sec.auth.library.init missing in Property QoS*", + "new_participant(*): required security property dds.sec.auth.library.finalize missing in Property QoS*", + "new_participant(*): required security property dds.sec.crypto.library.path missing in Property QoS*", + "new_participant(*): required security property dds.sec.crypto.library.init missing in Property QoS*", + "new_participant(*): required security property dds.sec.crypto.library.finalize missing in Property QoS*", + "new_participant(*): required security property dds.sec.access.library.path missing in Property QoS*", + "new_participant(*): required security property dds.sec.access.library.init missing in Property QoS*", + "new_participant(*): required security property dds.sec.access.library.finalize missing in Property QoS*", + NULL + }; + + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " finest" + " " + " " + " "TEST_IDENTITY_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_PRIVATE_KEY_DUMMY"" + " " + " " + " file:Governance.p7s" + " file:Permissions_CA.pem" + " file:Permissions.p7s" + " " + " " + ""; + + set_logger_exp(log_expected); + + CU_ASSERT_FATAL((qos = dds_create_qos()) != NULL); + dds_qset_prop(qos, "dds.sec.dummy", "testtext_dummy_testtext"); + + /* Create participant with security config in qos. */ + domain = dds_create_domain(0, sec_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, qos, NULL); + CU_ASSERT_EQUAL_FATAL(participant, DDS_RETCODE_ERROR); + dds_delete_qos(qos); + dds_delete(domain); + reset_logger(); + + /* All traces should have been provided. */ + CU_ASSERT_FATAL(found == 0xffff); +} diff --git a/src/security/core/tests/crypto.c b/src/security/core/tests/crypto.c new file mode 100644 index 0000000..68ae5fd --- /dev/null +++ b/src/security/core/tests/crypto.c @@ -0,0 +1,174 @@ +/* + * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include + +#include "dds/dds.h" +#include "CUnit/Test.h" +#include "CUnit/Theory.h" + +#include "dds/version.h" +#include "dds/ddsrt/cdtors.h" +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsi/q_config.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/ddsi/q_misc.h" +#include "dds/ddsi/ddsi_xqos.h" + +#include "dds/security/dds_security_api.h" + +#include "common/config_env.h" +#include "common/cryptography_wrapper.h" +#include "common/test_utils.h" +#include "common/security_config_test_utils.h" +#include "common/test_identity.h" +#include "common/cert_utils.h" + +static const char *config = + "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}" + "" + " " + " 0" + " \\${CYCLONEDDS_PID}" + " " + " " + " " + " " + " data:,${TEST_IDENTITY_CERTIFICATE}" + " data:,${TEST_IDENTITY_PRIVATE_KEY}" + " data:,${TEST_IDENTITY_CA_CERTIFICATE}" + " " + " " + " " + " " + " file:" COMMON_ETC_PATH("default_permissions_ca.pem") "" + " " + " " + " " + " " + " " + " " + ""; + +#define DDS_DOMAINID1 0 +#define DDS_DOMAINID2 1 + +static dds_entity_t g_domain1; +static dds_entity_t g_participant1; +static dds_entity_t g_domain2; +static dds_entity_t g_participant2; + +static uint32_t g_topic_nr = 0; + +static void init_domain_pp (dds_domainid_t domain_id, const char *id_cert, const char * id_key, const char * id_ca, + const char * gov_config, const char * perm_config, const char * crypto_init, const char * crypto_fini, dds_entity_t *domain, dds_entity_t *pp) +{ + struct kvp config_vars[] = + { + { "TEST_IDENTITY_CERTIFICATE", id_cert, 1 }, + { "TEST_IDENTITY_PRIVATE_KEY", id_key, 1 }, + { "TEST_IDENTITY_CA_CERTIFICATE", id_ca, 1 }, + { "PERMISSIONS_CONFIG", perm_config, 1 }, + { "GOVERNANCE_CONFIG", gov_config, 1 }, + { "CRYPTO_INIT", crypto_init, 1 }, + { "CRYPTO_FINI", crypto_fini, 1 }, + { NULL, NULL, 0 } + }; + char *conf = ddsrt_expand_vars_sh (config, &expand_lookup_vars_env, config_vars); + CU_ASSERT_EQUAL_FATAL (expand_lookup_unmatched (config_vars), 0); + *domain = dds_create_domain (domain_id, conf); + *pp = dds_create_participant (domain_id, NULL, NULL); + CU_ASSERT_FATAL (*pp > 0); + ddsrt_free (conf); +} + +static void crypto_init ( + const char * gov_config1, const char * perm_config1, const char * id_cert1, const char * id_key1, const char * crypto_init1, const char * crypto_fini1, + const char * gov_config2, const char * perm_config2, const char * id_cert2, const char * id_key2, const char * crypto_init2, const char * crypto_fini2, + const char * id_ca) +{ + init_domain_pp (DDS_DOMAINID1, id_cert1, id_key1, id_ca, gov_config1, perm_config1, crypto_init1, crypto_fini1, &g_domain1, &g_participant1); + init_domain_pp (DDS_DOMAINID2, id_cert2, id_key2, id_ca, gov_config2, perm_config2, crypto_init2, crypto_fini2, &g_domain2, &g_participant2); +} + +static void crypto_fini (void * res[], size_t nres) +{ + CU_ASSERT_EQUAL_FATAL (dds_delete (g_domain1), DDS_RETCODE_OK); + CU_ASSERT_EQUAL_FATAL (dds_delete (g_domain2), DDS_RETCODE_OK); + if (res != NULL) + { + for (size_t i = 0; i < nres; i++) + ddsrt_free (res[i]); + } +} + +CU_TheoryDataPoints(ddssec_crypto, inject_plain_data) = { + CU_DataPoints(const char *, + /* */"payload encrypt", + /* | */"payload sign", + /* | | */"submessage encrypt", + /* | | | */"submessage sign", + /* | | | | */"rtps encrypt", + /* | | | | | */"rtps sign"), + CU_DataPoints(DDS_Security_BasicProtectionKind, BPK_E, BPK_S, BPK_N, BPK_N, BPK_N, BPK_N), /* payload protection */ + CU_DataPoints(DDS_Security_ProtectionKind, PK_N, PK_N, PK_E, PK_S, PK_N, PK_N), /* submessage protection */ + CU_DataPoints(DDS_Security_ProtectionKind, PK_N, PK_N, PK_N, PK_N, PK_E, PK_S), /* rtps protection */ +}; +/* This test validates that non-encrypted data will not be received by a reader that has protection + enabled for rtps/submsg/payload. The test uses a crypto plugin wrapper mode that force the plugin + to write plain data in the encoded output buffer to DDSI, ignoring the security attributes for the + reader and writer. */ +CU_Theory((const char * test_descr, DDS_Security_BasicProtectionKind payload_pk, DDS_Security_ProtectionKind submsg_pk, DDS_Security_ProtectionKind rtps_pk), + ddssec_crypto, inject_plain_data, .timeout=30) +{ + print_test_msg ("running test inject_plain_data: %s\n", test_descr); + + char topic_name[100]; + create_topic_name ("ddssec_crypto_", g_topic_nr++, topic_name, sizeof (topic_name)); + + char *ca, *id1, *id1_subj, *id2, *id2_subj; + ca = generate_ca ("ca1", TEST_IDENTITY_CA1_PRIVATE_KEY, 0, 3600); + id1 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id1", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id1_subj); + id2 = generate_identity (ca, TEST_IDENTITY_CA1_PRIVATE_KEY, "id2", TEST_IDENTITY1_PRIVATE_KEY, 0, 3600, &id2_subj); + + char * grants[] = { + get_permissions_default_grant ("id1", id1_subj, topic_name), + get_permissions_default_grant ("id2", id2_subj, topic_name) }; + char * perm_config = get_permissions_config (grants, 2, true); + + char * gov_topic_rule = get_governance_topic_rule (topic_name, false, false, false, false, submsg_pk, payload_pk); + char * gov_config = get_governance_config (false, true, PK_N, PK_N, rtps_pk, gov_topic_rule, true); + + crypto_init ( + gov_config, perm_config, id1, TEST_IDENTITY1_PRIVATE_KEY, "init_test_cryptography_plain_data", "finalize_test_cryptography_plain_data", + gov_config, perm_config, id2, TEST_IDENTITY1_PRIVATE_KEY, "init_test_cryptography_wrapped", "finalize_test_cryptography_wrapped", + ca); + + dds_entity_t pub, sub, pub_tp, sub_tp, wr, rd; + rd_wr_init (g_participant1, &pub, &pub_tp, &wr, g_participant2, &sub, &sub_tp, &rd, topic_name); + + /* set forced plain data for payload/submsg/rtps */ + DDS_Security_DatawriterCryptoHandle wr_handle = get_writer_crypto_handle (wr); + struct dds_security_cryptography_impl * crypto_impl = get_cryptography_context (g_participant1); + set_force_plain_data (crypto_impl, wr_handle, rtps_pk != PK_N, submsg_pk != PK_N, payload_pk != BPK_N); + + /* sync and write/take sample */ + sync_writer_to_readers (g_participant1, wr, 1, DDS_SECS (2)); + write_read_for (wr, g_participant2, rd, DDS_MSECS (10), false, true); + + /* reset forced plain data */ + set_force_plain_data (crypto_impl, wr_handle, false, false, false); + + crypto_fini ((void * []) { gov_config, gov_topic_rule, grants[0], grants[1], perm_config, ca, id1_subj, id1, id2_subj, id2 }, 10); +} diff --git a/src/security/core/tests/fsm.c b/src/security/core/tests/fsm.c new file mode 100644 index 0000000..e947dfe --- /dev/null +++ b/src/security/core/tests/fsm.c @@ -0,0 +1,581 @@ +/* + * 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 + */ +#include +#include +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" + +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/misc.h" +#include "dds/dds.h" +#include "dds__types.h" +#include "dds__entity.h" +#include "dds/security/core/dds_security_fsm.h" + +#define CHECK_BIT(var, pos) ((var) & (1<<(pos))) +#define FSM_AUTH_ARG 10 + +static dds_entity_t g_participant = 0; +static ddsrt_mutex_t g_lock; +static struct dds_security_fsm_control *g_fsm_control = NULL; + +#define DO_SIMPLE(name, var, bit) static void name(struct dds_security_fsm *fsm, void *arg) { \ + DDSRT_UNUSED_ARG(fsm); \ + DDSRT_UNUSED_ARG(arg); \ + printf("Transition %s\n", __FUNCTION__); \ + ddsrt_mutex_lock(&g_lock); \ + visited_##var |= 1u << (bit); \ + ddsrt_mutex_unlock(&g_lock); \ +} + +typedef enum { + VALIDATION_PENDING_RETRY, + VALIDATION_FAILED, + VALIDATION_OK, + VALIDATION_OK_FINAL_MESSAGE, + VALIDATION_PENDING_HANDSHAKE_MESSAGE, + VALIDATION_PENDING_HANDSHAKE_REQUEST, + plugin_ret_MAX +} plugin_ret; + +static struct dds_security_fsm *fsm_auth; +static uint32_t visited_auth = 0; +static uint32_t correct_fsm = 0; +static uint32_t correct_arg = 0; +static int validate_remote_identity_first = 1; +static int begin_handshake_reply_first = 1; + + +static plugin_ret validate_remote_identity(void) +{ + printf("validate_remote_identity - %d\n", validate_remote_identity_first); + if (validate_remote_identity_first) + { + validate_remote_identity_first = 0; + return VALIDATION_PENDING_RETRY; + } + return VALIDATION_PENDING_HANDSHAKE_MESSAGE; +} + +static plugin_ret begin_handshake_reply(void) +{ + printf("begin_handshake_reply - %d\n", begin_handshake_reply_first); + if (begin_handshake_reply_first) + { + begin_handshake_reply_first = 0; + return VALIDATION_PENDING_RETRY; + } + return VALIDATION_OK_FINAL_MESSAGE; +} + +static plugin_ret get_shared_secret(void) +{ + return VALIDATION_OK; +} + +/* State actions */ +static void fsm_validate_remote_identity(struct dds_security_fsm *fsm, void *arg) +{ + DDSRT_UNUSED_ARG(arg); + plugin_ret ret = validate_remote_identity(); + printf("[%p] State %s (ret %d)\n", fsm, __FUNCTION__, (int) ret); + dds_security_fsm_dispatch(fsm, (int32_t) ret, false); +} + +static void fsm_begin_handshake_reply(struct dds_security_fsm *fsm, void *arg) +{ + DDSRT_UNUSED_ARG(arg); + plugin_ret ret = begin_handshake_reply(); + if (ret == VALIDATION_OK_FINAL_MESSAGE) + ret = get_shared_secret(); + printf("[%p] State %s (ret %d)\n", fsm, __FUNCTION__, (int) ret); + dds_security_fsm_dispatch(fsm, (int32_t) ret, false); +} + +/* A few states from the handshake state-machine. */ +static dds_security_fsm_state StateValidateRemoteIdentity = {fsm_validate_remote_identity, 0}; +static dds_security_fsm_state StateValRemIdentityRetryWait = {NULL, 100000000}; +static dds_security_fsm_state StateHandshakeInitMessageWait = {NULL, 0}; +static dds_security_fsm_state state_beginHandshakeReply = {fsm_begin_handshake_reply, 0}; +static dds_security_fsm_state state_beginHsReplyWait = {NULL, 100000000}; + +static void a(struct dds_security_fsm *fsm, void *arg) +{ + printf("[%p] Transition %s\n", fsm, __FUNCTION__); + ddsrt_mutex_lock (&g_lock); + if (arg != NULL) + correct_arg = *((int *)arg) == FSM_AUTH_ARG ? 1 : 0; + correct_fsm = (fsm == fsm_auth) ? 1 : 0; + visited_auth |= 1u << 0; + ddsrt_mutex_unlock (&g_lock); +} + +DO_SIMPLE(b, auth, 1) +DO_SIMPLE(c, auth, 2) +DO_SIMPLE(d, auth, 3) +DO_SIMPLE(e, auth, 4) +DO_SIMPLE(f, auth, 5) +DO_SIMPLE(g, auth, 6) +DO_SIMPLE(h, auth, 7) + +#define SHM_MSG_RECEIVED (plugin_ret_MAX + 1) + +/* + * .--. + * |##|--------------------------------------. + * '--' a() v + * .----------------------------------------------------. + * | StateValidateRemoteIdentity | + * |----------------------------------------------------| + * .------>| fsm_validate_remote_identity() | + * | | - dispatch VALIDATION_PENDING_RETRY | + * 100ms| | - dispatch VALIDATION_PENDING_HANDSHAKE_MESSAGE | + * d() | '----------------------------------------------------' + * | VALIDATION_PENDING_RETRY| | VALIDATION_PENDING_HANDSHAKE_MESSAGE + * | b() | | c() + * | | | + * .------------------------------. | | .-------------------------------. + * | StateValRemIdentityRetryWait | | | | StateHandshakeInitMessageWait | + * |------------------------------|<----------' '------>|-------------------------------| + * '------------------------------' '-------------------------------' + * SHM_MSG_RECEIVED | + * e() | + * v + * .----------------------------------------. + * VALIDATION_PENDING_RETRY | state_beginHandshakeReply | + * f() |----------------------------------------| + * .-------------------------| fsm_begin_handshake_reply() | + * | | - dispatch VALIDATION_PENDING_RETRY | + * v | - dispatch VALIDATION_OK | + * .-----------------------. 100ms '----------------------------------------' + * | state_beginHsReplyWait | h() ^ VALIDATION_OK | + * |-----------------------|-----------------------' g() | + * '-----------------------' v + * .-. + * '-' + */ +static dds_security_fsm_transition HandshakeTransistions[] = { + {NULL, DDS_SECURITY_FSM_EVENT_AUTO, a, &StateValidateRemoteIdentity}, // NULL state is the start state + {&StateValidateRemoteIdentity, VALIDATION_PENDING_RETRY, b, &StateValRemIdentityRetryWait}, + {&StateValidateRemoteIdentity, VALIDATION_PENDING_HANDSHAKE_MESSAGE, c, &StateHandshakeInitMessageWait}, + {&StateValRemIdentityRetryWait, DDS_SECURITY_FSM_EVENT_TIMEOUT, d, &StateValidateRemoteIdentity}, + {&StateHandshakeInitMessageWait, SHM_MSG_RECEIVED, e, &state_beginHandshakeReply}, + {&state_beginHandshakeReply, VALIDATION_PENDING_RETRY, f, &state_beginHsReplyWait}, + {&state_beginHandshakeReply, VALIDATION_OK, g, NULL}, // Reaching NULL means end of state-diagram + {&state_beginHsReplyWait, DDS_SECURITY_FSM_EVENT_TIMEOUT, h, &state_beginHandshakeReply} +}; +static const uint32_t HandshakeTransistionsSize = sizeof(HandshakeTransistions)/sizeof(HandshakeTransistions[0]); + + +/* Example State Machine properties and methods */ +typedef enum { + eventX, eventY, eventZ, +} test_events; + +static struct dds_security_fsm *fsm_test; +static uint32_t visited_test = 0; +static int do_stuff_counter = 0; +static int do_other_stuff_counter = 0; + +DO_SIMPLE(do_start, test, 0) +DO_SIMPLE(do_restart, test, 1) +DO_SIMPLE(do_event_stuff, test, 4) + +static void do_stuff(struct dds_security_fsm *fsm, void *arg) +{ + DDSRT_UNUSED_ARG(fsm); + DDSRT_UNUSED_ARG(arg); + printf("Transition %s - %d\n", __FUNCTION__, do_stuff_counter); + ddsrt_mutex_lock (&g_lock); + visited_test |= 1u << 2; + ddsrt_mutex_unlock (&g_lock); + if (do_stuff_counter < 2) + dds_security_fsm_dispatch(fsm, eventZ, false); + else if (do_stuff_counter == 2) + dds_security_fsm_dispatch(fsm, eventY, false); + ++do_stuff_counter; +} + +static void do_other_stuff(struct dds_security_fsm *fsm, void *arg) +{ + DDSRT_UNUSED_ARG(fsm); + DDSRT_UNUSED_ARG(arg); + printf("Transition %s - %d\n", __FUNCTION__, do_other_stuff_counter); + ddsrt_mutex_lock (&g_lock); + visited_test |= 1u << 3; + ddsrt_mutex_unlock (&g_lock); + if (do_other_stuff_counter == 0) + dds_security_fsm_dispatch(fsm, DDS_SECURITY_FSM_EVENT_AUTO, false); + else if (do_other_stuff_counter == 1) + dds_security_fsm_dispatch(fsm, eventY, false); + else if (do_other_stuff_counter == 2) + dds_security_fsm_dispatch(fsm, eventX, false); + ++do_other_stuff_counter; +} + +static dds_security_fsm_state state_a = {do_stuff, 0}; +static dds_security_fsm_state state_b = {do_stuff, 100000000}; +static dds_security_fsm_state state_c = {NULL, 0}; +static dds_security_fsm_state state_d = {do_other_stuff, 0}; + +static dds_security_fsm_transition Transitions[] = { + {NULL, DDS_SECURITY_FSM_EVENT_AUTO, do_start, &state_a}, // NULL state is the start state + {&state_a, eventZ, NULL, &state_b}, + {&state_a, eventY, do_other_stuff, &state_c}, + {&state_b, eventX, NULL, NULL}, // Reaching NULL means end of state-diagram + {&state_b, eventZ, do_restart, &state_a}, + {&state_c, DDS_SECURITY_FSM_EVENT_AUTO, do_event_stuff, &state_d}, + {&state_d, eventY, do_event_stuff, &state_d}, + {&state_d, eventX, do_stuff, NULL}, // Reaching NULL means end of sttimeoutate-diagram +}; +static const uint32_t TransitionsSize = sizeof(Transitions)/sizeof(Transitions[0]); + + +/* Timeout State Machine properties and methods */ +typedef enum { + event_to_timeout, event_to_interrupt, event_to_end, +} 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 struct fsm_timeout_arg fsm_arg = { .id = FSM_AUTH_ARG }; + +DO_SIMPLE(do_interrupt, timeout, 0) +DO_SIMPLE(timeout_cb2, timeout, 3) + +static void do_timeout(struct dds_security_fsm *fsm, void *arg) +{ + DDSRT_UNUSED_ARG(arg); + printf("Transition >>>> %s\n", __FUNCTION__); + ddsrt_mutex_lock (&g_lock); + visited_timeout |= 1u << 1; + ddsrt_mutex_unlock (&g_lock); + printf("Transition <<<< %s\n", __FUNCTION__); + dds_security_fsm_dispatch(fsm, event_to_timeout, false); +} + +static void timeout_cb(struct dds_security_fsm *fsm, void *arg) +{ + struct fsm_timeout_arg *farg = arg; + printf("timeout_cb\n"); + ddsrt_mutex_lock (&g_lock); + visited_timeout |= 1u << 2; + if (farg != NULL) + correct_arg_timeout = farg->id == FSM_AUTH_ARG ? 1 : 0; + correct_fsm_timeout = fsm == fsm_timeout ? 1 : 0; + ddsrt_mutex_unlock (&g_lock); +} + +static dds_security_fsm_state state_initial = {do_timeout, 0}; +static dds_security_fsm_state state_wait_timeout = {NULL, DDS_SECS(4)}; +static dds_security_fsm_state state_interrupt = {do_interrupt, 0}; + +static const dds_security_fsm_transition timeout_transitions[] = { + {NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &state_initial}, // NULL state is the start state + {&state_initial, event_to_timeout, NULL, &state_wait_timeout}, + {&state_wait_timeout, DDS_SECURITY_FSM_EVENT_TIMEOUT, NULL, &state_interrupt}, + {&state_wait_timeout, event_to_interrupt, NULL, &state_interrupt}, + {&state_interrupt, event_to_end, NULL, NULL}, // Reaching NULL means end of state-diagram +}; +static const uint32_t timeout_transitionsSize = sizeof(timeout_transitions)/sizeof(timeout_transitions[0]); + +/* Parallel Timeout State Machines properties and methods */ +static struct dds_security_fsm *fsm_timeout1; +static struct dds_security_fsm *fsm_timeout2; +static struct dds_security_fsm *fsm_timeout3; + +static dds_time_t time0 = 0; +static dds_time_t time1 = 0; +static dds_time_t time2 = 0; +static dds_time_t time3 = 0; + +static void state_par_time1(struct dds_security_fsm *fsm, void *arg) +{ + DDSRT_UNUSED_ARG(fsm); + DDSRT_UNUSED_ARG(arg); + time1 = dds_time(); +} + +static void state_par_time2(struct dds_security_fsm *fsm, void *arg) +{ + DDSRT_UNUSED_ARG(fsm); + DDSRT_UNUSED_ARG(arg); + time2 = dds_time(); +} + +static void state_par_time3(struct dds_security_fsm *fsm, void *arg) +{ + DDSRT_UNUSED_ARG(fsm); + DDSRT_UNUSED_ARG(arg); + time3 = dds_time(); +} + +static dds_security_fsm_state state_par_timeout1 = {NULL, DDS_SECS(1)}; +static dds_security_fsm_state state_par_timeout2 = {NULL, DDS_SECS(2)}; +static dds_security_fsm_state state_par_timeout3 = {NULL, DDS_SECS(1)}; + +static dds_security_fsm_transition parallel_timeout_transitions_1[] = { + {NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &state_par_timeout1}, // NULL state is the startfsm_control_thread state + {&state_par_timeout1, DDS_SECURITY_FSM_EVENT_TIMEOUT, &state_par_time1, NULL}, // Reaching NULL means end of state-diagram +}; +static const uint32_t parallel_timeout_transitionsSize_1 = sizeof(parallel_timeout_transitions_1) / sizeof(parallel_timeout_transitions_1[0]); + +static dds_security_fsm_transition parallel_timeout_transitions_2[] = { + {NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &state_par_timeout2}, // NULL state is the start state + {&state_par_timeout2, DDS_SECURITY_FSM_EVENT_TIMEOUT, &state_par_time2, NULL}, // Reaching NULL means end of state-diagram +}; +static const uint32_t parallel_timeout_transitionsSize_2 = sizeof(parallel_timeout_transitions_2) / sizeof(parallel_timeout_transitions_2[0]); + +static dds_security_fsm_transition parallel_timeout_transitions_3[] = { + {NULL, DDS_SECURITY_FSM_EVENT_AUTO, NULL, &state_par_timeout3}, // NULL state is the start state + {&state_par_timeout3, DDS_SECURITY_FSM_EVENT_TIMEOUT, &state_par_time3, NULL}, // Reaching NULL means end of state-diagram +}; +static const uint32_t parallel_timeout_transitionsSize_3 = sizeof(parallel_timeout_transitions_3) / sizeof(parallel_timeout_transitions_3[0]); + +static void fsm_control_init(void) +{ + struct dds_entity *e; + g_participant = dds_create_participant(DDS_DOMAIN_DEFAULT, NULL, NULL); + CU_ASSERT_FATAL(g_participant > 0); + ddsrt_mutex_init(&g_lock); + dds_return_t rc = dds_entity_pin(g_participant, &e); + CU_ASSERT_FATAL(rc == 0); + g_fsm_control = dds_security_fsm_control_create(&e->m_domain->gv); + CU_ASSERT_FATAL(g_fsm_control != NULL); + dds_entity_unpin(e); + rc = dds_security_fsm_control_start(g_fsm_control, NULL); + CU_ASSERT_EQUAL_FATAL(rc, 0); +} + +static void fsm_control_fini(void) +{ + dds_security_fsm_control_stop(g_fsm_control); + dds_security_fsm_control_free(g_fsm_control); + ddsrt_mutex_destroy (&g_lock); + dds_delete(g_participant); +} + +CU_Test(ddssec_fsm, create, .init = fsm_control_init, .fini = fsm_control_fini) +{ + /* Test single running state machine. Check creation of a single State Machine */ + fsm_auth = dds_security_fsm_create(g_fsm_control, HandshakeTransistions, HandshakeTransistionsSize, &fsm_arg); + CU_ASSERT_FATAL(fsm_auth != NULL) + + /* set a delay that doesn't expire. Should be terminate when fsm is freed. */ + dds_security_fsm_set_timeout(fsm_auth, timeout_cb, DDS_SECS(30)); + dds_security_fsm_start(fsm_auth); + + int n = 100; + while (dds_security_fsm_current_state(fsm_auth) != &StateHandshakeInitMessageWait && n-- > 0) + dds_sleepfor(DDS_MSECS(100)); + CU_ASSERT(n > 0); + dds_security_fsm_dispatch(fsm_auth, SHM_MSG_RECEIVED, false); + + n = 100; + while (dds_security_fsm_current_state(fsm_auth) != NULL && n-- > 0) + dds_sleepfor(DDS_MSECS(100)); + CU_ASSERT(n > 0); + + ddsrt_mutex_lock (&g_lock); + CU_ASSERT(visited_auth == 0xff); + ddsrt_mutex_unlock (&g_lock); + + /* Check correct callback parameter passing (from fsm to user defined methods) */ + CU_ASSERT(correct_arg && correct_fsm); + dds_security_fsm_free(fsm_auth); + + /* Check whether timeout callback has NOT been invoked */ + ddsrt_mutex_lock (&g_lock); + CU_ASSERT(visited_timeout == 0); + ddsrt_mutex_unlock (&g_lock); +} + +/* Test multiple (2) running state machines */ +CU_Test(ddssec_fsm, multiple, .init = fsm_control_init, .fini = fsm_control_fini) +{ + validate_remote_identity_first = 0; + begin_handshake_reply_first = 0; + visited_auth = 0; + visited_test = 0; + + fsm_auth = dds_security_fsm_create(g_fsm_control, HandshakeTransistions, HandshakeTransistionsSize, NULL); + CU_ASSERT_FATAL(fsm_auth != NULL); + + fsm_test = dds_security_fsm_create(g_fsm_control, Transitions, TransitionsSize, NULL); + CU_ASSERT_FATAL(fsm_test != NULL); + + dds_security_fsm_start(fsm_auth); + dds_security_fsm_start(fsm_test); + + /* Check the results of multiple running State Machines */ + int n = 100; /* 10 sec */ + while (dds_security_fsm_current_state(fsm_auth) != &StateHandshakeInitMessageWait && n-- > 0) + dds_sleepfor(DDS_MSECS(100)); + CU_ASSERT_FATAL(n > 0); + + n = 100; /* 10 sec */ + dds_security_fsm_dispatch(fsm_auth, SHM_MSG_RECEIVED, false); + while (dds_security_fsm_current_state(fsm_auth) != NULL && n-- > 0) + dds_sleepfor(DDS_MSECS(100)); + CU_ASSERT_FATAL(n > 0); + + // not all bits are set since we're running the state machine a second time + ddsrt_mutex_lock (&g_lock); + CU_ASSERT_FATAL(visited_auth == 0x55); + ddsrt_mutex_unlock (&g_lock); + + /* Wait for the last state to occur */ + n = 100; /* 10 sec */ + while (dds_security_fsm_current_state(fsm_test) != NULL && n-- > 0) + dds_sleepfor(DDS_MSECS(100)); + CU_ASSERT_FATAL(n > 0); + + ddsrt_mutex_lock (&g_lock); + CU_ASSERT(visited_test == 0x1f); + ddsrt_mutex_unlock (&g_lock); + + dds_security_fsm_free(fsm_auth); + dds_security_fsm_free(fsm_test); + +} + +/** + * Check creation of State Machine for timeout purposes + */ +CU_Test(ddssec_fsm, timeout, .init = fsm_control_init, .fini = fsm_control_fini) +{ + visited_timeout = 0; + /* Test timeout monitoring of state machines */ + fsm_timeout = dds_security_fsm_create(g_fsm_control, timeout_transitions, timeout_transitionsSize, &fsm_arg); + CU_ASSERT(fsm_timeout != NULL); + dds_security_fsm_set_timeout(fsm_timeout, timeout_cb, DDS_SECS(1)); + dds_security_fsm_start(fsm_timeout); + + int n = 100; /* 10 sec */ + ddsrt_mutex_lock (&g_lock); + while (visited_timeout != 0x7 && n-- > 0) + { + ddsrt_mutex_unlock (&g_lock); + dds_sleepfor(DDS_MSECS(100)); + ddsrt_mutex_lock (&g_lock); + } + CU_ASSERT(n > 0); + CU_ASSERT(visited_timeout == 0x7); + CU_ASSERT(correct_arg_timeout && correct_fsm_timeout); + ddsrt_mutex_unlock (&g_lock); + dds_security_fsm_free(fsm_timeout); +} + +/* Check the double global timeout */ +CU_Test(ddssec_fsm, double_timeout, .init = fsm_control_init, .fini = fsm_control_fini) +{ + visited_timeout = 0; + fsm_timeout = dds_security_fsm_create(g_fsm_control, timeout_transitions, timeout_transitionsSize, &fsm_arg); + CU_ASSERT(fsm_timeout != NULL); + + fsm_timeout2 = dds_security_fsm_create(g_fsm_control, timeout_transitions, timeout_transitionsSize, &fsm_arg); + CU_ASSERT(fsm_timeout2 != NULL); + + dds_security_fsm_set_timeout(fsm_timeout, timeout_cb, DDS_SECS(1)); + dds_security_fsm_set_timeout(fsm_timeout2, timeout_cb2, DDS_SECS(2)); + dds_security_fsm_start(fsm_timeout); + dds_security_fsm_start(fsm_timeout2); + int n = 100; + ddsrt_mutex_lock (&g_lock); + while (visited_timeout != 0xf && n-- > 0) + { + ddsrt_mutex_unlock (&g_lock); + dds_sleepfor(DDS_MSECS(100)); + ddsrt_mutex_lock (&g_lock); + } + CU_ASSERT(visited_timeout == 0xf); + ddsrt_mutex_unlock (&g_lock); + dds_security_fsm_free(fsm_timeout); + dds_security_fsm_free(fsm_timeout2); +} + +/* Check parallel state timeouts */ +CU_Test(ddssec_fsm, parallel_timeout, .init = fsm_control_init, .fini = fsm_control_fini) +{ + visited_timeout = 0; + + fsm_timeout1 = dds_security_fsm_create(g_fsm_control, parallel_timeout_transitions_1, parallel_timeout_transitionsSize_1, &fsm_arg); + CU_ASSERT_FATAL(fsm_timeout1 != NULL); + fsm_timeout2 = dds_security_fsm_create(g_fsm_control, parallel_timeout_transitions_2, parallel_timeout_transitionsSize_2, &fsm_arg); + CU_ASSERT_FATAL(fsm_timeout2 != NULL); + fsm_timeout3 = dds_security_fsm_create(g_fsm_control, parallel_timeout_transitions_3, parallel_timeout_transitionsSize_3, &fsm_arg); + CU_ASSERT_FATAL(fsm_timeout3 != NULL); + + time0 = dds_time(); + dds_security_fsm_start(fsm_timeout1); + dds_security_fsm_start(fsm_timeout2); + dds_security_fsm_start(fsm_timeout3); + + int n = 300; + while (((dds_security_fsm_current_state(fsm_timeout1) == NULL) + || (dds_security_fsm_current_state(fsm_timeout2) == NULL) + || (dds_security_fsm_current_state(fsm_timeout3) == NULL)) && n-- > 0) + { + dds_sleepfor(DDS_MSECS(100)); + } + while (((dds_security_fsm_current_state(fsm_timeout1) != NULL) + || (dds_security_fsm_current_state(fsm_timeout2) != NULL) + || (dds_security_fsm_current_state(fsm_timeout3) != NULL)) && n-- > 0) + { + dds_sleepfor(DDS_MSECS(100)); + } + + dds_duration_t delta1 = time1 - time0; + dds_duration_t delta2 = time2 - time0; + dds_duration_t delta3 = time3 - time0; + printf("time0 %"PRId64"\n", time0); + printf("time1 %"PRId64", delta1 %"PRId64"\n", time1, delta1); + printf("time2 %"PRId64", delta2 %"PRId64"\n", time2, delta2); + printf("time3 %"PRId64", delta3 %"PRId64"\n", time3, delta3); + CU_ASSERT(delta1 > DDS_MSECS(750)); + CU_ASSERT(delta1 < DDS_MSECS(1250)); + CU_ASSERT(delta2 > DDS_MSECS(1750)); + CU_ASSERT(delta2 < DDS_MSECS(2250)); + CU_ASSERT(delta3 > DDS_MSECS(750)); + CU_ASSERT(delta3 < DDS_MSECS(1250)); + + dds_security_fsm_free(fsm_timeout1); + dds_security_fsm_free(fsm_timeout2); + dds_security_fsm_free(fsm_timeout3); +} + +/* Delete with event timeout */ +CU_Test(ddssec_fsm, delete_with_timeout, .init = fsm_control_init, .fini = fsm_control_fini) +{ + fsm_timeout = dds_security_fsm_create(g_fsm_control, timeout_transitions, timeout_transitionsSize, &fsm_arg); + CU_ASSERT (fsm_timeout != NULL) + visited_timeout = 0; + dds_security_fsm_start(fsm_timeout); + + int n = 100; + ddsrt_mutex_lock (&g_lock); + while (visited_timeout == 0 && n-- > 0) + { + ddsrt_mutex_unlock (&g_lock); + dds_sleepfor(DDS_MSECS(100)); + ddsrt_mutex_lock (&g_lock); + } + ddsrt_mutex_unlock (&g_lock); + dds_security_fsm_free(fsm_timeout); +} + diff --git a/src/security/core/tests/handshake.c b/src/security/core/tests/handshake.c new file mode 100644 index 0000000..4988f69 --- /dev/null +++ b/src/security/core/tests/handshake.c @@ -0,0 +1,195 @@ +/* + * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include + +#include "dds/dds.h" +#include "CUnit/Test.h" + +#include "dds/version.h" +#include "dds/ddsrt/cdtors.h" +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsi/q_config.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/ddsi/q_misc.h" +#include "dds/ddsi/ddsi_xqos.h" + +#include "dds/security/dds_security_api.h" + +#include "common/config_env.h" +#include "common/authentication_wrapper.h" +#include "common/cryptography_wrapper.h" +#include "common/plugin_wrapper_msg_q.h" +#include "common/test_utils.h" +#include "common/test_identity.h" +#include "common/security_config_test_utils.h" + +static const char *config = + "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}" + "" + " " + " 0" + " \\${CYCLONEDDS_PID}" + " " + " " + " " + " " + " data:,"TEST_IDENTITY1_CERTIFICATE"" + " data:,"TEST_IDENTITY1_PRIVATE_KEY"" + " data:,"TEST_IDENTITY_CA1_CERTIFICATE"" + " " + " " + " " + " file:" COMMON_ETC_PATH("default_governance.p7s") "" + " file:" COMMON_ETC_PATH("default_permissions_ca.pem") "" + " file:" COMMON_ETC_PATH("default_permissions.p7s") "" + " " + " " + " " + " " + " " + ""; + +#define DDS_DOMAINID1 0 +#define DDS_DOMAINID2 1 + +static dds_entity_t g_domain1 = 0; +static dds_entity_t g_participant1 = 0; + +static dds_entity_t g_domain2 = 0; +static dds_entity_t g_participant2 = 0; + +static uint32_t g_topic_nr = 0; +static dds_entity_t g_pub = 0, g_pub_tp = 0, g_wr = 0, g_sub = 0, g_sub_tp = 0, g_rd = 0; + +static void handshake_init(const char * auth_init, const char * auth_fini, const char * crypto_init, const char * crypto_fini) +{ + struct kvp config_vars[] = { + { "AUTH_INIT", auth_init, 1}, + { "AUTH_FINI", auth_fini, 1}, + { "CRYPTO_INIT", crypto_init, 1 }, + { "CRYPTO_FINI", crypto_fini, 1 }, + { NULL, NULL, 0 } + }; + + char *conf = ddsrt_expand_vars_sh (config, &expand_lookup_vars_env, config_vars); + int32_t unmatched = expand_lookup_unmatched (config_vars); + CU_ASSERT_EQUAL_FATAL (unmatched, 0); + g_domain1 = dds_create_domain (DDS_DOMAINID1, conf); + g_domain2 = dds_create_domain (DDS_DOMAINID2, conf); + dds_free (conf); + + g_participant1 = dds_create_participant (DDS_DOMAINID1, NULL, NULL); + CU_ASSERT_FATAL (g_participant1 > 0); + g_participant2 = dds_create_participant (DDS_DOMAINID2, NULL, NULL); + CU_ASSERT_FATAL (g_participant2 > 0); +} + +static void handshake_fini(void) +{ + dds_return_t ret = dds_delete (g_domain1); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + ret = dds_delete (g_domain2); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); +} + +/* Happy-day test for the security handshake, that tests succesfull handshake for + two participants using the same typical security settings. */ +CU_Test(ddssec_handshake, happy_day) +{ + struct Handshake *hs_list; + int nhs; + + handshake_init ( + "init_test_authentication_wrapped", "finalize_test_authentication_wrapped", + "init_test_cryptography_wrapped", "finalize_test_cryptography_wrapped"); + + validate_handshake (DDS_DOMAINID1, false, NULL, &hs_list, &nhs, DDS_SECS(2)); + CU_ASSERT_EQUAL_FATAL (nhs, 1); + for (int n = 0; n < nhs; n++) + validate_handshake_result (&hs_list[n], false, NULL, false, NULL); + handshake_list_fini (hs_list, nhs); + + validate_handshake (DDS_DOMAINID2, false, NULL, &hs_list, &nhs, DDS_SECS(2)); + CU_ASSERT_EQUAL_FATAL (nhs, 1); + for (int n = 0; n < nhs; n++) + validate_handshake_result (&hs_list[n], false, NULL, false, NULL); + handshake_list_fini (hs_list, nhs); + + handshake_fini (); +} + +/* This test checks that all tokens that are sent to a remote participant are received + correctly by that participant and the token-data stored in the remote participant + is equal to the data in the token that was sent. */ +CU_Test(ddssec_handshake, check_tokens) +{ + handshake_init ( + "init_test_authentication_wrapped", "finalize_test_authentication_wrapped", + "init_test_cryptography_store_tokens", "finalize_test_cryptography_store_tokens"); + validate_handshake_nofail (DDS_DOMAINID1, DDS_SECS (2)); + validate_handshake_nofail (DDS_DOMAINID2, DDS_SECS (2)); + + char topic_name[100]; + create_topic_name("ddssec_authentication_", g_topic_nr++, topic_name, sizeof (topic_name)); + rd_wr_init (g_participant1, &g_pub, &g_pub_tp, &g_wr, g_participant2, &g_sub, &g_sub_tp, &g_rd, topic_name); + write_read_for (g_wr, g_participant2, g_rd, DDS_MSECS (100), false, false); + + // Get subscriber and publisher crypto tokens + struct dds_security_cryptography_impl * crypto_context_pub = get_cryptography_context (g_participant1); + CU_ASSERT_FATAL (crypto_context_pub != NULL); + struct ddsrt_circlist *pub_tokens = get_crypto_tokens (crypto_context_pub); + + struct dds_security_cryptography_impl * crypto_context_sub = get_cryptography_context (g_participant2); + CU_ASSERT_FATAL (crypto_context_sub != NULL); + struct ddsrt_circlist *sub_tokens = get_crypto_tokens (crypto_context_sub); + + // Find all publisher tokens in subscribers token store + while (!ddsrt_circlist_isempty (pub_tokens)) + { + struct ddsrt_circlist_elem *list_elem = ddsrt_circlist_oldest (pub_tokens); + struct crypto_token_data *token_data = DDSRT_FROM_CIRCLIST (struct crypto_token_data, e, list_elem); + enum crypto_tokens_type exp_type = TOKEN_TYPE_INVALID; + for (size_t n = 0; n < token_data->n_tokens; n++) + { + switch (token_data->type) + { + case LOCAL_PARTICIPANT_TOKENS: exp_type = REMOTE_PARTICIPANT_TOKENS; break; + case REMOTE_PARTICIPANT_TOKENS: exp_type = LOCAL_PARTICIPANT_TOKENS; break; + case LOCAL_WRITER_TOKENS: exp_type = REMOTE_WRITER_TOKENS; break; + case REMOTE_WRITER_TOKENS: exp_type = LOCAL_WRITER_TOKENS; break; + case LOCAL_READER_TOKENS: exp_type = REMOTE_READER_TOKENS; break; + case REMOTE_READER_TOKENS: exp_type = LOCAL_READER_TOKENS; break; + default: CU_FAIL ("Unexpected token type"); + } + printf("- find token %s #%"PRIuSIZE", len %"PRIuSIZE"\n", get_crypto_token_type_str (token_data->type), n, token_data->data_len[n]); + struct crypto_token_data *st = find_crypto_token (crypto_context_sub, exp_type, token_data->data[n], token_data->data_len[n]); + CU_ASSERT_FATAL (st != NULL); + } + ddsrt_circlist_remove (pub_tokens, list_elem); + ddsrt_free (token_data); + } + + // Cleanup + while (!ddsrt_circlist_isempty (sub_tokens)) + { + struct ddsrt_circlist_elem *list_elem = ddsrt_circlist_oldest (sub_tokens); + ddsrt_circlist_remove (sub_tokens, list_elem); + ddsrt_free (list_elem); + } + ddsrt_free (sub_tokens); + ddsrt_free (pub_tokens); + handshake_fini (); +} diff --git a/src/security/core/tests/plugin_loading.c b/src/security/core/tests/plugin_loading.c new file mode 100644 index 0000000..8e09cc5 --- /dev/null +++ b/src/security/core/tests/plugin_loading.c @@ -0,0 +1,680 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include "CUnit/Test.h" +#include "dds/dds.h" +#include "dds/ddsrt/cdtors.h" +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsi/q_misc.h" +#include "dds/security/dds_security_api_defs.h" +#include "common/config_env.h" +#include "common/test_identity.h" + +#define MAX_PARTICIPANTS_VARIABLE "MAX_PARTICIPANTS" + +static uint32_t found; + +static const char *default_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " finest" + ""; + +static void logger(void *ptr, const dds_log_data_t *data) +{ + char **expected = (char **)ptr; + fputs(data->message, stdout); + for (uint32_t i = 0; expected[i] != NULL; i++) + { + if (ddsi2_patmatch(expected[i], data->message)) + { + found |= (uint32_t)(1 << i); + } + } +} + +static void set_logger_exp(const void *log_expected) +{ + found = 0; + dds_set_log_mask(DDS_LC_FATAL | DDS_LC_ERROR | DDS_LC_WARNING | DDS_LC_CONFIG); + dds_set_log_sink(&logger, (void *)log_expected); + dds_set_trace_sink(&logger, (void *)log_expected); +} + +static void reset_logger() +{ + dds_set_log_sink(NULL, NULL); + dds_set_trace_sink(NULL, NULL); +} + +CU_Test(ddssec_security_plugin_loading, all_ok, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + const char *log_expected[] = { + "DDS Security plugins have been loaded*", + NULL}; + + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " finest" + " " + " " + " " + " "TEST_IDENTITY_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_PRIVATE_KEY_DUMMY"" + " testtext_Password_testtext" + " testtext_Dir_testtext" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + + set_logger_exp(log_expected); + domain = dds_create_domain(0, sec_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, NULL, NULL); + CU_ASSERT_FATAL(participant > 0); + dds_delete(participant); + dds_delete(domain); + reset_logger(); + + CU_ASSERT_FATAL(found == 0x1); +} + +CU_Test(ddssec_security_plugin_loading, missing_finalize, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + const char *log_expected[] = { + "Could not find the function: finalize_test_authentication_NON_EXISTING_FUNC*", + "Could not load Authentication plugin*", + NULL}; + + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " warning" + " " + " " + " " + " "TEST_IDENTITY_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_PRIVATE_KEY_DUMMY"" + " testtext_Password_testtext" + " testtext_Dir_testtext" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + + set_logger_exp(log_expected); + domain = dds_create_domain(0, sec_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, NULL, NULL); + CU_ASSERT_EQUAL_FATAL(participant, DDS_RETCODE_ERROR); + dds_delete(domain); + reset_logger(); + + CU_ASSERT_FATAL(found == 0x3); +} + +CU_Test(ddssec_security_plugin_loading, authentication_missing_function, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + const char *log_expected[] = { + "Could not find the function for Authentication: get_shared_secret*", + "Could not load security*", + NULL}; + + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " warning" + " " + " " + " " + " "TEST_IDENTITY_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_PRIVATE_KEY_DUMMY"" + " testtext_Password_testtext" + " testtext_Dir_testtext" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + + set_logger_exp(log_expected); + domain = dds_create_domain(0, sec_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, NULL, NULL); + CU_ASSERT_EQUAL_FATAL(participant, DDS_RETCODE_ERROR); + dds_delete(domain); + reset_logger(); + + CU_ASSERT_FATAL(found == 0x3); +} + +CU_Test(ddssec_security_plugin_loading, access_control_missing_function, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + const char *log_expected[] = { + "Could not find the function for Access Control: check_create_datareader*", + "Could not load security*", + NULL}; + + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " warning" + " " + " " + " " + " "TEST_IDENTITY_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_PRIVATE_KEY_DUMMY"" + " testtext_Password_testtext" + " testtext_Dir_testtext" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + + set_logger_exp(log_expected); + domain = dds_create_domain(0, sec_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, NULL, NULL); + CU_ASSERT_EQUAL_FATAL(participant, DDS_RETCODE_ERROR); + dds_delete(domain); + reset_logger(); + + CU_ASSERT_FATAL(found == 0x3); +} + +CU_Test(ddssec_security_plugin_loading, cryptography_missing_function, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + const char *log_expected[] = { + "Could not find the function for Cryptographic: set_remote_participant_crypto_tokens*", + "Could not load security*", + NULL}; + + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " warning" + " " + " " + " " + " "TEST_IDENTITY_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_PRIVATE_KEY_DUMMY"" + " testtext_Password_testtext" + " testtext_Dir_testtext" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + + set_logger_exp(log_expected); + domain = dds_create_domain(0, sec_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, NULL, NULL); + CU_ASSERT_EQUAL_FATAL(participant, DDS_RETCODE_ERROR); + dds_delete(domain); + reset_logger(); + + CU_ASSERT_FATAL(found == 0x3); +} + +CU_Test(ddssec_security_plugin_loading, no_library_in_path, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + const char *log_expected[] = { + "Could not load Authentication library: " WRAPPERLIB_PATH("dds_security_authentication_wrapper_INVALID") ": cannot open shared object file: No such file or directory*", + "Could not load Authentication library: dlopen(" WRAPPERLIB_PATH("dds_security_authentication_wrapper_INVALID") "*", + "Could not load Authentication library: The specified module could not be found.*", + "Could not load Authentication plugin*", + "Could not load security*", + NULL}; + + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " warning" + " " + " " + " " + " "TEST_IDENTITY_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_PRIVATE_KEY_DUMMY"" + " testtext_Password_testtext" + " testtext_Dir_testtext" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + + set_logger_exp(log_expected); + domain = dds_create_domain(0, sec_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, NULL, NULL); + CU_ASSERT_EQUAL_FATAL(participant, DDS_RETCODE_ERROR); + dds_delete(domain); + reset_logger(); + + CU_ASSERT_FATAL(found == 0x19 || found == 0x1a || found == 0x1c); +} + +CU_Test(ddssec_security_plugin_loading, init_error, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + const char *log_expected[] = { + "Error occured while initializing Authentication plugin*", + "Could not load Authentication plugin*", + "Could not load security*", + NULL}; + + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " warning" + " " + " " + " " + " "TEST_IDENTITY_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_PRIVATE_KEY_DUMMY"" + " testtext_Password_testtext" + " testtext_Dir_testtext" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + + set_logger_exp(log_expected); + domain = dds_create_domain(0, sec_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, NULL, NULL); + CU_ASSERT_EQUAL_FATAL(participant, DDS_RETCODE_ERROR); + dds_delete(domain); + reset_logger(); + + CU_ASSERT_FATAL(found == 0x7); +} + +CU_Test(ddssec_security_plugin_loading, all_ok_with_props, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + dds_qos_t *qos; + const char *log_expected[] = { + "DDS Security plugins have been loaded*", + NULL}; + + unsigned char bvalue[3] = {0x01, 0x02, 0x03}; + CU_ASSERT_FATAL((qos = dds_create_qos()) != NULL); + dds_qset_prop(qos, "test.prop1", "testtext_value1_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_IDENTITY_CA, "testtext_IdentityCA_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_PRIV_KEY, "testtext_PrivateKey_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_IDENTITY_CERT, "testtext_IdentityCertificate_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_PERMISSIONS_CA, "file:"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_GOVERNANCE, "file:"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_PERMISSIONS, "file:"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_PASSWORD, "testtext_Password_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_TRUSTED_CA_DIR, "file:/test/dir"); + + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_PATH, WRAPPERLIB_PATH("dds_security_authentication_wrapper")); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_INIT, "init_test_authentication_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_FINALIZE, "finalize_test_authentication_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_PATH, WRAPPERLIB_PATH("dds_security_cryptography_wrapper")); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_INIT, "init_test_cryptography_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_FINALIZE, "finalize_test_cryptography_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_PATH, WRAPPERLIB_PATH("dds_security_access_control_wrapper")); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_INIT, "init_test_access_control_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_FINALIZE, "finalize_test_access_control_all_ok"); + + dds_qset_prop(qos, "test.prop2", "testtext_value2_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_IDENTITY_CA, "testtext_IdentityCA_testtext"); + dds_qset_bprop(qos, "test.bprop1", bvalue, 3); + + set_logger_exp(log_expected); + domain = dds_create_domain(0, default_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, qos, NULL); + CU_ASSERT_FATAL(participant > 0); + dds_delete(participant); + dds_delete(domain); + dds_delete_qos(qos); + reset_logger(); + + CU_ASSERT_FATAL(found == 0x1); +} + +CU_Test(ddssec_security_plugin_loading, missing_plugin_property_with_props, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + dds_qos_t *qos; + const char *log_expected[] = { + "*using security settings from QoS*", + "*required security property dds.sec.auth.library.init missing in Property QoS*", + NULL}; + + unsigned char bvalue[3] = {0x01, 0x02, 0x03}; + CU_ASSERT_FATAL((qos = dds_create_qos()) != NULL); + dds_qset_prop(qos, "test.prop1", "testtext_value1_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_IDENTITY_CA, "testtext_IdentityCA_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_PRIV_KEY, "testtext_PrivateKey_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_IDENTITY_CERT, "testtext_IdentityCertificate_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_PERMISSIONS_CA, "file:"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_GOVERNANCE, "file:"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_PERMISSIONS, "file:"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_PASSWORD, "testtext_Password_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_TRUSTED_CA_DIR, "file:/test/dir"); + + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_PATH, "dds_security_authentication_all_ok"); + // missing: dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_INIT, "init_authentication"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_FINALIZE, "finalize_authentication"); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_PATH, "dds_security_cryptography_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_INIT, "init_crypto"); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_FINALIZE, "finalize_crypto"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_PATH, "dds_security_access_control_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_INIT, "init_access_control"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_FINALIZE, "finalize_access_control"); + + dds_qset_prop(qos, "test.prop2", "testtext_value2_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_IDENTITY_CA, "testtext_IdentityCA_testtext"); + dds_qset_bprop(qos, "test.bprop1", bvalue, 3); + + set_logger_exp(log_expected); + domain = dds_create_domain(0, default_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(0, qos, NULL); + CU_ASSERT_EQUAL_FATAL(participant, DDS_RETCODE_ERROR); + dds_delete_qos(qos); + dds_delete(domain); + reset_logger(); + + CU_ASSERT_FATAL(found == 0x3); +} + +CU_Test(ddssec_security_plugin_loading, empty_plugin_property_with_props, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + dds_qos_t *qos; + const char *log_expected[] = { + "*using security settings from QoS*", + "*required security property dds.sec.auth.library.finalize missing in Property QoS*", + NULL}; + + unsigned char bvalue[3] = {0x01, 0x02, 0x03}; + CU_ASSERT_FATAL((qos = dds_create_qos()) != NULL); + dds_qset_prop(qos, "test.prop1", "testtext_value1_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_IDENTITY_CA, "testtext_IdentityCA_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_PRIV_KEY, "testtext_PrivateKey_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_IDENTITY_CERT, "testtext_IdentityCertificate_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_PERMISSIONS_CA, "file:Permissions_CA.pem"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_GOVERNANCE, "file:"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_PERMISSIONS, "file:"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_PASSWORD, "testtext_Password_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_TRUSTED_CA_DIR, "file:/test/dir"); + + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_PATH, "dds_security_authentication_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_INIT, "init_authentication"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_FINALIZE, ""); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_PATH, "dds_security_cryptography_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_INIT, "init_crypto"); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_FINALIZE, "finalize_crypto"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_PATH, "dds_security_access_control_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_INIT, "init_access_control"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_FINALIZE, "finalize_access_control"); + + dds_qset_prop(qos, "test.prop2", "testtext_value2_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_IDENTITY_CA, "testtext_IdentityCA_testtext"); + dds_qset_bprop(qos, "test.bprop1", bvalue, 3); + + set_logger_exp(log_expected); + domain = dds_create_domain(0, default_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(DDS_DOMAIN_DEFAULT, qos, NULL); + CU_ASSERT_EQUAL_FATAL(participant, DDS_RETCODE_ERROR); + dds_delete_qos(qos); + dds_delete(domain); + reset_logger(); + + CU_ASSERT_FATAL(found == 0x3); +} + +CU_Test(ddssec_security_plugin_loading, missing_security_property_with_props, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain, participant; + dds_qos_t *qos; + const char *log_expected[] = { + "*using security settings from QoS*", + "*required security property dds.sec.access.permissions missing in Property QoS*", + NULL}; + + unsigned char bvalue[3] = {0x01, 0x02, 0x03}; + CU_ASSERT_FATAL((qos = dds_create_qos()) != NULL); + dds_qset_prop(qos, "test.prop1", "testtext_value1_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_IDENTITY_CA, "testtext_IdentityCA_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_PRIV_KEY, "testtext_PrivateKey_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_IDENTITY_CERT, "testtext_IdentityCertificate_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_PERMISSIONS_CA, "file:"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_GOVERNANCE, "file:"); + //dds_qset_prop (qos, DDS_SEC_PROP_ACCESS_PERMISSIONS, "file:"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_PASSWORD, "testtext_Password_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_TRUSTED_CA_DIR, "file:/test/dir"); + + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_PATH, "dds_security_authentication_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_INIT, "init_authentication"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_FINALIZE, "finalize_authentication"); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_PATH, "dds_security_cryptography_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_INIT, "init_crypto"); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_FINALIZE, "finalize_crypto"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_PATH, "dds_security_access_control_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_INIT, "init_access_control"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_FINALIZE, "finalize_access_control"); + + dds_qset_prop(qos, "test.prop2", "testtext_value2_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_IDENTITY_CA, "testtext_IdentityCA_testtext"); + dds_qset_bprop(qos, "test.bprop1", bvalue, 3); + + set_logger_exp(log_expected); + domain = dds_create_domain(0, default_config); + CU_ASSERT_FATAL(domain > 0); + participant = dds_create_participant(DDS_DOMAIN_DEFAULT, qos, NULL); + CU_ASSERT_EQUAL_FATAL(participant, DDS_RETCODE_ERROR); + dds_delete_qos(qos); + dds_delete(domain); + reset_logger(); + + CU_ASSERT_FATAL(found == 0x3); +} + +CU_Test(ddssec_security_plugin_loading, multiple_domains_different_config, .init = ddsrt_init, .fini = ddsrt_fini) +{ + dds_entity_t domain1, domain2, participant1, participant2, participant3; + dds_qos_t *qos; + const char *log_expected[] = { + "*using security settings from configuration*", + "*using security settings from QoS*", + "DDS Security plugins have been loaded*", + "*security is already loaded for this domain*", + NULL}; + + const char *sec_config = + "" + " " + " ${CYCLONEDDS_PID}" + " " + " finest" + " " + " " + " " + " "TEST_IDENTITY_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_PRIVATE_KEY_DUMMY"" + " testtext_Password_testtext" + " testtext_Dir_testtext" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + "" + "" + " finest" + " " + " ${CYCLONEDDS_PID}" + " " + " " + " " + " " + " "TEST_IDENTITY_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_CA_CERTIFICATE_DUMMY"" + " "TEST_IDENTITY_PRIVATE_KEY_DUMMY"" + " testtext_Password_testtext" + " testtext_Dir_testtext" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + + set_logger_exp(log_expected); + + domain1 = dds_create_domain(1, sec_config); + CU_ASSERT_FATAL(domain1 > 0); + domain2 = dds_create_domain(2, sec_config); + CU_ASSERT_FATAL(domain2 > 0); + + /* Create the qos */ + CU_ASSERT_FATAL((qos = dds_create_qos()) != NULL); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_IDENTITY_CA, "testtext_IdentityCA_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_PRIV_KEY, "testtext_PrivateKey_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_IDENTITY_CERT, "testtext_IdentityCertificate_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_PERMISSIONS_CA, "file:"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_GOVERNANCE, "file:"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_PERMISSIONS, "file:"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_PASSWORD, "testtext_Password_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_TRUSTED_CA_DIR, "file:/test/dir"); + + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_PATH, WRAPPERLIB_PATH("dds_security_authentication_wrapper")); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_INIT, "init_test_authentication_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_LIBRARY_FINALIZE, "finalize_test_authentication_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_AUTH_IDENTITY_CA, "testtext_IdentityCA_testtext"); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_PATH, WRAPPERLIB_PATH("dds_security_cryptography_wrapper")); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_INIT, "init_test_cryptography_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_CRYPTO_LIBRARY_FINALIZE, "finalize_test_cryptography_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_PATH, WRAPPERLIB_PATH("dds_security_access_control_wrapper")); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_INIT, "init_test_access_control_all_ok"); + dds_qset_prop(qos, DDS_SEC_PROP_ACCESS_LIBRARY_FINALIZE, "finalize_test_access_control_all_ok"); + + participant1 = dds_create_participant(1, NULL, NULL); + participant2 = dds_create_participant(2, NULL, NULL); + participant3 = dds_create_participant(2, qos, NULL); + CU_ASSERT_FATAL(participant1 > 0); + CU_ASSERT_FATAL(participant2 > 0); + CU_ASSERT_FATAL(participant3 > 0); + dds_delete_qos(qos); + dds_delete(domain1); + dds_delete(domain2); + reset_logger(); + + CU_ASSERT_FATAL(found == 0xf); +} 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/secure_communication.c b/src/security/core/tests/secure_communication.c new file mode 100644 index 0000000..2d1720d --- /dev/null +++ b/src/security/core/tests/secure_communication.c @@ -0,0 +1,479 @@ +/* + * Copyright(c) 2006 to 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include + +#include "dds/dds.h" +#include "CUnit/Test.h" +#include "CUnit/Theory.h" + +#include "dds/version.h" +#include "dds/ddsrt/cdtors.h" +#include "dds/ddsrt/environ.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/threads.h" +#include "dds/ddsrt/process.h" +#include "dds/ddsi/q_config.h" +#include "dds/ddsi/ddsi_domaingv.h" +#include "dds/ddsi/q_misc.h" +#include "dds/ddsi/ddsi_xqos.h" +#include "dds/security/dds_security_api.h" + +#include "common/config_env.h" +#include "common/test_identity.h" +#include "common/test_utils.h" +#include "common/security_config_test_utils.h" +#include "common/cryptography_wrapper.h" + +#include "SecurityCoreTests.h" + +static const char *config = + "${CYCLONEDDS_URI}${CYCLONEDDS_URI:+,}" + "" + " " + " 0" + " \\${CYCLONEDDS_PID}" + " " + " " + " " + " " + " data:,"TEST_IDENTITY1_CERTIFICATE"" + " data:,"TEST_IDENTITY1_PRIVATE_KEY"" + " data:,"TEST_IDENTITY_CA1_CERTIFICATE"" + " " + " ." + " " + " " + " " + " " + " file:" COMMON_ETC_PATH("default_permissions_ca.pem") "" + " file:" COMMON_ETC_PATH("default_permissions.p7s") "" + " " + " " + " " + " " + " " + ""; + +#define DDS_DOMAINID_PUB 0 +#define DDS_DOMAINID_SUB 10 + +#define MAX_DOMAINS 10 +#define MAX_PARTICIPANTS 10 + +uint32_t g_topic_nr = 0; + +static dds_entity_t g_pub_domains[MAX_DOMAINS]; +static dds_entity_t g_pub_participants[MAX_DOMAINS * MAX_PARTICIPANTS]; +static dds_entity_t g_pub_publishers[MAX_DOMAINS * MAX_PARTICIPANTS]; + +static dds_entity_t g_sub_domains[MAX_DOMAINS]; +static dds_entity_t g_sub_participants[MAX_DOMAINS * MAX_PARTICIPANTS]; +static dds_entity_t g_sub_subscribers[MAX_DOMAINS * MAX_PARTICIPANTS]; + +struct domain_sec_config { + DDS_Security_ProtectionKind discovery_pk; + DDS_Security_ProtectionKind liveliness_pk; + DDS_Security_ProtectionKind rtps_pk; + DDS_Security_ProtectionKind metadata_pk; + DDS_Security_BasicProtectionKind payload_pk; + const char * payload_secret; + const char * pp_userdata_secret; + const char * groupdata_secret; + const char * ep_userdata_secret; +}; + +typedef void (*set_crypto_params_fn)(struct dds_security_cryptography_impl *, const struct domain_sec_config *); +typedef dds_entity_t (*pubsub_create_fn)(dds_entity_t, const dds_qos_t *qos, const dds_listener_t *listener); +typedef dds_entity_t (*ep_create_fn)(dds_entity_t, dds_entity_t, const dds_qos_t *qos, const dds_listener_t *listener); + +const char * g_pp_secret = "ppsecret"; +const char * g_groupdata_secret = "groupsecret"; +const char * g_ep_secret = "epsecret"; + +static dds_qos_t *get_qos() +{ + dds_qos_t * qos = dds_create_qos (); + CU_ASSERT_FATAL (qos != NULL); + dds_qset_history (qos, DDS_HISTORY_KEEP_ALL, -1); + dds_qset_durability (qos, DDS_DURABILITY_TRANSIENT_LOCAL); + dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_INFINITY); + dds_qset_userdata (qos, g_ep_secret, strlen (g_ep_secret)); + return qos; +} + +static dds_entity_t create_pp (dds_domainid_t domain_id, const struct domain_sec_config * domain_config, set_crypto_params_fn set_crypto_params) +{ + dds_qos_t *qos = dds_create_qos (); + dds_qset_userdata (qos, g_pp_secret, strlen (g_pp_secret)); + dds_entity_t pp = dds_create_participant (domain_id, qos, NULL); + CU_ASSERT_FATAL (pp > 0); + dds_delete_qos (qos); + struct dds_security_cryptography_impl * crypto_context = get_cryptography_context (pp); + CU_ASSERT_FATAL (crypto_context != NULL); + assert (set_crypto_params); + set_crypto_params (crypto_context, domain_config); + return pp; +} + + +static void create_dom_pp_pubsub(dds_domainid_t domain_id_base, const char * domain_conf, const struct domain_sec_config * domain_sec_config, + size_t n_dom, size_t n_pp, dds_entity_t * doms, dds_entity_t * pps, dds_entity_t * pubsubs, pubsub_create_fn pubsub_create, set_crypto_params_fn set_crypto_params) +{ + for (size_t d = 0; d < n_dom; d++) + { + doms[d] = dds_create_domain (domain_id_base + (uint32_t)d, domain_conf); + CU_ASSERT_FATAL (doms[d] > 0); + for (size_t p = 0; p < n_pp; p++) + { + size_t pp_index = d * n_pp + p; + pps[pp_index] = create_pp (domain_id_base + (uint32_t)d, domain_sec_config, set_crypto_params); + dds_qos_t *qos = dds_create_qos (); + dds_qset_groupdata (qos, g_groupdata_secret, strlen (g_groupdata_secret)); + pubsubs[pp_index] = pubsub_create (pps[pp_index], qos, NULL); + CU_ASSERT_FATAL (pubsubs[pp_index] > 0); + dds_delete_qos (qos); + } + } +} + +static void test_init(const struct domain_sec_config * domain_config, size_t n_sub_domains, size_t n_sub_participants, size_t n_pub_domains, size_t n_pub_participants, set_crypto_params_fn set_crypto_params) +{ + assert (n_sub_domains < MAX_DOMAINS); + assert (n_sub_participants < MAX_PARTICIPANTS); + assert (n_pub_domains < MAX_DOMAINS); + assert (n_pub_participants < MAX_PARTICIPANTS); + + char * gov_topic_rule = get_governance_topic_rule ("*", true, true, true, true, domain_config->metadata_pk, domain_config->payload_pk); + char * gov_config_signed = get_governance_config (false, true, domain_config->discovery_pk, domain_config->liveliness_pk, domain_config->rtps_pk, gov_topic_rule, false); + + struct kvp config_vars[] = { + { "GOVERNANCE_DATA", gov_config_signed, 1 }, + { NULL, NULL, 0 } + }; + + char *conf_pub = ddsrt_expand_vars_sh (config, &expand_lookup_vars_env, config_vars); + create_dom_pp_pubsub (DDS_DOMAINID_PUB, conf_pub, domain_config, n_pub_domains, n_pub_participants, + g_pub_domains, g_pub_participants, g_pub_publishers, &dds_create_publisher, set_crypto_params); + dds_free (conf_pub); + + char *conf_sub = ddsrt_expand_vars_sh (config, &expand_lookup_vars_env, config_vars); + create_dom_pp_pubsub (DDS_DOMAINID_SUB, conf_sub, domain_config, n_sub_domains, n_sub_participants, + g_sub_domains, g_sub_participants, g_sub_subscribers, &dds_create_subscriber, set_crypto_params); + dds_free (conf_sub); + + dds_free (gov_config_signed); + dds_free (gov_topic_rule); +} + +static void test_fini(size_t n_sub_domain, size_t n_pub_domain) +{ + dds_return_t ret; + for (size_t d = 0; d < n_pub_domain; d++) + { + ret = dds_delete (g_pub_domains[d]); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + } + for (size_t d = 0; d < n_sub_domain; d++) + { + ret = dds_delete (g_sub_domains[d]); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + } + printf("Test finished\n"); +} + +static void create_eps (dds_entity_t **endpoints, dds_entity_t **topics, size_t n_dom, size_t n_pp, size_t n_eps, const char * topic_name, const dds_topic_descriptor_t *topic_descriptor, + const dds_entity_t * pps, const dds_qos_t * qos, ep_create_fn ep_create, unsigned status_mask) +{ + *topics = ddsrt_malloc (n_dom * n_pp * sizeof (dds_entity_t)); + *endpoints = ddsrt_malloc (n_dom * n_pp * n_eps * sizeof (dds_entity_t)); + for (size_t d = 0; d < n_dom; d++) + { + for (size_t p = 0; p < n_pp; p++) + { + size_t pp_index = d * n_pp + p; + (*topics)[pp_index] = dds_create_topic (pps[pp_index], topic_descriptor, topic_name, NULL, NULL); + CU_ASSERT_FATAL ((*topics)[pp_index] > 0); + for (size_t e = 0; e < n_eps; e++) + { + size_t ep_index = pp_index * n_eps + e; + (*endpoints)[ep_index] = ep_create (pps[pp_index], (*topics)[pp_index], qos, NULL); + CU_ASSERT_FATAL ((*endpoints)[ep_index] > 0); + dds_return_t ret = dds_set_status_mask ((*endpoints)[ep_index], status_mask); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + } + } + } +} + +static void free_eps(dds_entity_t *endpoints, dds_entity_t *topics) +{ + ddsrt_free (endpoints); + ddsrt_free (topics); +} + +static void test_write_read(struct domain_sec_config *domain_config, + size_t n_sub_domains, size_t n_sub_participants, size_t n_readers, + size_t n_pub_domains, size_t n_pub_participants, size_t n_writers, + set_crypto_params_fn set_crypto_params) +{ + dds_entity_t *writers, *readers, *writer_topics, *reader_topics; + dds_qos_t *qos; + SecurityCoreTests_Type1 sample = { 0, 1 }; + SecurityCoreTests_Type1 rd_sample; + void * samples[] = { &rd_sample }; + dds_sample_info_t info[1]; + dds_return_t ret; + char name[100]; + + printf("Testing: %"PRIuSIZE" subscriber domains, %"PRIuSIZE" pp per domain, %"PRIuSIZE" rd per pp; %"PRIuSIZE" publishing domains, %"PRIuSIZE" pp per domain, %"PRIuSIZE" wr per pp\n", + n_sub_domains, n_sub_participants, n_readers, n_pub_domains, n_pub_participants, n_writers); + test_init(domain_config, n_sub_domains, n_sub_participants, n_pub_domains, n_pub_participants, set_crypto_params); + + create_topic_name("ddssec_secure_communication_", g_topic_nr++, name, sizeof name); + + qos = get_qos (); + create_eps (&writers, &writer_topics, n_pub_domains, n_pub_participants, n_writers, name, &SecurityCoreTests_Type1_desc, g_pub_participants, qos, &dds_create_writer, DDS_PUBLICATION_MATCHED_STATUS); + create_eps (&readers, &reader_topics, n_sub_domains, n_sub_participants, n_readers, name, &SecurityCoreTests_Type1_desc, g_sub_participants, qos, &dds_create_reader, DDS_DATA_AVAILABLE_STATUS); + + for (size_t d = 0; d < n_pub_domains; d++) + { + for (size_t p = 0; p < n_pub_participants; p++) + { + size_t pp_index = d * n_pub_participants + p; + for (size_t w = 0; w < n_writers; w++) + { + size_t wr_index = pp_index * n_writers + w; + sync_writer_to_readers (g_pub_participants[pp_index], writers[wr_index], (uint32_t)(n_sub_domains * n_sub_participants * n_readers), DDS_SECS(5)); + sample.id = (int32_t) wr_index; + printf("writer %"PRId32" writing sample %d\n", writers[wr_index], sample.id); + ret = dds_write (writers[wr_index], &sample); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + } + } + } + + for (size_t d = 0; d < n_sub_domains; d++) + { + for (size_t p = 0; p < n_sub_participants; p++) + { + size_t pp_index = d * n_sub_participants + p; + for (size_t r = 0; r < n_readers; r++) + { + size_t rd_index = pp_index * n_readers + r; + size_t n_samples = n_pub_domains * n_pub_participants * n_writers; + while (n_samples > 0) + { + ret = dds_take (readers[rd_index], samples, info, 1, 1); + if (ret == 0) + { + reader_wait_for_data (g_sub_participants[pp_index], readers[rd_index], DDS_SECS(5)); + continue; + } + printf("reader %"PRId32" received sample %d\n", readers[rd_index], rd_sample.id); + CU_ASSERT_EQUAL_FATAL (ret, 1); + CU_ASSERT_EQUAL_FATAL (rd_sample.value, 1); + n_samples--; + } + } + } + } + + /* Cleanup */ + dds_delete_qos (qos); + test_fini (n_sub_domains, n_pub_domains); + free_eps (readers, reader_topics); + free_eps (writers, writer_topics); +} + +static void set_encryption_parameters_basic(struct dds_security_cryptography_impl * crypto_context, const struct domain_sec_config *domain_config) +{ + set_protection_kinds (crypto_context, domain_config->rtps_pk, domain_config->metadata_pk, domain_config->payload_pk); +} + +static void set_encryption_parameters_secret(struct dds_security_cryptography_impl * crypto_context, const struct domain_sec_config *domain_config) +{ + set_encrypted_secret (crypto_context, domain_config->payload_secret); + set_encryption_parameters_basic (crypto_context, domain_config); +} + +static void set_encryption_parameters_disc(struct dds_security_cryptography_impl * crypto_context, const struct domain_sec_config *domain_config) +{ + set_entity_data_secret (crypto_context, domain_config->pp_userdata_secret, domain_config->groupdata_secret, domain_config->ep_userdata_secret); + set_encryption_parameters_basic (crypto_context, domain_config); + set_disc_protection_kinds (crypto_context, domain_config->discovery_pk, domain_config->liveliness_pk); +} + +static void test_discovery_liveliness_protection(DDS_Security_ProtectionKind discovery_pk, DDS_Security_ProtectionKind liveliness_pk) +{ + struct domain_sec_config domain_config = { discovery_pk, liveliness_pk, PK_N, PK_N, BPK_N, NULL }; + /* FIXME: add more asserts in wrapper or test instead of just testing communication */ + test_write_read (&domain_config, 1, 1, 1, 1, 1, 1, set_encryption_parameters_disc); +} + +static void test_data_protection_kind(DDS_Security_ProtectionKind rtps_pk, DDS_Security_ProtectionKind metadata_pk, DDS_Security_BasicProtectionKind payload_pk) +{ + struct domain_sec_config domain_config = { PK_N, PK_N, rtps_pk, metadata_pk, payload_pk, NULL }; + test_write_read (&domain_config, 1, 1, 1, 1, 1, 1, set_encryption_parameters_basic); +} + +static void test_multiple_readers(size_t n_dom, size_t n_pp, size_t n_rd, DDS_Security_ProtectionKind metadata_pk, DDS_Security_BasicProtectionKind payload_pk) +{ + struct domain_sec_config domain_config = { PK_N, PK_N, PK_N, metadata_pk, payload_pk, NULL }; + test_write_read (&domain_config, n_dom, n_pp, n_rd, 1, 1, 1, set_encryption_parameters_basic); +} + +static void test_multiple_writers(size_t n_rd_dom, size_t n_rd, size_t n_wr_dom, size_t n_wr, DDS_Security_ProtectionKind metadata_pk) +{ + struct domain_sec_config domain_config = { PK_N, PK_N, PK_N, metadata_pk, BPK_N, NULL }; + test_write_read (&domain_config, n_rd_dom, 1, n_rd, n_wr_dom, 1, n_wr, set_encryption_parameters_basic); +} + +static void test_payload_secret(DDS_Security_ProtectionKind rtps_pk, DDS_Security_ProtectionKind metadata_pk, DDS_Security_BasicProtectionKind payload_pk) +{ + dds_entity_t *writers, *readers, *writer_topics, *reader_topics; + const char * secret = "my_test_secret"; + dds_qos_t *qos; + SecurityCoreTests_Type2 sample; + SecurityCoreTests_Type2 rd_sample = {0, NULL}; + void * samples[] = { &rd_sample }; + dds_sample_info_t info[1]; + dds_return_t ret; + char name[100]; + struct domain_sec_config domain_config = { PK_N, PK_N, rtps_pk, metadata_pk, payload_pk, secret }; + + size_t payload_sz = 100 * strlen (secret) + 1; + sample.id = 1; + sample.text = ddsrt_malloc (payload_sz); + for (size_t n = 0; n < 100; n++) + memcpy (sample.text + n * strlen (secret), secret, strlen (secret)); + sample.text[payload_sz - 1] = '\0'; + + test_init (&domain_config, 1, 1, 1, 1, set_encryption_parameters_secret); + create_topic_name ("ddssec_secure_communication_", g_topic_nr++, name, sizeof name); + qos = get_qos (); + create_eps (&writers, &writer_topics, 1, 1, 1, name, &SecurityCoreTests_Type2_desc, g_pub_participants, qos, &dds_create_writer, DDS_PUBLICATION_MATCHED_STATUS); + create_eps (&readers, &reader_topics, 1, 1, 1, name, &SecurityCoreTests_Type2_desc, g_sub_participants, qos, &dds_create_reader, DDS_DATA_AVAILABLE_STATUS); + dds_delete_qos (qos); + sync_writer_to_readers (g_pub_participants[0], writers[0], 1, DDS_SECS(2)); + ret = dds_write (writers[0], &sample); + CU_ASSERT_EQUAL_FATAL (ret, DDS_RETCODE_OK); + + while (true) + { + if ((ret = dds_take (readers[0], samples, info, 1, 1)) == 0) + { + reader_wait_for_data (g_sub_participants[0], readers[0], DDS_SECS(5)); + continue; + } + CU_ASSERT_EQUAL_FATAL (ret, 1); + break; + } + + test_fini (1, 1); + free_eps (readers, reader_topics); + free_eps (writers, writer_topics); + ddsrt_free (rd_sample.text); + ddsrt_free (sample.text); +} + +/* Test communication between 2 nodes for all combinations of RTPS, metadata (submsg) + and payload protection kinds using a single reader and writer */ +CU_Test(ddssec_secure_communication, protection_kinds, .timeout = 120) +{ + DDS_Security_ProtectionKind rtps_pk[] = { PK_N, PK_S, PK_E }; + DDS_Security_ProtectionKind metadata_pk[] = { PK_N, PK_S, PK_E }; + DDS_Security_BasicProtectionKind payload_pk[] = { BPK_N, BPK_S, BPK_E }; + for (size_t rtps = 0; rtps < sizeof (rtps_pk) / sizeof (rtps_pk[0]); rtps++) + { + for (size_t metadata = 0; metadata < sizeof (metadata_pk) / sizeof (metadata_pk[0]); metadata++) + { + for (size_t payload = 0; payload < sizeof (payload_pk) / sizeof (payload_pk[0]); payload++) + { + test_data_protection_kind (rtps_pk[rtps], metadata_pk[metadata], payload_pk[payload]); + } + } + } +} + +/* Test communication between 2 nodes for all combinations of discovery and + liveliness protection kinds using a single reader and writer */ +CU_Test(ddssec_secure_communication, discovery_liveliness_protection, .timeout = 60) +{ + DDS_Security_ProtectionKind discovery_pk[] = { PK_N, PK_S, PK_E }; + DDS_Security_ProtectionKind liveliness_pk[] = { PK_N, PK_S, PK_E }; + for (size_t disc = 0; disc < sizeof (discovery_pk) / sizeof (discovery_pk[0]); disc++) + { + for (size_t liveliness = 0; liveliness < sizeof (liveliness_pk) / sizeof (liveliness_pk[0]); liveliness++) + { + test_discovery_liveliness_protection (discovery_pk[disc], liveliness_pk[liveliness]); + } + } +} + +/* Test that a specific character sequence from the plain data does not appear in + encrypted payload, submessage or rtps message when protection kind is ENCRYPT*/ +CU_Test(ddssec_secure_communication, check_encrypted_secret, .timeout = 60) +{ + DDS_Security_ProtectionKind rtps_pk[] = { PK_N, PK_E, PK_EOA }; + DDS_Security_ProtectionKind metadata_pk[] = { PK_N, PK_E, PK_EOA }; + DDS_Security_BasicProtectionKind payload_pk[] = { BPK_N, BPK_E }; + for (size_t rtps = 0; rtps < sizeof (rtps_pk) / sizeof (rtps_pk[0]); rtps++) + { + for (size_t metadata = 0; metadata < sizeof (metadata_pk) / sizeof (metadata_pk[0]); metadata++) + { + for (size_t payload = 0; payload < sizeof (payload_pk) / sizeof (payload_pk[0]); payload++) + { + test_payload_secret (rtps_pk[rtps], metadata_pk[metadata], payload_pk[payload]); + } + } + } +} + +/* Test communication with specific combinations payload and submsg protection + kinds for 1-3 domains, 1-3 participants per domain and 1-3 readers per participant */ +CU_TheoryDataPoints(ddssec_secure_communication, multiple_readers) = { + CU_DataPoints(size_t, 1, 1, 1, 3), /* number of domains */ + CU_DataPoints(size_t, 1, 3, 1, 3), /* number of participants per domain */ + CU_DataPoints(size_t, 3, 1, 3, 3), /* number of readers per participant */ +}; +CU_Theory((size_t n_dom, size_t n_pp, size_t n_rd), ddssec_secure_communication, multiple_readers, .timeout = 90, .disabled = false) +{ + DDS_Security_ProtectionKind metadata_pk[] = { PK_N, PK_SOA, PK_EOA }; + DDS_Security_BasicProtectionKind payload_pk[] = { BPK_N, BPK_S, BPK_E }; + for (size_t metadata = 0; metadata < sizeof (metadata_pk) / sizeof (metadata_pk[0]); metadata++) + { + for (size_t payload = 0; payload < sizeof (payload_pk) / sizeof (payload_pk[0]); payload++) + { + test_multiple_readers (n_dom, n_pp, n_rd, metadata_pk[metadata], payload_pk[payload]); + } + } +} + +/* Test communication with specific combinations payload and submsg protection + kinds for 1-2 domains, 1-3 participants per domain, 1-3 readers per participant + and 1-3 writers per participant */ +CU_TheoryDataPoints(ddssec_secure_communication, multiple_readers_writers) = { + CU_DataPoints(size_t, 1, 1, 2), /* number of reader domains */ + CU_DataPoints(size_t, 1, 3, 3), /* number of readers per domain */ + CU_DataPoints(size_t, 1, 1, 2), /* number of writer domains */ + CU_DataPoints(size_t, 1, 3, 3), /* number of writers per domain */ +}; +CU_Theory((size_t n_rd_dom, size_t n_rd, size_t n_wr_dom, size_t n_wr), ddssec_secure_communication, multiple_readers_writers, .timeout = 60, .disabled = false) +{ + DDS_Security_ProtectionKind metadata_pk[] = { PK_SOA, PK_EOA }; + for (size_t metadata = 0; metadata < sizeof (metadata_pk) / sizeof (metadata_pk[0]); metadata++) + { + test_multiple_writers (n_rd_dom, n_rd, n_wr_dom, n_wr, metadata_pk[metadata]); + } +} diff --git a/src/security/core/tests/security_utils.c b/src/security/core/tests/security_utils.c new file mode 100644 index 0000000..ec4ab89 --- /dev/null +++ b/src/security/core/tests/security_utils.c @@ -0,0 +1,62 @@ +/* + * Copyright(c) 2006 to 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#include +#include +#include "CUnit/CUnit.h" +#include "CUnit/Test.h" +#include "dds/ddsrt/time.h" +#include "dds/security/core/dds_security_utils.h" + +CU_Test(ddssec_security_utils, parse_xml_date) +{ + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date(""), DDS_TIME_INVALID); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("abc"), DDS_TIME_INVALID); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01"), DDS_TIME_INVALID); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01D01:01:01Z"), DDS_TIME_INVALID); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2019-02-29T01:01:01Z"), DDS_TIME_INVALID); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2100-02-29T01:01:01Z"), DDS_TIME_INVALID); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("1969-01-01T01:01:01Z"), DDS_TIME_INVALID); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2010-01-01T23:59:60Z"), DDS_TIME_INVALID); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("1969-01-01T01:01:01+01"), DDS_TIME_INVALID); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("1969-01-01T01:01:01+0100"), DDS_TIME_INVALID); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("1969-01-01T01:01:01+0:00"), DDS_TIME_INVALID); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("1970-01-01T00:00:00+01:00"), DDS_TIME_INVALID); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01.0000000000001+01:00"), DDS_TIME_INVALID); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01.0.1+01:00"), DDS_TIME_INVALID); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01.+01:00"), DDS_TIME_INVALID); + + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("1970-01-01T00:00:00Z"), 0); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2000-02-29T00:00:00Z"), DDS_SECS(951782400)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01Z"), DDS_SECS(1577840461)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01+00:30"), DDS_SECS(1577840461 - 30 * 60)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01+01:00"), DDS_SECS(1577840461 - 60 * 60)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01+12:00"), DDS_SECS(1577840461 - 12 * 60 * 60)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01-01:00"), DDS_SECS(1577840461 + 60 * 60)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-12-31T23:59:59Z"), DDS_SECS(1609459199)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-02-29T01:01:01Z"), DDS_SECS(1582938061)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2038-01-19T03:14:07Z"), DDS_SECS(INT32_MAX)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2038-01-19T03:14:08Z"), DDS_SECS(INT64_C(INT32_MAX + 1))); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2100-01-01T00:00:00Z"), DDS_SECS(4102444800)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2120-01-01T00:00:00Z"), DDS_SECS(4733510400)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2200-01-01T00:00:00Z"), DDS_SECS(7258118400)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2220-01-01T00:00:00Z"), DDS_SECS(7889184000)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2262-04-11T23:47:16.854775807Z"), INT64_MAX); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2262-04-11T23:47:16.854775808Z"), DDS_TIME_INVALID); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2262-04-11T23:47:16.854775807+00:01"), INT64_MAX - DDS_SECS(60)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2262-04-11T23:47:16.854775807-00:01"), DDS_TIME_INVALID); + + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01.000000001+01:00"), INT64_C(1577836861000000001)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01.0000000004+01:00"), INT64_C(1577836861000000000)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01.0000000005+01:00"), INT64_C(1577836861000000001)); + CU_ASSERT_EQUAL(DDS_Security_parse_xml_date("2020-01-01T01:01:01.987654321+01:00"), INT64_C(1577836861987654321)); +} diff --git a/src/security/core/tests/timed_cb.c b/src/security/core/tests/timed_cb.c new file mode 100644 index 0000000..6b01a9e --- /dev/null +++ b/src/security/core/tests/timed_cb.c @@ -0,0 +1,374 @@ +/* + * Copyright(c) 2019 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#include +#include "CUnit/Test.h" + +#include "dds/security/core/dds_security_timed_cb.h" +#include "dds/ddsrt/misc.h" + +#define SEQ_SIZE (16) + +typedef struct +{ + struct dds_security_timed_dispatcher_t *d; + dds_security_timed_cb_kind kind; + void *listener; + void *arg; + dds_time_t time; +} test_sequence_data; + +static int g_sequence_idx = 0; +static test_sequence_data g_sequence_array[SEQ_SIZE]; + +static void simple_callback(struct dds_security_timed_dispatcher_t *d, dds_security_timed_cb_kind kind, void *listener, void *arg) +{ + DDSRT_UNUSED_ARG(d); + DDSRT_UNUSED_ARG(kind); + DDSRT_UNUSED_ARG(listener); + *((bool *)arg) = !(*((bool *)arg)); +} + +static int g_order_callback_idx = 0; +static void *g_order_callback[2] = {(void *)NULL, (void *)NULL}; +static void order_callback(struct dds_security_timed_dispatcher_t *d, dds_security_timed_cb_kind kind, void *listener, void *arg) +{ + DDSRT_UNUSED_ARG(d); + DDSRT_UNUSED_ARG(kind); + DDSRT_UNUSED_ARG(listener); + g_order_callback[g_order_callback_idx] = arg; + g_order_callback_idx++; +} + +static void test_callback(struct dds_security_timed_dispatcher_t *d, dds_security_timed_cb_kind kind, void *listener, void *arg) +{ + if (g_sequence_idx < SEQ_SIZE) + { + g_sequence_array[g_sequence_idx].d = d; + g_sequence_array[g_sequence_idx].arg = arg; + g_sequence_array[g_sequence_idx].kind = kind; + g_sequence_array[g_sequence_idx].listener = listener; + g_sequence_array[g_sequence_idx].time = dds_time(); + } + g_sequence_idx++; +} + +CU_Test(ddssec_timed_cb, simple_test) +{ + struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new(); + static bool test_var = false; + dds_time_t future = dds_time() + DDS_SECS(2); + struct dds_security_timed_dispatcher_t *d1 = dds_security_timed_dispatcher_new(tcb); + CU_ASSERT_PTR_NOT_NULL_FATAL(d1); + dds_security_timed_dispatcher_add(tcb, d1, simple_callback, future, (void *)&test_var); + dds_security_timed_dispatcher_enable(tcb, d1, (void *)NULL); + CU_ASSERT_FALSE_FATAL(test_var); + dds_sleepfor(DDS_MSECS(500)); + CU_ASSERT_FALSE_FATAL(test_var); + dds_sleepfor(DDS_SECS(2)); + CU_ASSERT_TRUE_FATAL(test_var); + dds_security_timed_dispatcher_free(tcb, d1); + dds_security_timed_cb_free(tcb); +} + +CU_Test(ddssec_timed_cb, simple_order) +{ + struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new(); + struct dds_security_timed_dispatcher_t *d1 = dds_security_timed_dispatcher_new(tcb); + CU_ASSERT_PTR_NOT_NULL_FATAL(d1); + dds_time_t future = dds_time() + DDS_MSECS(20), future2 = future; + dds_security_timed_dispatcher_add(tcb, d1, order_callback, future, (void *)1); + dds_security_timed_dispatcher_add(tcb, d1, order_callback, future2, (void *)2); + dds_security_timed_dispatcher_enable(tcb, d1, (void *)&g_order_callback); + dds_sleepfor(DDS_MSECS(10)); + dds_security_timed_dispatcher_free(tcb, d1); + CU_ASSERT_EQUAL_FATAL(g_order_callback[0], (void *)1); + CU_ASSERT_EQUAL_FATAL(g_order_callback[1], (void *)2); + dds_security_timed_cb_free(tcb); +} + +CU_Test(ddssec_timed_cb, test_enabled_and_disabled) +{ + struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new(); + static bool test_var = false; + dds_time_t future = dds_time() + DDS_SECS(2); + struct dds_security_timed_dispatcher_t *d1 = dds_security_timed_dispatcher_new(tcb); + CU_ASSERT_PTR_NOT_NULL_FATAL(d1); + dds_security_timed_dispatcher_add(tcb, d1, simple_callback, future, (void *)&test_var); + dds_security_timed_dispatcher_enable(tcb, d1, (void *)NULL); + CU_ASSERT_FALSE(test_var); + dds_security_timed_dispatcher_disable(tcb, d1); + dds_sleepfor(DDS_MSECS(500)); + CU_ASSERT_FALSE(test_var); + dds_sleepfor(DDS_SECS(2)); + CU_ASSERT_FALSE(test_var); + dds_security_timed_dispatcher_free(tcb, d1); + dds_security_timed_cb_free(tcb); +} + +CU_Test(ddssec_timed_cb, simple_test_with_future) +{ + struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new(); + static bool test_var = false; + dds_time_t now = dds_time(), future = now + DDS_SECS(2), far_future = now + DDS_SECS(10); + struct dds_security_timed_dispatcher_t *d1 = dds_security_timed_dispatcher_new(tcb); + CU_ASSERT_PTR_NOT_NULL_FATAL(d1); + dds_security_timed_dispatcher_enable(tcb, d1, (void *)NULL); + dds_security_timed_dispatcher_add(tcb, d1, simple_callback, future, (void *)&test_var); + dds_security_timed_dispatcher_add(tcb, d1, simple_callback, far_future, (void *)&test_var); + CU_ASSERT_FALSE_FATAL(test_var); + dds_sleepfor(DDS_MSECS(500)); + CU_ASSERT_FALSE_FATAL(test_var); + dds_sleepfor(DDS_SECS(2)); + CU_ASSERT_TRUE_FATAL(test_var); + dds_security_timed_dispatcher_free(tcb, d1); + dds_security_timed_cb_free(tcb); +} + +CU_Test(ddssec_timed_cb, test_multiple_dispatchers) +{ + struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new(); + static bool test_var = false; + dds_time_t now = dds_time(), future = now + DDS_SECS(2), far_future = now + DDS_SECS(10); + struct dds_security_timed_dispatcher_t *d1 = dds_security_timed_dispatcher_new(tcb); + struct dds_security_timed_dispatcher_t *d2 = dds_security_timed_dispatcher_new(tcb); + CU_ASSERT_PTR_NOT_NULL_FATAL(d1); + dds_security_timed_dispatcher_enable(tcb, d1, (void *)NULL); + dds_security_timed_dispatcher_enable(tcb, d2, (void *)NULL); + dds_security_timed_dispatcher_free(tcb, d2); + dds_security_timed_dispatcher_add(tcb, d1, simple_callback, future, (void *)&test_var); + dds_security_timed_dispatcher_add(tcb, d1, simple_callback, far_future, (void *)&test_var); + CU_ASSERT_FALSE_FATAL(test_var); + dds_sleepfor(DDS_MSECS(500)); + CU_ASSERT_FALSE_FATAL(test_var); + dds_sleepfor(DDS_SECS(2)); + CU_ASSERT_TRUE_FATAL(test_var); + dds_security_timed_dispatcher_free(tcb, d1); + dds_security_timed_cb_free(tcb); +} + +CU_Test(ddssec_timed_cb, test_not_enabled_multiple_dispatchers) +{ + struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new(); + struct dds_security_timed_dispatcher_t *d1 = dds_security_timed_dispatcher_new(tcb); + struct dds_security_timed_dispatcher_t *d2 = dds_security_timed_dispatcher_new(tcb); + CU_ASSERT_PTR_NOT_NULL_FATAL(d1); + CU_ASSERT_PTR_NOT_NULL_FATAL(d2); + dds_security_timed_dispatcher_free(tcb, d2); + dds_security_timed_dispatcher_free(tcb, d1); + dds_security_timed_cb_free(tcb); +} + +CU_Test(ddssec_timed_cb, test_create_dispatcher) +{ + struct dds_security_timed_cb_data *tcb = dds_security_timed_cb_new(); + struct dds_security_timed_dispatcher_t *d1 = NULL; + struct dds_security_timed_dispatcher_t *d2 = NULL; + struct dds_security_timed_dispatcher_t *d3 = NULL; + struct dds_security_timed_dispatcher_t *d4 = NULL; + struct dds_security_timed_dispatcher_t *d5 = NULL; + + dds_time_t now = dds_time(); + dds_time_t past = now - DDS_SECS(1); + dds_time_t present = now + DDS_SECS(1); + dds_time_t future = present + DDS_SECS(1); + dds_time_t future2 = future + DDS_SECS(10); + + d1 = dds_security_timed_dispatcher_new(tcb); + d2 = dds_security_timed_dispatcher_new(tcb); + CU_ASSERT_PTR_NOT_NULL_FATAL(d1); + CU_ASSERT_PTR_NOT_NULL_FATAL(d2); + + /* The last argument is a sequence number in which + the callbacks are expected to be called. */ + dds_security_timed_dispatcher_add(tcb, d1, test_callback, present, (void *)1); + dds_security_timed_dispatcher_add(tcb, d2, test_callback, past, (void *)0); + dds_security_timed_dispatcher_add(tcb, d2, test_callback, present, (void *)2); + dds_security_timed_dispatcher_add(tcb, d1, test_callback, future, (void *)7); + + d3 = dds_security_timed_dispatcher_new(tcb); + d4 = dds_security_timed_dispatcher_new(tcb); + d5 = dds_security_timed_dispatcher_new(tcb); + + CU_ASSERT_PTR_NOT_NULL_FATAL(d3); + CU_ASSERT_PTR_NOT_NULL_FATAL(d4); + CU_ASSERT_PTR_NOT_NULL_FATAL(d5); + + /* The sleeps are added to get the timing between 'present' and 'past' callbacks right. */ + dds_sleepfor(DDS_MSECS(600)); + dds_security_timed_dispatcher_enable(tcb, d1, (void *)NULL); + dds_security_timed_dispatcher_enable(tcb, d2, (void *)d2); + dds_security_timed_dispatcher_enable(tcb, d3, (void *)NULL); + /* Specifically not enabling d4 and d5. */ + dds_sleepfor(DDS_MSECS(600)); + + /* The last argument is a sequence number in which the callbacks are expected to be called. */ + dds_security_timed_dispatcher_add(tcb, d4, test_callback, past, (void *)99); + dds_security_timed_dispatcher_add(tcb, d2, test_callback, future, (void *)8); + dds_security_timed_dispatcher_add(tcb, d3, test_callback, future2, (void *)9); + dds_security_timed_dispatcher_add(tcb, d1, test_callback, past, (void *)3); + dds_security_timed_dispatcher_add(tcb, d1, test_callback, future2, (void *)10); + dds_security_timed_dispatcher_add(tcb, d1, test_callback, present, (void *)4); + dds_security_timed_dispatcher_add(tcb, d2, test_callback, present, (void *)5); + dds_security_timed_dispatcher_add(tcb, d1, test_callback, future, (void *)6); + dds_security_timed_dispatcher_add(tcb, d3, test_callback, future2, (void *)11); + + int idx; + int n = 200; + + /* Wait for the callbacks to have been triggered. Ignore the ones in the far future. */ + while (g_sequence_idx < 8 && n-- > 0) + dds_sleepfor(DDS_MSECS(10)); + + /* Print and check sequence of triggered callbacks. */ + for (idx = 0; idx < g_sequence_idx && idx < SEQ_SIZE; idx++) + { + int seq = (int)(long long)(g_sequence_array[idx].arg); + struct dds_security_timed_dispatcher_t *expected_d; + void *expected_l; + + if (seq == 1 || seq == 6 || seq == 3 || seq == 10 || seq == 4 || seq == 7) + { + expected_d = d1; + expected_l = NULL; + } + else if (seq == 0 || seq == 2 || seq == 8 || seq == 5) + { + expected_d = d2; + expected_l = d2; + } + else if (seq == 9) + { + expected_d = d3; + expected_l = NULL; + } + else if (seq == 99) + { + expected_d = d4; + expected_l = NULL; + CU_FAIL_FATAL("Unexpected callback on a disabled dispatcher"); + } + else + { + expected_d = NULL; + expected_l = NULL; + CU_FAIL_FATAL(sprintf("Unknown sequence idx received %d", seq)); + } + + if (seq != idx) + { + /* 6 and 7 order may be mixed since the order is not defined for same time stamp */ + if (!((seq == 6 && idx == 7) || (seq == 7 && idx == 6))) + { + CU_FAIL_FATAL(sprintf("Unexpected sequence ordering %d vs %d\n", seq, idx)); + } + } + if (seq > 8) + { + CU_FAIL_FATAL(sprintf("Unexpected sequence idx %d of the far future", seq)); + } + if (idx > 8) + { + CU_FAIL_FATAL(sprintf("Too many callbacks %d", idx)); + } + + /* Callback contents checks. */ + if (expected_d != NULL) + { + if (g_sequence_array[idx].d != expected_d) + { + CU_FAIL_FATAL(sprintf("Unexpected dispatcher %p vs %p\n", g_sequence_array[idx].d, expected_d)); + } + if (g_sequence_array[idx].listener != expected_l) + { + CU_FAIL_FATAL(sprintf("Unexpected listener %p vs %p", g_sequence_array[idx].listener, expected_l)); + } + } + + /* Callback kind check. */ + if (g_sequence_array[idx].kind != DDS_SECURITY_TIMED_CB_KIND_TIMEOUT) + { + CU_FAIL_FATAL(sprintf("Unexpected kind %d vs %d", (int)g_sequence_array[idx].kind, (int)DDS_SECURITY_TIMED_CB_KIND_TIMEOUT)); + } + } + if (g_sequence_idx < 8) + { + CU_FAIL_FATAL(sprintf("Received %d callbacks, while 9 are expected", g_sequence_idx + 1)); + } + + /* Reset callback index to catch the deletion ones. */ + g_sequence_idx = 0; + + /* Check if deleting succeeds with dispatchers in different states */ + if (d1) + dds_security_timed_dispatcher_free(tcb, d1); + if (d2) + dds_security_timed_dispatcher_free(tcb, d2); + if (d3) + dds_security_timed_dispatcher_free(tcb, d3); + if (d4) + dds_security_timed_dispatcher_free(tcb, d4); + if (d5) + dds_security_timed_dispatcher_free(tcb, d5); + + /* Wait for the callbacks to have been triggered. Ignore the ones in the far future. */ + n = 200; + while (g_sequence_idx < 4 && n-- > 0) + dds_sleepfor(DDS_MSECS(10)); + + /* Print and check sequence of triggered callbacks. */ + for (idx = 0; (idx < g_sequence_idx) && (idx < SEQ_SIZE); idx++) + { + int seq = (int)(long long)(g_sequence_array[idx].arg); + struct dds_security_timed_dispatcher_t *expected_d; + if (seq == 99) + expected_d = d4; + else if (seq == 9 || seq == 11) + expected_d = d3; + else if (seq == 10) + expected_d = d1; + else + { + expected_d = NULL; + CU_FAIL_FATAL(sprintf("Unexpected sequence idx received %d", seq)); + } + if (idx > 4) + { + CU_FAIL_FATAL(sprintf("Too many callbacks %d", idx)); + } + + /* Callback contents checks. */ + if (expected_d != NULL) + { + if (g_sequence_array[idx].d != expected_d) + { + CU_FAIL_FATAL(sprintf("Unexpected dispatcher %p vs %p", g_sequence_array[idx].d, expected_d)); + } + if (g_sequence_array[idx].listener != NULL) + { + CU_FAIL_FATAL(sprintf("Unexpected listener %p vs NULL", g_sequence_array[idx].listener)); + } + } + + /* Callback kind check. */ + if (g_sequence_array[idx].kind != DDS_SECURITY_TIMED_CB_KIND_DELETE) + { + CU_FAIL_FATAL(sprintf("Unexpected kind %d vs %d", (int)g_sequence_array[idx].kind, (int)DDS_SECURITY_TIMED_CB_KIND_TIMEOUT)); + } + } + if (g_sequence_idx < 4) + { + CU_FAIL_FATAL(sprintf("Received %d callbacks, while 3 are expected", g_sequence_idx + 1)); + } + + dds_security_timed_cb_free(tcb); +} diff --git a/src/security/openssl/CMakeLists.txt b/src/security/openssl/CMakeLists.txt new file mode 100644 index 0000000..ebcbfc9 --- /dev/null +++ b/src/security/openssl/CMakeLists.txt @@ -0,0 +1,21 @@ +# +# Copyright(c) 2020 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 +# + +add_library(security_openssl INTERFACE) + +target_sources(security_openssl INTERFACE + "${CMAKE_CURRENT_SOURCE_DIR}/src/openssl_support.c") + +target_include_directories( + security_openssl INTERFACE + "$" +) diff --git a/src/security/openssl/include/dds/security/openssl_support.h b/src/security/openssl/include/dds/security/openssl_support.h new file mode 100644 index 0000000..a6cf7d8 --- /dev/null +++ b/src/security/openssl/include/dds/security/openssl_support.h @@ -0,0 +1,80 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ + +#ifndef DDS_OPENSSL_SUPPORT_H +#define DDS_OPENSSL_SUPPORT_H + +#include "dds/security/dds_security_api_types.h" + +/* There's OpenSSL 1.1.x and there's OpenSSL 1.0.2 and the difference is like + night and day: 1.1.0 deprecated all the initialization and cleanup routines + and so any library can link with OpenSSL and use it safely without breaking + the application code or some other library in the same process. + + OpenSSL 1.0.2h deprecated the cleanup functions such as EVP_cleanup because + calling the initialisation functions multiple times was survivable, but an + premature invocation of the cleanup functions deadly. It still has the per- + thread error state that one ought to clean up, but that firstly requires + keeping track of which threads make OpenSSL calls, and secondly we do + perform OpenSSL calls on the applications main-thread and so cleaning up + might interfere with the application code. + + Compatibility with 1.0.2 exists merely as a courtesy to those who insist on + using it with that problematic piece of code. We only initialise it, and we + don't clean up thread state. If Cyclone DDS is the only part of the process + that uses OpenSSL, it should be ok (just some some minor leaks at the end), + if the application code or another library also uses it, it'll probably be + fine too. */ + +#ifdef _WIN32 +/* WinSock2 must be included before openssl 1.0.2 headers otherwise winsock will be used */ +#include +#endif + +#include +#include +#include +#include +#include + +#if OPENSSL_VERSION_NUMBER >= 0x1000200fL +#define AUTH_INCLUDE_EC +#include +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +#define AUTH_INCLUDE_DH_ACCESSORS +#endif +#else +#error "OpenSSL version is not supported" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void dds_openssl_init (void); + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +/* 1.1.0 has it as a supported API. 1.0.2 has it in practice and since that has been + obsolete for ages, chances are that we can safely use it */ +struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result); +#endif + +void DDS_Security_Exception_set_with_openssl_error (DDS_Security_SecurityException *ex, const char *context, int code, int minor_code, const char *error_area); + +#endif diff --git a/src/security/openssl/src/openssl_support.c b/src/security/openssl/src/openssl_support.c new file mode 100644 index 0000000..a212439 --- /dev/null +++ b/src/security/openssl/src/openssl_support.c @@ -0,0 +1,127 @@ +/* + * Copyright(c) 2020 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/sync.h" +#include "dds/ddsrt/misc.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/threads.h" +#include "dds/ddsrt/atomics.h" +#include "dds/security/core/dds_security_utils.h" +#include "dds/security/openssl_support.h" + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static unsigned long ssl_id (void) +{ + return (unsigned long) ddsrt_gettid (); +} + +typedef struct CRYPTO_dynlock_value { + ddsrt_mutex_t m_mutex; +} CRYPTO_dynlock_value; + +CRYPTO_dynlock_value *dds_openssl102_ssl_locks = NULL; + +static void ssl_dynlock_lock (int mode, CRYPTO_dynlock_value *lock, const char *file, int line) +{ + (void) file; + (void) line; + if (mode & CRYPTO_LOCK) + ddsrt_mutex_lock (&lock->m_mutex); + else + ddsrt_mutex_unlock (&lock->m_mutex); +} + +static void ssl_lock (int mode, int n, const char *file, int line) +{ + ssl_dynlock_lock (mode, &dds_openssl102_ssl_locks[n], file, line); +} + +static CRYPTO_dynlock_value *ssl_dynlock_create (const char *file, int line) +{ + (void) file; + (void) line; + CRYPTO_dynlock_value *val = ddsrt_malloc (sizeof (*val)); + ddsrt_mutex_init (&val->m_mutex); + return val; +} + +static void ssl_dynlock_destroy (CRYPTO_dynlock_value *lock, const char *file, int line) +{ + (void) file; + (void) line; + ddsrt_mutex_destroy (&lock->m_mutex); + ddsrt_free (lock); +} + +void dds_openssl_init (void) +{ + // This is terribly fragile and broken-by-design, but with OpenSSL sometimes + // linked dynamically and sometimes linked statically, with Windows and Unix + // in the mix, this appears to be the compromise that makes it work reliably + // enough ... + if (CRYPTO_get_id_callback () == 0) + { + CRYPTO_set_id_callback (ssl_id); + CRYPTO_set_locking_callback (ssl_lock); + CRYPTO_set_dynlock_create_callback (ssl_dynlock_create); + CRYPTO_set_dynlock_lock_callback (ssl_dynlock_lock); + CRYPTO_set_dynlock_destroy_callback (ssl_dynlock_destroy); + + if (dds_openssl102_ssl_locks == NULL) + { + const int locks = CRYPTO_num_locks (); + assert (locks >= 0); + dds_openssl102_ssl_locks = ddsrt_malloc (sizeof (CRYPTO_dynlock_value) * (size_t) locks); + for (int i = 0; i < locks; i++) + ddsrt_mutex_init (&dds_openssl102_ssl_locks[i].m_mutex); + } + + OpenSSL_add_all_algorithms (); + OpenSSL_add_all_ciphers (); + OpenSSL_add_all_digests (); + ERR_load_BIO_strings (); + ERR_load_crypto_strings (); + } +} +#else +void dds_openssl_init (void) +{ + // nothing needed for OpenSSL 1.1.0 and later +} +#endif + +void DDS_Security_Exception_set_with_openssl_error (DDS_Security_SecurityException *ex, const char *context, int code, int minor_code, const char *error_area) +{ + BIO *bio; + assert (context); + assert (error_area); + assert (ex); + DDSRT_UNUSED_ARG (context); + + if ((bio = BIO_new (BIO_s_mem ()))) { + ERR_print_errors (bio); + char *buf = NULL; + size_t len = (size_t) BIO_get_mem_data (bio, &buf); + size_t exception_msg_len = len + strlen (error_area) + 1; + char *str = ddsrt_malloc (exception_msg_len); + ddsrt_strlcpy (str, error_area, exception_msg_len); + memcpy (str + strlen (error_area), buf, len); + str[exception_msg_len - 1] = '\0'; + ex->message = str; + ex->code = code; + ex->minor_code = minor_code; + BIO_free (bio); + } else { + DDS_Security_Exception_set (ex, context, code, minor_code, "BIO_new failed"); + } +} diff --git a/src/tools/pubsub/common.h b/src/tools/pubsub/common.h index 036e7b7..8854ec5 100644 --- a/src/tools/pubsub/common.h +++ b/src/tools/pubsub/common.h @@ -42,12 +42,13 @@ #define DDS_READERLIFESPAN_QOS_POLICY_NAME "ReaderLifespan" #define DDS_SHARE_QOS_POLICY_NAME "Share" #define DDS_SCHEDULING_QOS_POLICY_NAME "Scheduling" +#define DDS_PROPERTY_QOS_POLICY_NAME "Property" -#define DDS_SUBSCRIPTIONKEY_QOS_POLICY_ID 23 -#define DDS_VIEWKEY_QOS_POLICY_ID 24 -#define DDS_READERLIFESPAN_QOS_POLICY_ID 25 -#define DDS_SHARE_QOS_POLICY_ID 26 -#define DDS_SCHEDULING_QOS_POLICY_ID 27 +#define DDS_SUBSCRIPTIONKEY_QOS_POLICY_ID 24 +#define DDS_VIEWKEY_QOS_POLICY_ID 25 +#define DDS_READERLIFESPAN_QOS_POLICY_ID 26 +#define DDS_SHARE_QOS_POLICY_ID 27 +#define DDS_SCHEDULING_QOS_POLICY_ID 28 extern dds_entity_t dp; extern const dds_topic_descriptor_t *ts_KeyedSeq; diff --git a/src/tools/pubsub/pubsub.c b/src/tools/pubsub/pubsub.c index b83e748..3d8c581 100644 --- a/src/tools/pubsub/pubsub.c +++ b/src/tools/pubsub/pubsub.c @@ -894,6 +894,7 @@ static const char *policystr(uint32_t id) { case DDS_READERLIFESPAN_QOS_POLICY_ID: return DDS_READERLIFESPAN_QOS_POLICY_NAME; case DDS_SHARE_QOS_POLICY_ID: return DDS_SHARE_QOS_POLICY_NAME; case DDS_SCHEDULING_QOS_POLICY_ID: return DDS_SCHEDULING_QOS_POLICY_NAME; + case DDS_PROPERTY_QOS_POLICY_ID: return DDS_PROPERTY_QOS_POLICY_NAME; default: return "?"; } }