3. Elements of a Connext DDS Secure System

This chapter covers all the elements that you need to secure a Connext DDS application.

3.1. QoS Properties

To enable and configure the Security Plugins, we use properties defined in the DomainParticipant’s PROPERTY QosPolicy (see PROPERTY QosPolicy (DDS Extension) in the Core Libraries User’s Manual). You can set these properties in code (see RTI Connext C++ API: PROPERTY) or in XML, similar to how you would set transport properties (see Transport Properties in the Core Libraries User’s Manual).

Note

You can include environment variables within XML tags and attributes by using the following notation: $(MY_VARIABLE). See Using Environment Variables in XML in the Core Libraries User’s Manual.

There are two kinds of properties to configure the Security Plugins (you can use a combination of them):

  1. Properties starting with dds.sec. are defined in the DDS Security standard, and provide the functionality specified there. They allow you to configure features of specific plugins (authentication, access control, etc.).

  2. Properties starting with com.rti.serv.secure. (assuming you used com.rti.serv.secure as the prefix to load the plugin, see Table 9.1) are implementation-specific. These properties are used for extra functionality or for parameters that can be configured according to the DDS Security specification but where no configuration method is specified.

Note

For brevity, in this document we omit the prefix (e.g., com.rti.serv.secure.) when referring to implementation-specific properties; we will still use the full name for properties defined by the DDS Security standard.

Authentication, Access Control, Cryptography, and Security Events and Logging describe the properties to configure each of the plugins. Building and Running Security Plugins-Based Applications describes the properties for enabling the Security Plugins. Alternatively, you can make your profile inherit from the Generic.Security builtin profile (which loads the security plugins dynamically).

All the Security Plugins properties are validated when the DomainParticipant and the plugin are created; for more information, see Property validation in the Core Libraries User’s Manual.

In order to have a successful Security Plugins properties validation, you can not add implementation-specific properties (e.g., properties starting with com.rti.serv.secure. 1) without first specifying the property com.rti.serv.load_plugin. In the same way, you cannot disable the Security Plugins by just removing the com.rti.serv.load_plugin, it is also necessary to remove the rest of the properties of the RTI Security Plugins.

Here are some examples:

  • Correct scenario.

    ...
    <property>
      <value>
        <element>
          <name>com.rti.serv.load_plugin</name>
          <value>com.rti.serv.secure</value>
        </element>
        <element>
          <name>com.rti.serv.secure.library</name>
          <value>nddssecurity</value>
        </element>
        <element>
          <name>com.rti.serv.secure.create_function</name>
          <value>RTI_Security_PluginSuite_create</value>
        </element>
      </value>
    </property>
    ...
    
  • Incorrect scenario. The properties com.rti.serv.secure.create_function and com.rti.serv.secure.library will be considered invalid, and (by default) the participant creation will fail with an error.

    ...
    <property>
      <value>
        <element>
          <name>com.rti.serv.secure.library</name>
          <value>nddssecurity</value>
        </element>
        <element>
          <name>com.rti.serv.secure.create_function</name>
          <value>RTI_Security_PluginSuite_create</value>
        </element>
      </value>
    </property>
    ...
    

For further details and configuration options that control the behavior of property validation, see Property Validation in the RTI Connext DDS Core Libraries User’s Manual.

Note

You must set the security-related participant properties before you create a participant (see Table 9.1). You cannot create a participant without security and then call DomainParticipant::set_qos() with security properties, even if the participant has not yet been enabled.

1

Assuming you used com.rti.serv.secure as the prefix to load the plugin, see Table 9.1.

3.2. Public Key Infrastructure (PKI)

The Security Plugins use public-key cryptography to establish a secure and authenticated communication between DomainParticipants. This includes mutually authenticating the participants, which involves validating their identities against the Identity Certificate Authority (CA) and establishing a Shared Key between them. It also includes validating the Governance and Permissions Files against a common Permissions CA.

3.2.1. Identity Certificates

To be correctly authenticated in the system, every secure DomainParticipant needs an Identity, consisting of two artifacts:

  • The Identity Certificate is a X.509 digital certificate (in PEM format) that includes a Public Key and binds it to the Distinguished Name (subject name) for that DomainParticipant. The Identity Certificate is signed by the issuer Certificate Authority (normally the Identity CA, but it can be an intermediate CA), who certifies that the Public Key corresponds to the entity whose information is in the certificate. To specify the Identity Certificate to your DomainParticipant, use the dds.sec.auth.identity_certificate property (see Table 5.3).

  • The Private Key may be a 2048-bit RSA private key, a 256-bit Elliptic Curve Key, or any other private key supported by OpenSSL. To provide the Private Key to your DomainParticipants, use the dds.sec.auth.private_key property (see Table 4.1).

To prevent attackers from forging their own identities, all the Identity Certificates in your system must be signed by a common Identity CA. As part of the authentication process, secure DomainParticipants will use the Identity CA certificate to validate the identity of discovered peers. Alternatively, Identity Certificates can be issued by subordinate CAs that chain up to the Identity CA, creating a chain of trust (see Identity Certificate Chaining). The Identity CA certificate must be an X.509 certificate and it can be self-signed if it is a root CA or signed by some other CA public key if it is a subordinate CA. The Identity CA certificate is provided by the dds.sec.auth.identity_ca property.

3.2.1.1. Certificate Chaining

If your Identity Certificates are not signed/issued by the Identity CA, you must provide your participants with the complete certificate chain by concatenating them in a single file. In other words, you need to concatenate the Identity Certificate, its issuer CA, and every other intermediate CA that chains up to the Identity CA in a single file (or string). By specifying this file (or string) in the dds.sec.auth.identity_certificate property, your participant will load the complete certificate chain that it will use to authenticate against remotely discovered participants. This way, participants in your system can validate the Identity Certificate issued by subordinate CAs. (Note that all the DomainParticipants in your system should have access to a copy of the Identity CA certificate).

For details, see Identity Certificate Chaining.

3.2.1.2. Alternative CAs

Depending on your use case, different DomainParticipants may trust a different Identity CA. This can happen, for example, when several intermediate CAs exist in your PKI. In this case, your Identity Certificate should specify the full chain to the root CA for the greatest compatibility.

