9. Building and Running Security Plugins-Based Applications¶
To use the Security Plugins with your DDS applications:
Decide whether to load the Security Plugins statically or dynamically. (See Linking Applications with the Security Plugins.)
Configure the DomainParticipants based on that decision. This includes specifying how to load the Security Plugins, by setting the security-related participant properties listed in Table 9.1. The properties you have to configure depend on whether you link your libraries statically or dynamically. You also need to configure the security artifacts that your DomainParticipants need to communicate securely (as specified in Using Connext DDS Secure).
Link your DDS application against the Security Plugins libraries and the OpenSSL libraries. These libraries will be different for each target architecture.
Security Plugins libraries are in the
rti_security_plugins-<version>-target-<target architecture>.rtipkg
bundle;There are two types of OpenSSL bundles that you need to install, a host and a target:
openssl-<openssl version>-<connext version>-host-<host platform>.rtipkg
openssl-<openssl version>-<connext version>-target-<target architecture>.rtipkg
See Download Instructions in the RTI Security Plugins Installation Guide. Refer to Libraries Required for Using the RTI Security Plugins to select the appropriate files for your platform and your chosen library format.
Note
You must set the security-related participant properties before you create a DomainParticipant (see Table 9.1). You cannot create a DomainParticipant without security and then call DomainParticipant::set_qos()
with security properties, even if the DomainParticipant has not yet been enabled.
Note
You can have secure and unsecure DomainParticipants in the same DDS application. However, all your Secure DomainParticipants will load the same OpenSSL library with the same configuration (including the same OpenSSL Engines). If you manually load OpenSSL before creating any participant, your Secure DomainParticipants will reuse that OpenSSL library and its configuration.
9.1. Linking Applications with the Security Plugins¶
Your application’s start sequence will be different depending on whether you use static or dynamic linking. This choice will also have an impact on how you need to configure your application.
Table 9.1 defines the properties that you need to set in your DomainParticipant to load the Security Plugins. Depending on whether you link your libraries statically or dynamically, you need to set different properties to load the Security Plugins. The following sections will guide you through the linking process.
![Differences in the Startup Sequence of Connext DDS Secure Applications Using Static Linking and Dynamic Linking](../_images/linking-static-dynamic.png)
Figure 9.1 Differences in the Startup Sequence of Connext DDS Secure Applications Using Static Linking and Dynamic Linking¶
Important
Do not mix dynamic and static libraries. See Mixing Libraries Not Supported for further information.
9.1.1. Dynamic Linking¶
Note
For a step-by-step example on dynamic linking, please see the RTI Security Plugins Getting Started Guide.
When you use dynamic linking, your application loads the Connext DDS Core libraries at load time and all the plugins (Transport, Security, Discovery, etc.) at run time. On Linux systems, for instance, your applications need to link against libnddsc.so
and libnddscore.so
. You can link your applications to these libraries with GCC using the following command:
$ gcc -o myApp myApp.o -L$NDDSHOME/lib/$ARCH -lnddsc -lnddscore
Note that in the above command, Security Plugins is not included in the list of required
libraries, because it is dynamically loaded at run time from the
DomainParticipantQos com.rti.serv.secure.library
(see
Table 9.1). Using dynamic linking allows you to
control the Security Plugins from the DomainParticipantQos. For example, if you are
configuring the DomainParticipantQos using XML, the required snippet will look
similar to:
<domain_participant_qos>
<property>
<value>
<element>
<name>com.rti.serv.secure.library</name>
<value>nddssecurity</value>
</element>
</value>
</property>
</domain_participant_qos>
This example QoS will make your DomainParticipant load the nddssecurity library
(libnddssecurity.so
on Linux systems), which in turn loads the OpenSSL
libraries. Note that the Security Plugins are loaded on a per participant basis. Therefore,
you can have secure and unsecure DomainParticipants in the same application. Similarly, each
of your DomainParticipants can load a different set of plugins.
Dynamic loading is particularly useful if, for example, you use your own security plugins library, because the library can be easily defined at run time through the QoS.
This is the initialization sequence of a DDS application using the Security Plugins with dynamic linking:
When your application starts, the dynamic loader automatically loads the Connext DDS libraries (
libnddsc.so
,libnddscore.so
) from your dynamic library search path (LD_LIBRARY_PATH
on Linux systems).When the DomainParticipant is created and the QoS is set, the Connext DDS Core libraries dynamically load the security library (
libnddssecurity.so
) at run time. Because the Security Plugins library depends onlibnddscore.so
, the dynamic loader knows that the library has already been loaded, and it automatically resolves the undefined symbols to use the currently loaded library.Since the Security Plugins library depends on OpenSSL shared objects, these are automatically loaded by the dynamic loader. Therefore, OpenSSL libraries have to be accessible from your dynamic library search path (
LD_LIBRARY_PATH
on Linux systems).On Linux systems, if you encounter a segmentation fault in
libcrypto.so
, you may be dynamically loading thelibcrypto.so
from the operating system (possibly in addition to loading thelibcrypto.so
from RTI). In that case, setLD_PRELOAD
to the RTIlibcrypto.so
. Example:export LD_PRELOAD=$NDDSHOME/resource/app/lib/x64Linux2.6gcc4.4.5/libcrypto.so.1.1 $NDDSHOME/bin/rtiadminconsole
Hint
When linking dynamically, the %PATH%
or $LD_LIBRARY_PATH
environment variable must include RTI and OpenSSL DLLs or libraries.
9.1.2. Static Linking¶
If you choose to statically link the RTI libraries, the mechanism for dynamically selecting and loading the Security Plugins is no longer available. Compared to dynamic linking, you need to pay attention to two things with static linking.
First, you need to include the Security Plugins library and the OpenSSL dependency libraries in the list of libraries needed during linking:
$ gcc -o myApp myApp.o -L$NDDSHOME/lib/$ARCH -lnddssecurityz $RTI_OPENSSLHOME/$ARCH/release/lib/libcrypto.a
Note
For an example of the full linking command see <path to examples>/connext_dds/c/hello_security
.
Second, you need to manually tell Connext DDS the pointer to the function of the entry point of Security Plugins before you create the DomainParticipant. Setting this pointer requires setting the com.rti.serv.secure.create_function_ptr
property (see Table 9.1). Here is an example on how to set this pointer in code:
#include "security/security_default.h"
...
extern "C" int publisher_main(int domainId, int sample_count)
{
DDS_DomainParticipantFactory *factory = NULL;
struct DDS_DomainParticipantQos participantQos =
DDS_DomainParticipantQos_INITIALIZER;
DDS_DomainParticipant *participant = NULL;
factory = DDS_DomainParticipantFactory_get_instance();
if (factory == NULL) {
/* error */
}
if (DDS_DomainParticipantFactory_get_default_participant_qos(
factory, &participantQos) != DDS_RETCODE_OK) {
/* error */
}
/* This property indicates that the DomainParticipant has security turned
* on. The property name MUST be "com.rti.serv.load_plugin". The value can
* be anything.*/
if (DDS_PropertyQosPolicyHelper_add_property(
&participantQos.property,
"com.rti.serv.load_plugin",
"com.rti.serv.secure",
DDS_BOOLEAN_FALSE)
!= DDS_RETCODE_OK) {
/* error */
}
/* The property name "com.rti.serv.secure.create_function_ptr" indicates the
* entry point for the Security Plugins library. The value MUST be the
* value of the function pointer of RTI_Security_PluginSuite_create */
if (DDS_PropertyQosPolicyHelper_add_pointer_property(
&participantQos.property,
"com.rti.serv.secure.create_function_ptr",
RTI_Security_PluginSuite_create)
!= DDS_RETCODE_OK) {
/* error */
}
/* create DomainParticipant with participantQos */
participant=
DDS_DomainParticipantFactory_create_participant(
factory, domainId, &participantQos,
NULL /* listener */,
DDS_STATUS_MASK_NONE);
if (participant == NULL) {
/* error */
}
...
#include "security/security_default.h"
...
extern "C" int publisher_main(int domainId, int sample_count)
{
DDSDomainParticipant *participant = NULL;
DDS_DomainParticipantQos participant_qos;
DDS_ReturnCode_t retcode;
/* Get default QoS */
retcode = DDSTheParticipantFactory->get_default_participant_qos(
participant_qos);
if (retcode != DDS_RETCODE_OK) {
/*Error*/
}
/* This property indicates that the DomainParticipant has security turned
* on. The property name MUST be "com.rti.serv.load_plugin". The value can
* be anything.*/
retcode = DDSPropertyQosPolicyHelper::add_property(
participant_qos.property,
"com.rti.serv.load_plugin",
"com.rti.serv.secure",
DDS_BOOLEAN_FALSE);
if (retcode != DDS_RETCODE_OK) {
/*Error*/
}
/* The property name "com.rti.serv.secure.create_function_ptr" indicates the
* entry point for the Security Plugins library. The value MUST be the
* value of the function pointer of RTI_Security_PluginSuite_create */
retcode = DDSPropertyQosPolicyHelper::add_pointer_property(
participant_qos.property,
"com.rti.serv.secure.create_function_ptr",
(void *) RTI_Security_PluginSuite_create);
if (retcode!= DDS_RETCODE_OK) {
/* Error */
}
/* Create DomainParticipant with participant_qos */
participant = DDSTheParticipantFactory->create_participant(
domainId, participant_qos,
NULL /* listener */,
DDS_STATUS_MASK_NONE);
if (participant == NULL) {
/* Error */
}
...
#include "security/security_default.h"
#include "rti/rti.hpp"
...
using rti::core::policy::Property;
void publisher_main(int domain_id, int sample_count)
{
// Get property policy from default DomainParticipantQos
auto participant_qos =
dds::core::QosProvider::Default().participant_qos();
auto property_policy = participant_qos.policy<Property>();
// This property turns the Security Plugins on
property_policy.set(Property::Entry(
"com.rti.serv.load_plugin",
"com.rti.serv.secure"));
// This property specifies the entry point (function pointer) for the
// Security Plugins library.
std::ostringstream security_function_to_str;
security_function_to_str <<
reinterpret_cast<void*>(RTI_Security_PluginSuite_create);
property_policy.set(Property::Entry(
"com.rti.serv.secure.create_function_ptr",
security_function_to_str.str()));
participant_qos << property_policy;
// Create a DomainParticipant with Qos
dds::domain::DomainParticipant participant(0, participant_qos);
...
Enabling the Security Plugins in code requires recompiling your application each time you want to enable and disable them. As an alternative, you can set the function pointer value for com.rti.serv.secure.create_function_ptr
property in an environment variable that is set programmatically. Hence you can specify the function pointer in an XML file, which allows you to enable and disable the Security Plugins without recompiling.
If you choose to use this method, you have to specify the environment variable from which the pointer will be loaded, as follows:
<domain_participant_qos>
<property>
<value>
<element>
<name>com.rti.serv.load_plugin</name>
<value>com.rti.serv.secure</value>
</element>
<element>
<name>com.rti.serv.secure.create_function_ptr</name>
<value>$(RTISECURITYFUNCPTR)</value>
</element>
</value>
</property>
</domain_participant_qos>
Then, in the DDS application that links in the Security Plugins, get the function pointer of RTI_Security_PluginSuite_create
and write it to the same environment variable you named in the XML file (RTISECURITYFUNCPTR
in this example). Be aware that your application must set the environment variable before it creates the DomainParticipant that loads the QoS Profile using that variable, as shown in the following snippet:
#include "security/security_default.h"
...
char putenvBuffer[35]; /* 35 = strlen(“RTISECURITYFUNCPTR”) + 2*8 + 1 */
int putenvReturn;
putenvBuffer[0] = '\0';
sprintf(putenvBuffer, "RTISECURITYFUNCPTR=%p",
RTI_Security_PluginSuite_create);
putenvReturn = putenv(putenvBuffer);
if (putenvReturn) {
printf(
"Error: couldn't set env variable for RTISECURITYFUNCPTR. "
"error code: %d\n", putenvReturn);
}
...
/* create DomainParticipant */
...
Finally, you have to create a DomainParticipant by using the XML profile where you load the function pointer.
Caution
putenv()
will not export variables from your process to the calling process (e.g., to the shell). Instead, the environment variables set in your process will only apply to your process and child processes of it. Therefore, you need to use this function in the same process that links in the Security Plugins (or a child process).
This is the initialization sequence of a DDS application using the Security Plugins with static linking:
Since your application includes the binary code of the Connext DDS libraries, when it starts, these libraries are copied in the memory space of your application.
When the DomainParticipant is created and the QoS is set, the Connext DDS Core libraries initialize the Security Plugins, which are also in the application’s memory space along with the OpenSSL library.
Important
If you statically link Security Plugins, the QoS property com.rti.serv.secure.library
will be silently ignored, if defined. With static linking, Security Plugins is only set at compile time; there is no runtime selection.
9.2. Mixing Libraries Not Supported¶
You must choose either static or dynamic linking. Mixing static and dynamic RTI libraries —for example, using static Connext DDS Core libraries and dynamic Security Plugins libraries— is not supported.
The examples in this section are for Linux systems, but except for small differences in names, the same concepts apply to Windows and macOS systems as well.
Suppose you have a Connext DDS-based application, myApp
, and you want to use Security Plugins to protect the communication. The library dependency looks something like Figure 9.2.
![Library Dependency](../_images/library-dependency.png)
Figure 9.2 Library Dependency¶
Figure 9.2 is a simple and common situation, but make sure that the Connext DDS Core libraries that your application uses are the same kind of libraries that Security Plugins uses. For example, if myApp
links statically with nddsc
, but you load nddssecurity
dynamically, there will be a mismatch between the libraries, potentially creating a dangerous situation. In particular, problems may become visible when you enable the Security Plugins logging distribution (see Configuring the Logging Distribution).
You can easily end up in a mixed linking scenario without realizing it. For example, suppose you design your statically linked application without security in mind, then add security from the QoS. This scenario is not valid because when the runtime dynamic loader loads the Security Plugins library, it also loads a second copy of the Connext DDS Core libraries in memory as shown by Figure 9.3.
![Mixed Library Linking (Not Supported)](../_images/mixed-libraries.png)
Figure 9.3 Mixed Library Linking (Not Supported)¶
If you mix static and dynamic libraries, your application might still work, but this configuration is not supported and you might end up with unexpected behavior at run time. To avoid undesired situations, you must use static or dynamic linking, but not both.
Important
Even if a combination of static and dynamic libraries seems to work, RTI cannot guarantee there won’t be issues when running the Connext DDS application.
9.3. Properties for Enabling Security¶
Table 9.1 lists the properties that you can use for enabling security. These properties are configured through the DomainParticipant’s PROPERTY QosPolicy (see QoS Properties).
Property Name (prefix with |
Property Value Description |
---|---|
|
Required The prefix name of the security plugin suite that will be loaded by Connext DDS. For example:
String. Default: |
|
Only required if linking dynamically Must be set to the dynamic library that implements the security plugin suite. If using Connext DDS’s provided security plugin suite, you must set this value to This library and the dependent OpenSSL libraries must be in your library
search path (pointed to by the environment variable String. Default: |
|
Only required if linking dynamically Must be set to the security plugin suite creation function that is implemented by the library. If using Connext DDS’s provided security plugin suite, you must set this value to String. Default: |
|
Only required if linking statically Must be set to the security plugin suite creation function implemented by the library. If using Connext DDS’s provided security plugin suite, you must set this value to the stringified pointer value of
String. Default: |
|
Optional By default, property names given in the PROPERTY QoSPolicy are validated to avoid using incorrect or unknown names (for example, due to a typo). This behavior is controlled by the In general, we recommend that you use The Security Plugins’s
If this property is not set, the property validation behavior will be the same as that of the DomainParticipant (controlled by the Enum: Default: not set |
- 1
Assuming you used
com.rti.serv.secure
as the alias to load the plugin. If not, change the prefix to match the string used withcom.rti.serv.load_plugins
, followed by the.
character.
9.4. Advanced Concepts¶
9.4.1. Creating/Deleting a DomainParticipant as a C++ Static Object¶
In some scenarios, you may want a DomainParticipant that can be shared by multiple functions. You could implement this by declaring a DomainParticipant as a C++ static object, as in the following example.
struct Test {
DDSDomainParticipantFactory *factory;
DDSDomainParticipant *participant;
Test(string n) : name(n)
{
DDS_DomainParticipantQos participantQos;
factory = DDSDomainParticipantFactory::get_instance();
factory->get_default_participant_qos(participantQos);
/* set up participantQos to use security */
participant = factory->create_participant(
0,
participantQos,
NULL,
DDS_STATUS_MASK_NONE);
}
~Test()
{
factory->delete_participant(participant);
DDSDomainParticipantFactory::finalize_instance();
}
std::string name;
};
Test my_static("my_static");
int main(int argc, char **argv)
{
return 0;
}
This DomainParticipant is created and deleted outside of the main()
function. This code may crash because OpenSSL 1.1.1n’s cleanup function, OPENSSL_cleanup()
(see OPENSSL_cleanup in OpenSSL Documentation), may get executed before the ~Test()
destructor gets executed, in which case some of the DomainParticipant’s internal OpenSSL state will be inconsistent. To work around this problem, you must invoke OPENSSL_init_crypto()
and OPENSSL_cleanup()
as follows:
/* Add -I$(RTI_OPENSSLHOME)/$(target)/release/include to your compilation flags. */
#include <openssl/crypto.h>
struct Test {
DDSDomainParticipantFactory *factory;
DDSDomainParticipant *participant;
Test(string n) : name(n)
{
DDS_DomainParticipantQos participantQos;
factory = DDSDomainParticipantFactory::get_instance();
factory->get_default_participant_qos(participantQos);
/* Set up participantQos to use security */
...
/*
* OPENSSL_INIT_NO_ATEXIT prevents OpenSSL from registering
* OPENSSL_cleanup() as a function to be invoked upon exit.
* The other two flags are required by Security Plugins. Only call
* OPENSSL_init_crypto before creating the first participant in the process.
*/
OPENSSL_init_crypto(
OPENSSL_INIT_NO_ATEXIT
| OPENSSL_INIT_ADD_ALL_CIPHERS
| OPENSSL_INIT_ADD_ALL_DIGESTS,
NULL);
participant = factory->create_participant(
0,
participantQos,
NULL,
DDS_STATUS_MASK_NONE);
}
~Test()
{
factory->delete_participant(participant);
/*
* Make sure that OPENSSL_cleanup is invoked only after deleting the last
* participant in the process.
*/
OPENSSL_cleanup();
DDSDomainParticipantFactory::finalize_instance();
}
std::string name;
};
9.5. Platform-Specific Notes¶
9.5.1. Building Security Plugins-Based Applications for VxWorks 7¶
You can use the Security Plugins on VxWorks 7. The specific platforms that you can use are listed in the Security Plugins Release Notes.
Building VxWorks applications requires cross-compiling your source code for your target platform. When building Connext DDS Secure applications for VxWorks 7, you will use the OpenSSL libraries from Wind River that are installed on your VxWorks system. Therefore, there’s no need to install any OpenSSL bundle provided by RTI. Instead, applications should be linked against the OpenSSL libraries provided with the OS (installed by default).
For further information on building Connext DDS applications, refer to VxWorks Platforms in the RTI Connext DDS Core Libraries Platform Notes.
The OpenSSL binaries (such as openssl
) will be under <vxworks_toolchain_path>/vxworks-7/host/<host_arch>/bin
.
The OpenSSL libraries (such as libcrypto
) will be under <your_vsb_directory>/usr/lib/common
.
9.5.1.1. Considerations for Building and Running Connext DDS Secure in Kernel Modules¶
When running kernel modules, dynamic loading is not allowed, which implies that Connext DDS will not load the Security Plugins at runtime through a call to dlopen()
. Instead, you have to link your application statically to the Connext DDS Core and the Security Plugins libraries to create a single kernel module. (See Static Linking for details). Alternatively, you can build multiple kernel modules for libnddscore
, libnddsc
, and libnddssecurity
and load them into the kernel separately before loading your DDS application.
In order to be able to run the Security Plugins as a kernel module, the OpenSSL symbols have to be available in the kernel. To do that, you must include the component INCLUDE_IPSSL
into your kernel. Once you have done this, OpenSSL is already included in the kernel itself, and you do not have to include it in the application kernel module. If the INCLUDE_IPSSL
is not enabled, you will need to rebuild your kernel, including this component.
9.5.1.2. Considerations for Building and Running Connext DDS Secure in RTP Executables¶
When running an RTP (Real-Time Process) executable, the process runs at user level, which means that the program does not have access to the kernel memory directly. Thus, the process described in the previous section, Considerations for Building and Running Connext DDS Secure in Kernel Modules, is not valid in this case. In other words, even if you already included OpenSSL symbols in your kernel, the RTP executable cannot use them directly, and thus, you must link it against libcrypto
.
As you will be using the OpenSSL shipped by Wind River, when you link libcrypto
against the application, you need to link the one placed into <your_vsb_directory>/usr/lib/common
. To do that, make RTI_OPENSSLHOME
point to <your_vsb_directory>/usr/lib/common
, where your system’s libraries live. Other than that, follow the steps in Dynamic Linking.
9.6. Libraries Required for Using the RTI Security Plugins¶
To use the RTI Security Plugins, link against the additional libraries in one of the following tables, depending on your platform. Select the files appropriate for your chosen library format.
Library Format |
RTI Security Plugins Libraries 5 |
OpenSSL Libraries 6 |
---|---|---|
Dynamic Release |
|
|
Dynamic Debug |
|
|
Library Format |
RTI Security Plugins Libraries 5 |
OpenSSL Libraries 6 |
---|---|---|
Static Release |
|
|
Static Debug |
|
|
Library Format |
RTI Security Plugins Libraries 5 |
OpenSSL Libraries 6 |
---|---|---|
Dynamic Release |
|
|
Dynamic Debug |
|
|
Static Release |
|
|
Static Debug |
|
|
Library Format |
RTI Security Plugins Libraries 5 |
OpenSSL Libraries 6 |
---|---|---|
Dynamic Release |
|
|
Dynamic Debug |
|
|
Static Release |
|
|
Static Debug |
|
|
Library Format |
RTI Security Plugins Libraries 5 |
OpenSSL Libraries 6 |
---|---|---|
Dynamic Release |
|
|
Dynamic Debug |
|
|
Static Release |
|
|
Static Debug |
|
|
Library Format |
RTI Security Plugins Libraries 5 |
---|---|
Dynamic Release |
|
Dynamic Debug |
|
Static Release |
|
Static Debug |
|
Library Format |
RTI Security Plugins Libraries 5 |
OpenSSL Libraries 2 |
---|---|---|
Dynamic Release |
|
|
Dynamic Debug |
|
|
Static Release |
|
|
Static Debug |
|
|
- 2
These libraries are in
<your vsb directory>/usr/lib/common
.
Library Format |
RTI Security Plugins Libraries 3 |
OpenSSL Libraries 4 |
System Libraries |
---|---|---|---|
Dynamic Release |
|
|
(none) |
Dynamic Debug |
|
|
(none) |
Static Release |
|
|
|
Static Debug |
|
|
|