There are use cases where you may also have different Root CAs with their own PKIs and intermediate certificates issuing identities for your DomainParticipants. Therefore, there’s no way for every Identity Certificate to chain up to the same Identity CA. In this case, you can use the authentication.alternative_ca_files property to make your participants load alternative Identity CAs (see Table 4.1). When you do so, your participant will use every alternative Identity CA (as well as the main Identity CA) to validate the Identity Certificate of remotely discovered participants.

3.2.1.3. Certificate Revocation

The Identity CA (and any CA under it) can maintain a certificate revocation list (CRL) with information about digital certificates that have been revoked before their scheduled expiration date and should no longer be trusted. You can provide the CRL to your participants by setting the authentication.crl property (see Table 4.1). By doing this, your DomainParticipant will check the certificate against the revocation list. For more information, see Identity Certificate Validation.

Important

If you update the revocation list, the changes will not take effect until you delete and recreate your DomainParticipant.

3.2.1.4. Multiple Certificate Revocation Lists

The value of the authentication.crl property may contain the concatenation of multiple CRLs (see Table 4.1). For example, if a DomainParticipant is configured to have a list of alternative CAs, each of those alternative CAs may have its own CRL included as part of the authentication.crl.

During certificate verification, only the CRL associated with the involved CA will be used. That is, if an Identity Certificate has been signed by the Identity CA, then only the Identity CA’s CRL will be used when verifying the certificate. On the other hand, if an Identity Certificate has been signed by an intermediate CA, then only the intermediate CA’s CRL will be used when verifying the certificate.

The authentication.crl may also contain CRLs from the intermediate CAs of an Identity Certificate chain. If an element in the dds.sec.auth.identity_certificate chain has not been revoked by its signer, then certificate verification will proceed as usual.

3.2.2. Governance and Permissions

To communicate securely, your participants need to follow the rules that you define through the Governance File, provided to your DomainParticipant through the dds.sec.access.governance property. Also, participants need access control policies specified for permission to join the system, to subscribe to Topics, etc. You give your participants permission through the Permissions File, specified by the dds.sec.access.permissions property. These properties are defined in Table 5.3.

Key Terms

A Governance File defines how your system is protected, while Permissions Files define who can access what.

To prevent attackers from pretending to have permissions they do not have, or to communicate using different security parameters than the ones you defined for your system, both Governance and Permissions Files are signed by the Permissions Certificate Authority (CA) using PKCS#7 signatures. The Permissions CA must be shared by all DomainParticipants, therefore any DomainParticipant trusting that Permissions CA can verify whether another DomainParticipant has the permissions it claims. You specify the Permissions CA to your participants through the dds.sec.access.permissions_ca property (see Table 5.3).

Tip

The Permissions CA may be the same as the Identity CA, or it can be a different one, depending on your use case.

Different DomainParticipants may trust different Permissions CAs. In this case, you can use the access_control.alternative_permissions_authority_files property to make your participants load alternative Permissions CAs (see Table 5.3). When you do so, your participant will use every alternative Permissions CA (as well as the main Permissions CA) to validate the Permissions File of remotely discovered participants.

3.3. Governance File

The Governance Document specifies which DDS Domains will be protected and the details of the protection. The Governance Document is specified in an XML file called the Governance File. The Governance File defines two levels of configuration properties: domain level, affecting participants in the Domain (see domain-level rules); and topic level, affecting Endpoints from that Topic (see Topic-Level Rules). You can apply these rules to a single Domain, multiple Domains, or ranges of Domains (see Specifying Domain IDs).

The Governance File must be signed by the Permissions CA using a PKCS#7 signature. You need to specify the signed version of your Governance File using the dds.sec.access.governance property, as described in Table 5.3.

All the participants in your system need to load the same Governance File, or compatible versions (see Governance Compatibility Validation).

3.3.1. Specifying Domain IDs

Both the Governance File and the Permissions File require you to specify the applicable domain IDs using the domains tag. You may use this tag to specify individual domain IDs, domain ranges, open domain ranges, and combinations thereof.

Example: Individual Domain IDs. \(Domains_{protected} = \lbrace 0 \rbrace\cup\lbrace 1\rbrace\)

<domains>
  <!-- Domains 0 and 1 -->
  <id>0</id>
  <id>1</id>
</domains>

Example: Domain Ranges. \(Domains_{protected} = \lbrack 3, 10\rbrack\)

<domains>
  <!-- All domains between 3 and 10, inclusive -->
  <id_range>
      <min>3</min>
      <max>10</min>
  </id_range>
</domains>

Example: Open Domain Ranges. \(Domains_{protected} =\lbrack 0, 5\rbrack\cup\lbrack 10, \mathtt{MAX\_VALID\_DOMAIN\_ID}\rbrack\) 2

<domains>
  <!-- Domain 10 and above -->
  <id_range>
      <min>10</min>
  </id_range>
  <!-- Domains from 0 to 5, inclusive -->
  <id_range>
      <max>5</max>
  </id_range>
</domains>

Example: Combination of Individual Domain IDs and Domain Ranges. \(Domains_{protected} = \lbrace 3 \rbrace\cup\lbrace 7 \rbrace\cup\lbrack 10, 20 \rbrack\cup\lbrack50, \mathtt{MAX\_VALID\_DOMAIN\_ID}\rbrack\)

<domains>
  <!-- Domains 3 and 7 -->
  <id>3</id>
  <id>7</id>
  <!-- Domains from 10 to 20, inclusive -->
  <id_range>
      <min>10</min>
      <max>20</max>
  </id_range>
  <!-- Domain 50 and above -->
  <id_range>
      <min>50</min>
  </id_range>
</domains>
2

Domain IDs are 32-bit unsigned integers, typically between 0 and 232 (or 167 on Windows platforms). This upper limit (MAX_VALID_DOMAIN_ID) comes from the limitations of the DDS_RtpsWellKnownPorts_t structure (see Ports Used for Discovery in the WIRE_PROTOCOL QoSPolicy section of the Connext DDS Core Libraries User’s Manual) and the transport’s port mapping for discovery traffic (see Ports Used for Discovery in the Discovery section of the Connext DDS Core Libraries User’s Manual). For more information on the domain ID limit on Windows systems, see Domain ID Support in the Core Libraries Platform Notes.

3.3.2. Domain-Level Rules

Domain-level rules affect participants in the Domain, taking effect at the DomainParticipant level. These rules will apply to every DomainParticipant in the Domain (or Domain range) that you specify in the domains tag (see Specifying Domain IDs). Domain-level rules fall under a domain_rule tag, as shown in Example Governance File (XML).

  1. allow_unauthenticated_participants: Determines if a secure DomainParticipant is allowed to match a participant that is not able to successfully complete the authentication process. By disallowing unauthenticated participants, we prevent them from publishing or subscribing to Topics in our Secure Domain. For details, see allow_unauthenticated_participants (domain_rule).

  2. enable_join_access_control: Determines if the participant-level permissions configured in the Permissions File are enforced for remote participants. For details, see enable_join_access_control (within a domain_rule).

  3. discovery_protection_kind and liveliness_protection_kind: OMG DDS Security defines a set of secure endpoint discovery and secure participant liveliness builtin topics. These rules determine what level of protection is applied to those builtin topics. Possible values: ENCRYPT, ENCRYPT_WITH_ORIGIN_AUTHENTICATION, SIGN, SIGN_WITH_ORIGIN_AUTHENTICATION, NONE. For details, see Domain-Level Rules.

  4. rtps_protection_kind: Determines what level of protection is applied to RTPS messages. Possible values: ENCRYPT, ENCRYPT_WITH_ORIGIN_AUTHENTICATION, SIGN, SIGN_WITH_ORIGIN_AUTHENTICATION, NONE. For details, see Domain-Level Rules.

3.3.3. Topic-Level Rules

Topic-level rules affect Endpoints for a particular Topic or set of Topics. They belong in a topic_rule, which identifies the Topic that the rule applies to with the topic_expression attribute. All topic_rule tags that apply to your Domain or Domain range fall under the topic_access_rules tag, as shown in Example Governance File (XML).

  1. enable_discovery_protection / enable_liveliness_protection: Determines if discovery information and liveliness updates related to Endpoints from this Topic will be sent with the level of security defined in the domain-level discovery_protection_kind and liveliness_protection_kind rules. For details, see Topic-Level Rules.

  2. enable_read_access_control / enable_write_access_control: Determines if endpoint-level permissions configured in the Permissions File are enforced for local and remote DataReader/DataWriter. For details, see Topic-Level Rules.

  3. metadata_protection_kind: Determines what level of protection is applied to RTPS submessages from Endpoints of the associated Topic. Possible values: ENCRYPT, ENCRYPT_WITH_ORIGIN_AUTHENTICATION, SIGN, SIGN_WITH_ORIGIN_AUTHENTICATION, NONE. For details, see Topic-Level Rules.

  4. data_protection_kind: Determines what level of protection is applied to the serialized payload from Endpoints of the associated topic. Possible values: ENCRYPT, SIGN, NONE. For details, see Topic-Level Rules.

3.3.4. Example Governance File (XML)

This is an example of what a Governance File looks like. You can find this example document in rti_workspace/version/examples/dds_security/xml/Governance.xml. Use this file just as a reference, you will need to update its content, create new files, and/or define or adapt the rules to match your system configuration (Domains, Topics, and used Identity Certificates) before signing the Governance File.

<?xml version="1.0" encoding="UTF-8"?>
<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="http://community.rti.com/schema/6.1.1/dds_security_governance.xsd">
  <domain_access_rules>
    <domain_rule>
      <domains>
        <id_range>
          <min>0</min>
        </id_range>
      </domains>
      <allow_unauthenticated_participants>
        FALSE
      </allow_unauthenticated_participants>
      <enable_join_access_control>TRUE</enable_join_access_control>
      <discovery_protection_kind>ENCRYPT</discovery_protection_kind>
      <liveliness_protection_kind>ENCRYPT</liveliness_protection_kind>
      <rtps_protection_kind>SIGN</rtps_protection_kind>
      <topic_access_rules>
        <topic_rule>
          <topic_expression>Sq*</topic_expression>
          <enable_discovery_protection>FALSE</enable_discovery_protection>
          <enable_liveliness_protection>FALSE</enable_liveliness_protection>
          <enable_read_access_control>FALSE</enable_read_access_control>
          <enable_write_access_control>FALSE</enable_write_access_control>
          <metadata_protection_kind>NONE</metadata_protection_kind>
          <data_protection_kind>NONE</data_protection_kind>
        </topic_rule>
        <topic_rule>
          <topic_expression>*</topic_expression>
          <enable_discovery_protection>TRUE</enable_discovery_protection>
          <enable_liveliness_protection>TRUE</enable_liveliness_protection>
          <enable_read_access_control>TRUE</enable_read_access_control>
          <enable_write_access_control>TRUE</enable_write_access_control>
          <metadata_protection_kind>ENCRYPT</metadata_protection_kind>
          <data_protection_kind>ENCRYPT</data_protection_kind>
        </topic_rule>
      </topic_access_rules>
    </domain_rule>
  </domain_access_rules>
</dds>

The Governance File above defines just one configuration to be applied to any Domain in the system (as specified by the domains XML tag). Consequently, all the Domains and Topics in the system are protected in the same way, in particular, see Table 3.1:

Table 3.1 Domain-Level Rules in the Example Governance File

Domain-level rule (domain_rule)

Value

Security implications

allow_unauthenticated_participants

FALSE

Only authenticated participants are allowed in the system

enable_join_access_control

TRUE

Permissions are checked for any matched and authenticated remote participant

discovery_protection_kind

ENCRYPT

The integrity and confidentiality of the Builtin Secure Discovery Topics are protected

liveliness_protection_kind

ENCRYPT

The integrity and confidentiality of the Builtin Secure Liveliness Topic are protected

rtps_protection_kind

SIGN

The integrity of RTPS messages is protected

Then, this Governance File defines two topic-level rules, as analyzed in Table 3.2 and Table 3.3.

Table 3.2 Topic-Level Rules for Topics Starting with “Sq” (topic_expression is Sq*)

Topic-level rule (topic_rule)

Value

Security implications

enable_discovery_protection

FALSE

Endpoint discovery data for these Topics is not protected

enable_liveliness_protection

FALSE

Liveliness assertions for these Topics are not protected

enable_read_access_control

FALSE

Neither local or remote permissions are checked for DataReaders of these Topics

enable_write_access_control

false

Neither local or remote permissions are checked for DataWriters of these Topics

metadata_protection_kind

NONE

These Topics are not protected at the Submessage level

data_protection_kind

NONE

These Topics are not protected at the Serialized Data level.

Table 3.3 Topic-Level Rules for the Other Topics (topic_expression is *)

Topic-level rule (topic_rule)

Value

Security implications

enable_discovery_protection

true

Endpoint discovery data for the rest of the Topics is protected (encrypted, as specified by discovery_protection_kind)

enable_liveliness_protection

true

Liveliness assertions for the rest of the Topics are protected (encrypted, as specified by liveliness_protection_kind)

enable_read_access_control

true

Permissions are checked for locally created and remotely discovered DataReaders

enable_write_access_control

true

Permissions are checked for locally created and remotely discovered DataWriters

metadata_protection_kind

ENCRYPT

The integrity and confidentiality of RTPS Submessages are protected for the rest of the Topics

data_protection_kind

ENCRYPT

The integrity and confidentiality of Serialized Data are protected for the rest of the Topics

3.3.5. How the Governance File is Interpreted

The rules that compose the Governance File specify how your system is protected. All the DomainParticipants in your secure system need to load the same or a compatible Governance File, either by having a copy of it or by accessing a single Governance File from a shared location (see Governance Compatibility Validation for more details).

As defined by the DDS Security specification, the Governance File is parsed from top to bottom. The first domain_rule matching the participant’s Domain ID will apply to this participant. This means that your Governance File could potentially define other domain_rules for that Domain ID that will not be used.

Note that a DomainParticipant joining a Secure Domain must have compatible domain-level rules. This means that rtps_protection_kind, discovery_protection_kind, and liveliness_protection_kind must match. Otherwise, secure participants will not be able to communicate in the Secure Domain. For details, see Governance Compatibility Validation.

Then, inside a domain_rule section, the topic-level rules will also be parsed from top to bottom. The first topic_rule with a topic_expression matching the topic name will apply, as defined by the DDS Security specification. This means that you can have overlapping patterns with wildcards, and only the first one matching your topic name will apply.

Note that matching Secure DataWriters and Secure DataReaders need to have compatible topic-level rules. This means that data_protection_kind, metadata_protection_kind, enable_discovery_protection, enable_liveliness_protection, enable_read_access_control and enable_write_access_control must match. Otherwise, Secure Endpoints will not be able to communicate. For details, see Governance Compatibility Validation.

3.3.6. XML Validation in the Governance File

The XSD definition of the Governance File is in <NDDSHOME>/resource/schema/dds_security_governance.xsd.

<?xml version="1.0" encoding="UTF-8"?>
<!-- 
   (c) Copyright, Real-Time Innovations, Inc. 2001-2016.
   All rights reserved.
   No duplications, whole or partial, manual or electronic, may be made
   without prior written permission.  Any such copies, or
   revisions thereof, must display this notice unaltered.
   This code contains trade secrets of Real-Time Innovations, Inc.
-->

<!-- =================================================================== -->
<!-- RTI Domain Governance XML Schema File                             -->
<!-- =================================================================== -->

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified" attributeFormDefault="unqualified">

    <xs:element name="dds" type="DomainAccessRulesNode" />

    <xs:complexType name="DomainAccessRulesNode">
        <xs:sequence minOccurs="1" maxOccurs="1">
            <xs:element name="domain_access_rules" type="DomainAccessRules" />
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="DomainAccessRules">
        <xs:sequence minOccurs="1" maxOccurs="unbounded">
            <xs:element name="domain_rule" type="DomainRule" />
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="DomainRule">
        <xs:sequence minOccurs="1" maxOccurs="1">
            <xs:element name="domains" type="DomainIdSet" />
            <xs:element name="allow_unauthenticated_participants" type="xs:boolean" />
            <xs:element name="enable_join_access_control" type="xs:boolean" />
            <xs:element name="discovery_protection_kind" type="ProtectionKind" />
            <xs:element name="liveliness_protection_kind" type="ProtectionKind" />
            <xs:element name="rtps_protection_kind" type="ProtectionKind" />
            <xs:element name="topic_access_rules" type="TopicAccessRules" />
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="DomainIdSet">
        <xs:choice minOccurs="1" maxOccurs="unbounded">
            <xs:element name="id" type="DomainId" />
            <xs:element name="id_range" type="DomainIdRange" />
        </xs:choice>
    </xs:complexType>

    <xs:simpleType name="DomainId">
        <xs:restriction base="xs:nonNegativeInteger" />
    </xs:simpleType>

    <xs:complexType name="DomainIdRange">
        <xs:choice>
            <xs:sequence>
                <xs:element name="min" type="DomainId" />
                <xs:element name="max" type="DomainId" minOccurs="0" />
            </xs:sequence>
            <xs:element name="max" type="DomainId" />
        </xs:choice>    
    </xs:complexType>

    <xs:simpleType name="BasicProtectionKind">
        <xs:restriction base="xs:string">
        <!--  RTI extension: allow whitespaces surrounding values -->
            <xs:whiteSpace value="collapse"/>
            <xs:enumeration value="ENCRYPT" />
            <xs:enumeration value="SIGN" />
            <xs:enumeration value="NONE" />
        </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="ProtectionKind">
        <xs:restriction base="xs:string">
        <!--  RTI extension: allow whitespaces surrounding values -->
            <xs:whiteSpace value="collapse"/>
            <xs:enumeration value="ENCRYPT_WITH_ORIGIN_AUTHENTICATION" />
            <xs:enumeration value="SIGN_WITH_ORIGIN_AUTHENTICATION" />
            <xs:enumeration value="ENCRYPT" />
            <xs:enumeration value="SIGN" />
            <xs:enumeration value="NONE" />
        </xs:restriction>
    </xs:simpleType>
    
    <xs:complexType name="TopicAccessRules">
        <xs:sequence minOccurs="1" maxOccurs="unbounded">
            <xs:element name="topic_rule" type="TopicRule" />
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="TopicRule">
        <xs:sequence minOccurs="1" maxOccurs="1">
            <xs:element name="topic_expression" type="TopicExpression" />
            <xs:element name="enable_discovery_protection" type="xs:boolean" />
            <xs:element minOccurs="0" name="enable_liveliness_protection" type="xs:boolean" />
            <xs:element name="enable_read_access_control" type="xs:boolean" />
            <xs:element name="enable_write_access_control" type="xs:boolean" />
            <xs:element name="metadata_protection_kind" type="ProtectionKind" />
            <xs:element name="data_protection_kind" type="BasicProtectionKind" />
        </xs:sequence>
    </xs:complexType>


    <xs:simpleType name="TopicExpression">
        <xs:restriction base="xs:string" />
    </xs:simpleType>

</xs:schema>

3.3.7. Governance Compatibility Validation

Governance Files loaded by different DomainParticipants need to be compatible. The Security Plugins check Governance compatibility by means of two parameters that are sent during discovery, namely the PID_PARTICIPANT_SECURITY_INFO, to check the participant security attributes, and the PID_ENDPOINT_SECURITY_INFO, to check the endpoint security attributes. These parameters allow DomainParticipant to make matching decisions upon discovering a remote peer or endpoint.

At the participant level, Governance compatibility involves having the same values for the following domain-level rules:

  • RTPS Protection (configured with the rtps_protection_kind domain-level rule)

  • Discovery Protection (configured with the discovery_protection_kind domain-level rule)

  • Liveliness Protection (configured with the liveliness_protection_kind domain-level rule)

If local and remote Governance Files are not compatible, the discovery of the remote participant will fail.

In order to communicate, two matching Endpoints need to have a compatible configuration for the endpoint security attributes. A compatible configuration involves having the same Governance Rules for the topic of the Secure Endpoints:

  • Serialized Data Protection (configured with the data_protection_kind topic-level rule)

  • Submessage Protection (configured with the metadata_protection_kind topic-level rule)

  • Discovery Protection (configured with the enable_discovery_protection topic-level rule)

  • Liveliness Protection (configured with the enable_liveliness_protection topic-level rule)

  • Access Control Enforcements (configured with the enable_read_access_control and enable_write_access_control topic-level rules).

3.4. Permissions File

The Permissions Document specifies what actions a DomainParticipant is allowed to take in a DDS Secure Domain. For example, it determines whether the DomainParticipant can join the Domain, whether it can publish or subscribe to particular Topics, etc.

Permissions Files go beyond many traditional methods of security, where an application that is allowed to communicate within a secure system is generally assumed to be safe, and may be able to access data that it should not. The use of Permissions Files locks down the specific access that trusted applications have, so if one becomes compromised, the damage to the system is limited.

The Permissions File contains a set of grants, which in turn contain a set of allow_rule and deny_rule sections. These rules define what your DomainParticipant is allowed to do in a specific Domain (or range of Domains, as defined in Specifying Domain IDs).

Grants are bound to the DomainParticipant identity. In other words, the subject_name section of the grant identifies the specific DomainParticipant to which the permissions apply. The contents of the subject_name tag need to match the subject name in the participant’s Identity Certificate, with the format being the string representation of the X.509 certificate subject name as defined in IETF RFC 4514. Note that the subject name attribute order doesn’t matter and that you may use “S” or “ST” as the stateOrProvinceName. See RTI Security Plugins Getting Started Guide Hands-on 4 for an example openssl command to extract a correctly-formatted subject name.

Each Permissions File must be signed by the Permissions CA using a PKCS#7 signature. You need to specify the signed version of your Permissions File using the dds.sec.access.permissions property, as described in Table 5.3. Note that the contents of your Permissions Files are sent in the clear during participant authentication (right after Participant Discovery). Therefore, to reduce your network usage each of your Permissions Files should only contain a grant for the participant loading it. For further details, see Contents of Your Permissions Files.

3.4.1. Example Permissions File (XML)

This is an example of what a Permissions File looks like. You can find example documents in rti_workspace/version/examples/dds_security/xml/Permissions_*.xml. Use these files just as a reference, you will need to update their contents or create new files, defining or adapting the rules to match your system configuration (Domains, Topics, and referenced Identity Certificates) before signing the Permissions Files.

<?xml version="1.0" encoding="UTF-8"?>

<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="http://community.rti.com/schema/6.1.1/dds_security_permissions.xsd">
  <permissions>
    <grant name="ParticipantA">
      <subject_name>
        C = US,
        ST = CA,
        O = Real Time Innovations,
        emailAddress = meECdsa@rti.com,
        CN = dtlsexampleECdsa
      </subject_name>
      <validity>
        <!-- Format is CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] in GMT -->
        <not_before>2020-06-30T13:00:00</not_before>
        <not_after>2030-06-30T13:00:00</not_after>
      </validity>
      <allow_rule>
        <domains>
          <id>0</id>
          <id>2</id>
        </domains>
        <publish>
          <topics>
            <topic>Cir*</topic>
          </topics>
          <partitions>
            <partition>P1*</partition>
          </partitions>
        </publish>
        <subscribe>
          <topics>
            <topic>*Sq*</topic>
          </topics>
          <partitions>
            <partition>P2</partition>
          </partitions>
          <data_tags>
            <tag>
              <name>Title</name>
              <value>*Software*</value>
            </tag>
          </data_tags>
        </subscribe>
        <subscribe>
          <topics>
            <topic>Triangle</topic>
          </topics>
        </subscribe>
      </allow_rule>
      <default>DENY</default>
    </grant>
  </permissions>
</dds>

This Permissions File configures a single grant, which are analyzed in Table 3.4.

Table 3.4 Permissions Defined by Grant in Sample Permissions File

XML Attribute

Security Implications

      <subject_name>
        C = US,
        ST = CA,
        O = Real Time Innovations,
        emailAddress = meECdsa@rti.com,
        CN = dtlsexampleECdsa
      </subject_name>

This grant applies to the participant loading the Identity Certificate, with the subject being:

  • Country: US

  • State: CA

  • Organization: Real Time Innovations

  • email address: meECdsa@rti.com

  • Common Name: dtlsexampleECdsa

        <not_before>2020-06-30T13:00:00</not_before>

This grant can only be used after June 30, 2020 at 1:00 pm (GMT).

        <not_after>2030-06-30T13:00:00</not_after>

This grant can only be used before June 30, 2030 at 1:00 pm (GMT).

This grant then defines an allow_rule, which determines everything that the participants using this grant will be allowed to do. This includes joining Domains (participant-level rules) and publishing/subscribing to Topics (endpoint-level rules). Table 3.5 analyzes this grant.

Table 3.5 Actions Allowed by Grant in Sample Permissions File

XML Attribute

Security Implications

        <domains>
          <id>0</id>
          <id>2</id>
        </domains>

The participant using this grant can only join domain 0 and domain 2.

        <publish>
          <topics>
            <topic>Cir*</topic>
          </topics>
          <partitions>
            <partition>P1*</partition>
          </partitions>
        </publish>

The participant using this grant is only allowed to publish topics starting with Cir and only in partitions starting with P1.

        <subscribe>
          <topics>
            <topic>*Sq*</topic>
          </topics>
          <partitions>
            <partition>P2</partition>
          </partitions>
          <data_tags>
            <tag>
              <name>Title</name>
              <value>*Software*</value>
            </tag>
          </data_tags>
        </subscribe>

The participant using this grant is allowed to subscribe to Topics containing Sq in the topic name and only in partition P2.

Moreover, to subscribe to the aforementioned topics, the participant must use readers that either do not announce any data tag, or they announce the Title data tag with a value containing Software.

          </data_tags>
        </subscribe>
        <subscribe>
          <topics>
            <topic>Triangle</topic>

The participant using this grant is also allowed to publish the Topic Triangle in the “empty string” partition.

The DataReader created by the participant to subscribe to the Triangle Topic must not announce any data tag.

Finally, this grant denies any other action, as explained in Table 3.6.

Table 3.6 Default Permissions Defined by Grant in Sample Permissions File

XML Attribute

Security Implications

      <default>DENY</default>

Any action not explicitly allowed in an allow_rule will be denied.

3.4.2. How the Permissions are Interpreted

Permissions for DDS Entities in a DomainParticipant are associated with the subject in the DomainParticipant’s Identity Certificate. When a DomainParticipant loads a Permissions File, it looks for a grant with a subject_name matching its identity. Likewise, when a DomainParticipant receives a remote DomainParticipant’s Permissions File, it looks for a grant with a subject_name matching the remote’s identity. In other words, the subject_name identifies the DomainParticipant to which the grant’s permissions apply.

Note

The contents of the subject_name tag must be the X.509 subject name for the DomainParticipant, as given in the Subject field of its Identity Certificate.

The Permissions File is parsed from top to bottom. In other words, the first rule that matches the operation being attempted will apply, as defined by the DDS Security specification. If a rule’s criteria match the Domain ID (either by id being an exact match or by id_range containing the Domain ID) and the publish or subscribe operation, then the corresponding allow or deny decision is applied. If the criteria for a rule does not match the attempted operation, the evaluation proceeds to the next rule. If no rule is defined for the attempted operation, then the decision specified by the default rule is applied.

The Permissions File loaded by your DomainParticipant needs to contain exactly one grant for this DomainParticipant. Otherwise, the participant creation will fail. Also, the grant needs to be valid for the current date. The Access Control Plugin checks the validity tag to determine this. If the grant is not valid for the current date, the participant creation will fail. Note that you are not required to have the same validity dates in the Permissions File and the Identity Certificate (upon creation, your DomainParticipant will independently verify that the Identity Certificate and the grant in your Permissions File are valid for the current date).

You can give a participant permission to join a Domain by including that Domain ID in the domain tag of an allow_rule. Alternatively, if you set the default to ALLOW, the participant will have access to all Domains that are not included in a deny_rule. If a participant attempts to join a Domain ID it is not authorized to join, the participant creation will fail. Note that if a deny_rule has any publish or subscribe tags, then the deny_rule will not prevent a DomainParticipant from being created; it will only prevent certain Topics, DataWriters, and DataReaders from being created.

DomainParticipants will only be allowed to perform publish operations for Topics, Partitions and tags that explicitly appear under an allow_rules section, unless the default is set to ALLOW. The same applies to subscribe operations. In the case where the default is ALLOW, the publish/subscribe operation will only be denied if it appears inside a deny_rules section. You can also combine allow and deny rules to adapt your system to complex scenarios, as shown in the following example, where your participant is allowed to publish on any topic and in any Partition except Partition “A” in Domain 0.

...
  <deny_rule>
    <domains>
      <id>0</id>
    </domains>
    <publish>
      <topics>
        <topic>*</topic>
      </topics>
      <partitions>
        <partition>A</partition>
      </partitions>
    </publish>
  </deny_rule>
  <allow_rule>
    <domains>
      <id>0</id>
    </domains>
    <publish>
      <topics>
        <topic>*</topic>
      </topics>
      <partitions>
        <partition>*</partition>
      </partitions>
    </publish>
  </allow_rule>
  <default>DENY</default>
...

For further information on how each rule is interpreted, refer to Permissions Document.

3.4.3. XML Validation in the Permissions File

The XSD definition of the Permissions File is in <NDDSHOME>/resource/schema/dds_security_permissions.xsd.

<?xml version="1.0" encoding="UTF-8"?>
<!-- 
   (c) Copyright, Real-Time Innovations, Inc. 2014-2017.
   All rights reserved.
   No duplications, whole or partial, manual or electronic, may be made
   without prior written permission.  Any such copies, or
   revisions thereof, must display this notice unaltered.
   This code contains trade secrets of Real-Time Innovations, Inc.
-->

<!-- =================================================================== -->
<!-- RTI Security XML Schema File                             -->
<!-- =================================================================== -->

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           elementFormDefault="qualified"
           attributeFormDefault="unqualified">

    <!-- =================================================================== -->
    <!-- Main Elements                                                       -->
    <!-- =================================================================== -->

    <xs:element name="dds" type="PermissionsNode" />
    <xs:complexType name="PermissionsNode">
        <xs:sequence minOccurs="1" maxOccurs="1">
            <xs:element name="permissions" type="Permissions" />
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="Permissions">
        <xs:sequence minOccurs="1" maxOccurs="unbounded">
            <xs:element name="grant" type="Grant" />
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="Grant">
        <xs:sequence minOccurs="1" maxOccurs="1">
            <xs:element name="subject_name" type="xs:string" />
            <xs:element name="validity" type="Validity" />
            <xs:sequence minOccurs="1" maxOccurs="unbounded">
                <xs:choice minOccurs="1" maxOccurs="1">
                    <xs:element name="allow_rule" minOccurs="0" type="Rule" />
                    <xs:element name="deny_rule" minOccurs="0" type="Rule" />
                </xs:choice>
            </xs:sequence>
            <xs:element name="default" type="DefaultAction" />
        </xs:sequence>
        <xs:attribute name="name" type="xs:string" use="required" />
    </xs:complexType>

    <xs:complexType name="Validity">
        <xs:sequence minOccurs="1" maxOccurs="1">
            <xs:element name="not_before" type="xs:dateTime" /> <!-- DDSSEC-134 -->
            <xs:element name="not_after" type="xs:dateTime" /> <!-- DDSSEC-134 -->
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="Rule">
        <xs:sequence minOccurs="1" maxOccurs="1">
            <!-- DDSSEC-75 -->
            <xs:element name="domains" type="DomainIdSet" />
            <xs:sequence minOccurs="0" maxOccurs="unbounded"> <!-- DDSSEC-134 -->
                <xs:element name="publish" type="Criteria" />
            </xs:sequence>
            <xs:sequence minOccurs="0" maxOccurs="unbounded">
                <xs:element name="subscribe" type="Criteria" />
            </xs:sequence>
             <xs:sequence minOccurs="0" maxOccurs="unbounded">
                <xs:element name="relay" type="Criteria" />
            </xs:sequence>           
        </xs:sequence>
    </xs:complexType>

    <!-- DDSSEC-75 -->
    <xs:complexType name="DomainIdSet">
        <xs:choice minOccurs="1" maxOccurs="unbounded">
            <xs:element name="id" type="DomainId" />
            <xs:element name="id_range" type="DomainIdRange" />
        </xs:choice>
    </xs:complexType>

    <!-- DDSSEC-75 -->
    <xs:simpleType name="DomainId">
        <xs:restriction base="xs:nonNegativeInteger" />
    </xs:simpleType>

    <!-- DDSSEC-75 -->
    <xs:complexType name="DomainIdRange">
        <xs:choice> <!-- DDSSEC-134 -->
            <xs:sequence>
                <xs:element name="min" type="DomainId" />
                <xs:element name="max" type="DomainId" minOccurs="0" />
            </xs:sequence>
            <xs:element name="max" type="DomainId" />
        </xs:choice>
    </xs:complexType>
    
    <xs:complexType name="Criteria">
        <!-- DDSSEC-72 -->
        <xs:all minOccurs="1">
            <xs:element name="topics" minOccurs="1" type="TopicExpressionList" />
            <xs:element name="partitions" minOccurs="0" type="PartitionExpressionList" />
            <xs:element name="data_tags" minOccurs="0" type="DataTags" />       
        </xs:all>
    </xs:complexType>

    <!-- DDSSEC-72 -->
    <xs:complexType name="TopicExpressionList">
        <xs:sequence minOccurs="1" maxOccurs="unbounded">
            <xs:element name="topic" type="TopicExpression" />
        </xs:sequence>
    </xs:complexType>

    <!-- DDSSEC-72 -->
    <xs:complexType name="PartitionExpressionList">
        <xs:sequence minOccurs="1" maxOccurs="unbounded">
            <xs:element name="partition" type="PartitionExpression" />
        </xs:sequence>
    </xs:complexType>
   
    <xs:simpleType name="TopicExpression">
        <xs:restriction base="xs:string" />
    </xs:simpleType>

    <xs:simpleType name="PartitionExpression">
        <xs:restriction base="xs:string" />
    </xs:simpleType>


    <xs:complexType name="DataTags">
        <xs:sequence minOccurs="1" maxOccurs="unbounded">
            <xs:element name="tag" type="TagNameValuePair" />
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="TagNameValuePair">
        <xs:sequence minOccurs="1" maxOccurs="unbounded">
            <xs:element name="name" type="xs:string" />
            <xs:element name="value" type="xs:string" />
        </xs:sequence>
    </xs:complexType>

    <xs:simpleType name="DefaultAction">
        <xs:restriction base="xs:string">
            <xs:enumeration value="ALLOW" />
            <xs:enumeration value="DENY" />
        </xs:restriction>
    </xs:simpleType>

</xs:schema>

3.5. Security Builtin Topics

To perform some of the security operations (such as mutual authentication) between DomainParticipants, the Security Plugins need to be able to send messages to each other with specific protection kinds or QoS parameters. The mechanisms provided by unsecure DDS builtin Topic entities are not adequate for this purpose. For this reason, the DDS Security specification introduces new builtin Topics and corresponding builtin DataReader and DataWriter entities to read and write the Topics. The Security Plugins implements these Topics using the parameters defined by the DDS Security specification. The following sections describe the most important features and parameters of the security-specific builtin Topics.

Note that some of the security parameters used by these Topics are defined in the DDS Security specification, while others can be tuned through the Governance File (see details below).

3.5.1. Authentication Builtin Topic (ParticipantStatelessMessage)

The Authentication Builtin Topic is used to perform mutual authentication and allows exchanging directed messages through an unsecure communication channel. It is a best-effort stateless Topic, which prevents the sequence-number prediction vulnerability that is present in unsecure reliable protocols. For details, see Authentication Builtin Topic (ParticipantStatelessMessage).

Table 3.7 Non-default QoS Policies for Authentication Stateless DataWriter and DataReader (not configurable)

Policy

Kind

RELIABILITY

BEST_EFFORT

3.5.2. Secure Key Exchange Builtin Topic (ParticipantVolatileMessageSecure)

DomainParticipants use the Secure Key Exchange Builtin Topic to exchange the symmetric keys that secure entities need to communicate securely. This Topic allows DomainParticipants to exchange directed messages to each other using a reliable secure channel. To prevent sending data to unauthorized late joiners, this Topic sets the DURABILITY QoS to kind VOLATILE – because the exchanged messages are directed to specific Participants, there is no need to keep historical samples for late joiners. The Secure Key Exchange Builtin Topic uses Submessage Protection to encrypt the RTPS submessages that include the exchanged keys. For details, see Secure Key Exchange Channel (ParticipantVolatileMessageSecure Topic).

The following tables show the security parameters and QoS settings used by the Secure Key Exchange Builtin Topic.

Table 3.8 Endpoint Security Attributes for Key Exchange DataWriter and DataReader (not configurable)

Topic-Level Rule

Value

enable_discovery_protection

FALSE

enable_liveliness_protection

FALSE

enable_read_access_control

FALSE

enable_write_access_control

FALSE

metadata_protection_kind

ENCRYPT

data_protection_kind

NONE

Table 3.9 Non-default QoS Policies for Key Exchange DataWriter and DataReader (not configurable)

Policy

Kind

RELIABILITY

RELIABLE

HISTORY

KEEP_ALL

DURABILITY

VOLATILE

3.5.3. Builtin Secure Logging Topic

You can distribute the security logging information over DDS. If you decide to do so, your DomainParticipant will publish this information to the Builtin Secure Logging Topic (DDS:Security:LogTopic), as defined in the DDS Security specification.

The following tables show the security parameters used by the Builtin Secure Logging Topic.

Table 3.10 Endpoint Security Attributes for Builtin Secure Logging DataWriter and DataReader (not configurable)

Topic-Level Rule

Value

enable_discovery_protection

FALSE

enable_liveliness_protection

FALSE

enable_read_access_control

TRUE

enable_write_access_control

FALSE

metadata_protection_kind

SIGN 3

data_protection_kind

ENCRYPT

For more information about the Builtin Secure Logging Topic, see Builtin Secure Logging Topic.

3

In Connext DDS 5.3.0, the Builtin Secure Logging Topic did not use Submessage Protection (which did not comply with the DDS Security specification). For backward compatibility, you can choose to disable Submessage Protection in this Topic with the access_control.use_530_logging_protection property (see Table 7.3).

3.5.4. Builtin Secure Discovery Topics

The Builtin Secure Discovery Topics are the analogous versions of the Builtin Discovery Topics. You can configure whether to use the secure version (or the regular/unsecure version) of the builtin Discovery Endpoints for a certain Topic with the enable_discovery_protection Governance Rule. If you set this Governance Rule to TRUE, discovery information related to your Topic will be exchanged through the Builtin Secure Discovery Endpoints. These Endpoints will apply Submessage Protection to the level you configure with the discovery_protection_kind Governance Rule. Note that enable_discovery_protection also determines whether Topic Queries are secured (see Builtin Secure ServiceRequest Topic).

Note that the Builtin Secure Discovery Endpoints are created in addition to the unsecure version of the same Endpoints, and have the same QoS configuration. The following table shows the correspondence between the secure and unsecure versions of the discovery builtin Topics.

Table 3.11 Correspondence between Unsecure and Secure Versions of Discovery Builtin Topics

Description

DDS Builtin Topics

DDS Security Builtin Topics

Participant Discovery

DCPSParticipant

DCPSParticipantSecure

Endpoint Discovery

DCPSPublication

DCPSPublicationSecure

DCPSSubscription

DCPSSubscriptionSecure

For further information about discovery Endpoints, see Discovery Implementation in the Core Libraries User’s Manual. For more information about the secure version of discovery Endpoints see Builtin Secure Discovery Endpoints.

3.5.5. Builtin Secure Liveliness Topic

You can configure whether to use the secure or unsecure version of the Builtin Liveliness Endpoints for a certain Topic with the enable_liveliness_protection Governance Rule. If you set this Governance Rule to TRUE, liveliness information related to your Topic will be exchanged through the Builtin Secure Liveliness Endpoints. These Endpoints will apply Submessage Protection to the level you configure with the liveliness_protection_kind Governance Rule. Please note that the Builtin Liveliness Topics (either the secure and regular version) are only used for Topics that set the LIVELINESS QosPolicy to AUTOMATIC or MANUAL_BY_PARTICIPANT (see enable_liveliness_protection (topic_rule)).

Note that the Builtin Secure Liveliness Endpoints are created in addition to the unsecure version of the same Endpoints, and have the same QoS configuration. The following table shows the correspondence between the secure and unsecure versions of the liveliness builtin Topic.

Table 3.12 Correspondence between Unsecure and Secure versions of Liveliness Builtin Topic

Description

DDS Builtin Topics

DDS Security Builtin Topics

Liveliness (when the LIVELINESS QosPolicy of a particular Topic is AUTOMATIC or MANUAL_BY_PARTICIPANT)

DCPSParticipantMessage

DCPSParticipantMessageSecure

For more information about the secure version of the liveliness Endpoints see Builtin Secure Liveliness Endpoints.

3.5.6. Builtin Secure ServiceRequest Topic

The Builtin Secure ServiceRequest Topic is a vendor-specific Topic analogous to the Builtin ServiceRequest Topic. Whenever you use the secure version of the Builtin Discovery Endpoints (by setting enable_discovery_protection), the Builtin Secure ServiceRequest Endpoints will be used to communicate Topic Queries. These Endpoints will apply Submessage Protection to the level you configure with the discovery_protection_kind Governance Rule.

Note that the Builtin Secure ServiceRequest Endpoints are created in addition to the unsecure version of the same Endpoints. The following table shows the correspondence between the secure and unsecure versions of the ServiceRequest builtin Topics.

Table 3.13 Correspondence between Unsecure and Secure versions of ServiceRequest Builtin Topics

Description

DDS Builtin Topics

DDS Security Builtin Topics

Service Request

DDSServiceRequest

DDSServiceRequestSecure

For further information, see The Built-in ServiceRequest DataReader in the Core Libraries User’s Manual.