DDS Security#

OpenDDS includes an implementation of the DDS Security specification. This allows participants to encrypt messages and to authenticate remote participants before engaging with them.

Important

Library filename: OpenDDS_Security

MPC base project name: opendds_security

CMake target Name: OpenDDS::Security

Initialization header: dds/DCPS/security/BuiltInPlugins.h

Building OpenDDS with Security Enabled#

OpenDDS isn’t built with security enabled by default. See Security for more information.

Architecture of the DDS Security Specification#

The DDS Security specification defines plugin APIs for Authentication, Access Control, and Cryptographic operations. These APIs provide a level of abstraction for DDS implementations as well as allowing for future extensibility and version control. Additionally, the specification defines Built-In implementations of each of these plugins, which allows for a baseline of functionality and interoperability between DDS implementations. OpenDDS implements these Built-In plugins, and this document assumes that the Built-In plugins are being used. Developers using OpenDDS may also implement their own custom plugins, but those efforts are well beyond the scope of this document.

Terms and Background Info#

DDS Security uses current industry standards and best-practices in security. As such, this document makes use of several security concepts which may warrant additional research by OpenDDS users.

Term Group

References

Public Key Cryptography (including Private Keys)

Public Key Certificate

Signed Documents

Required DDS Security Artifacts#

Per-Domain Artifacts#

These are shared by all participants within the secured DDS Domain:

  • Identity CA Certificate

  • Permissions CA Certificate (may be same as Identity CA Certificate)

  • Governance Document

    • Signed by Permissions CA using its private key

Per-Participant Artifacts#

These are specific to the individual Domain Participants within the DDS Domain:

  • Identity Certificate and its Private Key

    • Issued by Identity CA (or a CA that it authorized to act on its behalf)

  • Permissions Document

    • Contains a “subject name” which matches the participant certificate’s Subject

    • Signed by Permissions CA using its private key

Required OpenDDS Configuration#

The following configuration steps are required to enable OpenDDS Security features:

  1. Select RTPS Discovery and the RTPS-UDP Transport; because DDS Security only works with these configurations, both must be specified for any security-enabled participant.

  2. Enable OpenDDS security-features, which can be done two ways:

    • Via API: TheServiceParticipant->set_security(true); or

    • Via config file: setting [common] DCPSSecurity to 1.

DDS Security Configuration via Property Qos Policy#

When the application creates a DomainParticipant, the DomainParticipantQos passed to the create_participant() method contains Property QoS, which has a sequence of name-value pairs. The following properties must be included to enable security. Except where noted, these values take the form of a URI starting with either the scheme file: followed by a filesystem path (absolute or relative) or the scheme data:, followed by the literal data.

Name

Value

Notes

dds.sec.auth.identity_ca

Certificate PEM file

Can be the same as permissions_ca

dds.sec.access.permissions_ca

Certificate PEM file

Can be the same as identity_ca

dds.sec.access.governance

Signed XML (.p7s)

Signed by permissions_ca

dds.sec.auth.identity_certificate

Certificate PEM file

Signed by identity_ca

dds.sec.auth.private_key

Private Key PEM file

Private key for identity_certificate

dds.sec.auth.password

Private Key Password (not a URI)

Optional, Base64 encoded

dds.sec.access.permissions

Signed XML (.p7s)

Signed by permissions_ca

Example Code#

Below is an example of code that sets the Participant QoS’s Property QoS in order to configure DDS Security.

// DDS Security artifact file locations
const char auth_ca_file[] = "file:identity_ca_cert.pem";
const char perm_ca_file[] = "file:permissions_ca_cert.pem";
const char id_cert_file[] = "file:test_participant_01_cert.pem";
const char id_key_file[] = "file:test_participant_01_private_key.pem";
const char governance_file[] = "file:governance_signed.p7s";
const char permissions_file[] = "file:permissions_01_signed.p7s";

// DDS Security property names
const char DDSSEC_PROP_IDENTITY_CA[] = "dds.sec.auth.identity_ca";
const char DDSSEC_PROP_IDENTITY_CERT[] = "dds.sec.auth.identity_certificate";
const char DDSSEC_PROP_IDENTITY_PRIVKEY[] = "dds.sec.auth.private_key";
const char DDSSEC_PROP_PERM_CA[] = "dds.sec.access.permissions_ca";
const char DDSSEC_PROP_PERM_GOV_DOC[] = "dds.sec.access.governance";
const char DDSSEC_PROP_PERM_DOC[] = "dds.sec.access.permissions";

void append(DDS::PropertySeq& props, const char* name, const char* value)
{
  const DDS::Property_t prop = {name, value, false /*propagate*/};
  const unsigned int len = props.length();
  props.length(len + 1);
  props[len] = prop;
}

int main(int argc, char* argv[])
{
  DDS::DomainParticipantFactory_var dpf =
    TheParticipantFactoryWithArgs(argc, argv);

  // Start with the default Participant QoS
  DDS::DomainParticipantQos part_qos;
  dpf->get_default_participant_qos(part_qos);

  // Add properties required by DDS Security
  DDS::PropertySeq& props = part_qos.property.value;
  append(props, DDSSEC_PROP_IDENTITY_CA, auth_ca_file);
  append(props, DDSSEC_PROP_IDENTITY_CERT, id_cert_file);
  append(props, DDSSEC_PROP_IDENTITY_PRIVKEY, id_key_file);
  append(props, DDSSEC_PROP_PERM_CA, perm_ca_file);
  append(props, DDSSEC_PROP_PERM_GOV_DOC, governance_file);
  append(props, DDSSEC_PROP_PERM_DOC, permissions_file);

  // Create the participant
  participant = dpf->create_participant(4, // DomainID
                                        part_qos,
                                        0, // No listener
                                        OpenDDS::DCPS::DEFAULT_STATUS_MASK);

Identity Certificates and Certificate Authorities#

All certificate inputs to OpenDDS, including self-signed CA certificates, are expected to be an X.509 v3 certificate in PEM format for either a 2048-bit RSA key or a 256-bit Elliptic Curve key (using the prime256v1 curve).

Identity, Permissions, and Subject Names#

The “subject_name” element for a signed permissions XML document must match the “Subject:” field provided by the accompanying Identity Certificate which is transmitted during participant discovery, authentication, and authorization. This ensures that the permissions granted by the Permissions CA do, in fact, correspond to the identity provided.

Examples in the OpenDDS Source Code Repository#

Examples to demonstrate how the DDS Security features are used with OpenDDS can be found in the OpenDDS GitHub repository.

The following table describes the various examples and where to find them in the source tree.

Example

Source Location

C++ application that configures security QoS policies via command-line parameters

tests/DCPS/Messenger/publisher.cpp

Identity CA Certificate (along with private key)

tests/security/certs/identity/identity_ca_cert.pem

Permissions CA Certificate (along with private key)

tests/security/certs/permissions/permissions_ca_cert.pem

Participant Identity Certificate (along with private key)

tests/security/certs/identity/test_participant_01_cert.pem

Governance XML Document (alongside signed document)

tests/DCPS/Messenger/governance.xml

Permissions XML Document (alongside signed document)

tests/DCPS/Messenger/permissions_1.xml

Using OpenSSL Utilities for OpenDDS#

To generate certificates using the openssl command, a configuration file openssl.cnf is required (see below for example commands). Before proceeding, it may be helpful to review OpenSSL’s man pages to get help with the file format. In particular, configuration file format and ca command’s documentation and configuration file options.

An example OpenSSL CA-Config file used in OpenDDS testing can be found here: tests/security/certs/identity/identity_ca_openssl.cnf

Creating Self-Signed Certificate Authorities#

Generate a self-signed 2048-bit RSA CA:

openssl genrsa -out ca_key.pem 2048
openssl req -config openssl.cnf -new -key ca_key.pem -out ca.csr
openssl x509 -req -days 3650 -in ca.csr -signkey ca_key.pem -out ca_cert.pem

Generate self-signed 256-bit Elliptic Curve CA:

openssl ecparam -name prime256v1 -genkey -out ca_key.pem
openssl req -config openssl.cnf -new -key ca_key.pem -out ca.csr
openssl x509 -req -days 3650 -in ca.csr -signkey ca_key.pem -out ca_cert.pem

Creating Signed Certificates with an Existing CA#

Generate a signed 2048-bit RSA certificate:

openssl genrsa -out cert_1_key.pem 2048
openssl req -new -key cert_1_key.pem -out cert_1.csr
openssl ca -config openssl.cnf -days 3650 -in cert_1.csr -out cert_1.pem

Generate a signed 256-bit Elliptic Curve certificate:

openssl ecparam -name prime256v1 -genkey -out cert_2_key.pem
openssl req -new -key cert_2_key.pem -out cert_2.csr
openssl ca -config openssl.cnf -days 3650 -in cert_2.csr -out cert_2.pem

Signing Documents with SMIME#

Sign a document using existing CA & CA private key:

openssl smime -sign -in doc.xml -text -out doc_signed.p7s -signer ca_cert.pem -inkey ca_private_key.pem

Common XML Elements#

These are elements that are common to all the XML documents.

Domain Id Set#

A list of domain ids and/or domain id ranges of domains impacted by the current domain rule. This is the type of domains in the governance document and in the permissions document.

The set is made up of <id> tags or <id_range> tags. An <id> tag simply contains the domain id that are part of the set. An <id_range> tag can be used to add multiple ids at once. It must contain a <min> tag to say where the range starts and may also have a <max> tag to say where the range ends. If the <max> tag is omitted then the set includes all valid domain ids starting at <min>.

If the domain rule or permissions grant should to apply to all domains, use the following:

<domains>
  <id_range><min>0</min></id_range>
</domains>

If there’s a need to be selective about what domains are chosen, here’s an annotated example:

<domains>
  <id>2</id>
  <id_range><min>4</min><max>6</max></id_range> <!-- 4, 5, 6 -->
  <id_range><min>10</min></id_range> <!-- 10 and onward -->
</domains>

Domain Governance Document#

The signed governance document is used by the DDS Security built-in access control plugin in order to determine both per-domain and per-topic security configuration options for specific domains. For full details regarding the content of the governance document, see DDS Security v1.1 9.4.1.2 Domain Governance Document.

Global Governance Model#

It’s worth noting that the DDS Security Model expects the governance document to be globally shared by all participants making use of the relevant domains described within the governance document. Even if this is not the case, the local participant will verify incoming authentication and access control requests as if the remote participant shared the same governance document and accept or reject the requests accordingly.

Key Governance Elements#

The following types and values are used in configuring both per-domain and per-topic security configuration options. We summarize them here to simplify discussion of the configuration options where they’re used, found below.

Boolean#

A boolean value indicating whether a configuration option is enabled or not. Recognized values are: TRUE/true/1 and FALSE/false/0

Protection Kind#

The method used to protect domain data (message signatures or message encryption) along with the ability to include origin authentication for either protection kind.

Recognized values are:

  • NONE

  • SIGN

  • ENCRYPT

  • SIGN_WITH_ORIGIN_AUTHENTICATION

  • ENCRYPT_WITH_ORIGIN_AUTHENTICATION

Attention

Currently, OpenDDS doesn’t implement origin authentication. So while the _WITH_ORIGIN_AUTHENTICATION options are recognized, the underlying configuration is unsupported.

Basic Protection Kind#

The method used to protect domain data (message signatures or message encryption). Recognized values are NONE, SIGN, and ENCRYPT

Domain Rule Configuration Options#

The following XML elements are used to configure domain participant behaviors.

domains#

A Domain Id Set of domains impacted by the current domain rule.

allow_unauthenticated_participants#

A Boolean value which determines whether to allow unauthenticated participants for the current domain rule

enable_join_access_control#

A Boolean value which determines whether to enforce domain access controls for authenticated participants

discovery_protection_kind#

The discovery protection element specifies the Protection Kind used for the built-in DataWriter(s) and DataReader(s) used for secure endpoint discovery messages

liveliness_protection_kind#

The liveliness protection element specifies the Protection Kind used for the built-in DataWriter and DataReader used for secure liveliness messages

rtps_protection_kind#

Indicate the Protection Kind for the whole RTPS message. Very little RTPS data exists outside the “metadata protection” envelope (see topic rule configuration options), and so for most use cases topic-level “data protection” or “metadata protection” can be combined with discovery protection and/or liveliness protection in order to secure domain data adequately. One item that is not secured by “metadata protection” is the timestamp, since RTPS uses a separate InfoTimestamp submessage for this. The timestamp can be secured by using rtps_protection_kind

Topic Rule Configuration Options#

The following XML elements are used to configure topic endpoint behaviors:

topic_expression#

A fnmatch expression of the topic names to match. A default rule to catch all previously unmatched topics can be made with: <topic_expression>*</topic_expression>

enable_discovery_protection#

A Boolean to enable the use of secure discovery protections for matching user topic announcements.

enable_read_access_control#

A Boolean to enable the use of access control protections for matching user topic DataReaders.

enable_write_access_control#

A Boolean to enable the use of access control protections for matching user topic DataWriters.

metadata_protection_kind#

Specifies the Protection Kind used for the RTPS SubMessages sent by any DataWriter and DataReader whose associated Topic name matches the rule’s topic expression.

data_protection_kind#

Specifies the Basic Protection Kind used for the RTPS SerializedPayload SubMessage element sent by any DataWriter whose associated Topic name matches the rule’s topic expression.

Governance XML Example#

<?xml version="1.0" encoding="utf-8"?>
<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.omg.org/spec/DDS- Security/20170801/omg_shared_ca_domain_governance.xsd">
  <domain_access_rules>
    <domain_rule>
      <domains>
        <id>0</id>
        <id_range>
          <min>10</min>
          <max>20</max>
        </id_range>
      </domains>
      <allow_unauthenticated_participants>FALSE</allow_unauthenticated_participants>
      <enable_join_access_control>TRUE</enable_join_access_control>
      <rtps_protection_kind>SIGN</rtps_protection_kind>
      <discovery_protection_kind>ENCRYPT</discovery_protection_kind>
      <liveliness_protection_kind>SIGN</liveliness_protection_kind>
      <topic_access_rules>
        <topic_rule>
          <topic_expression>Square*</topic_expression>
          <enable_discovery_protection>TRUE</enable_discovery_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_rule>
          <topic_expression>Circle</topic_expression>
          <enable_discovery_protection>TRUE</enable_discovery_protection>
          <enable_read_access_control>FALSE</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_rule>
          <topic_expression>Triangle</topic_expression>
          <enable_discovery_protection>FALSE</enable_discovery_protection>
          <enable_read_access_control>FALSE</enable_read_access_control>
          <enable_write_access_control>TRUE</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_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>

Participant Permissions Document#

The signed permissions document is used by the DDS Security built-in access control plugin in order to determine participant permissions to join domains and to create endpoints for reading, writing, and relaying domain data. For full details regarding the content of the permissions document, see DDS Security v1.1 9.4.1.3 DomainParticipant permissions document.

Key Permissions Elements#

Each permissions file consists of one or more permissions grants. Each grant bestows access control privileges to a single subject name for a limited validity period.

subject_name#

This is a X.509 subject name field. In order for permissions checks to successfully validate for both local and remote participants, the supplied identity certificate subject name must match the subject name of one of the grants included in the permissions file.

This will look something like:

<subject_name>emailAddress=cto@acme.com, CN=DDS Shapes Demo, OU=CTO Office, O=ACME Inc., L=Sunnyvale, ST=CA, C=US</subject_name>

Changed in version 3.25.0: The order of attributes in subject names is now significant.

validity#

Each grant’s validity section contains a start date and time (<not_before>) and an end date and time (<not_after>) to indicate the period of time during which the grant is valid.

The format of the date and time, which is like ISO-8601, must take one of the following forms:

  1. YYYY-MM-DDThh:mm:ss

    Example: 2020-10-26T22:45:30

  2. YYYY-MM-DDThh:mm:ssZ

    Example:2020-10-26T22:45:30Z

  3. YYYY-MM-DDThh:mm:ss+hh:mm

    Example:2020-10-26T23:45:30+01:00

  4. YYYY-MM-DDThh:mm:ss-hh:mm

    Example:2020-10-26T16:45:30-06:00

All fields shown must include leading zeros to fill out their full width, as shown in the examples. YYYY-MM-DD is the date and hh:mm:ss is the time in 24-hour format. The date and time must be able to be represented by the time_t (C standard library) type of the system. The seconds field can also include a variable length fractional part, like 00.0 or 01.234, but it will be ignored because time_t represents a whole number of seconds. Examples #1 and #2 are both interpreted using UTC. To put the date and time in a local time, a time zone offset can to be added that says how far the local timezone is ahead of (using + as in example #3) or behind (using - as in example #4) UTC at that date and time.

allow_rule and deny_rule#

Grants will contain one or more allow / deny rules to indicate which privileges are being applied. When verifying that a particular operation is allowed by the supplied grant, rules are checked in the order they appear in the file. If the domain, partition, and (when implemented) data tags for an applicable topic rule match the operation being verified, the rule is applied (either allow or deny). Otherwise, the next rule is considered. Special Note: If a grant contains any allow rule that matches a given domain (even one with no publish / subscribe / relay rules), the grant may be used to join a domain with join access controls enabled.

domains#

Every allow or deny rule must contain a set of domain ids to which it applies. The syntax is the same as the domain id set found in the governance document. See Domain Id Set for details.

publish, subscribe, and relay Rules (PSR rules)#

Every allow or deny rule may optionally contain a list of publish, subscribe, or relay rules bestowing privileges to publish, subscribe, or relay data (respectively). Each rule applies to a collection of topics in a set of partitions with a particular set of data tags. As such, each rule must then meet these three conditions (topics, partitions, and (when implemented) data tags) in order to apply to a given operation. These conditions are governed by their relevant subsection, but the exact meaning and default values will vary depending on the both the PSR type (publish, subscribe, relay) as well as whether this is an allow rule or a deny rule. Each condition is summarized below. See the DDS Security specification for full details. OpenDDS does not currently support relay-only behavior and consequently ignores allow and deny relay rules for both local and remote entities. Additionally, OpenDDS does not currently support data tags, and so the data tag condition applied is always the “default” behavior described below.

topics#

The list of topics and/or topic expressions for which a rule applies. Topic names and expressions are matched using Fnmatch Expressions. If the triggering operation matches any of the topics listed, the topic condition is met. The topic section must always be present for a PSR rule, so there there is no default behavior.

partitions#

The partitions list contains the set of partition names for which the parent PSR rule applies. Similarly to topics, partition names and expressions are matched using Fnmatch Expressions. For “allow” PSR rules, the DDS entity of the associated triggering operation must be using a strict subset of the partitions listed for the rule to apply. When no partition list is given for an “allow” PSR rule, the “empty string” partition is used as the default value. For “deny” PSR rules, the rule will apply if the associated DDS entity is using any of the partitions listed. When no partition list is given for a “deny” PSR rule, the wildcard expression “*” is used as the default value.

data_tags#

Attention

Data tags are an optional part of the DDS Security specification and are not currently implemented by OpenDDS. If they were implemented, the condition criteria for data tags would be similar to partitions.

For “allow” PSR rules, the DDS entity of the associated triggering operation must be using a strict subset of the data tags listed for the rule to apply. When no data tag list is given for an “allow” PSR rule, the empty set of data tags is used as the default value. For “deny” PSR rules, the rule will apply if the associated DDS entity is using any of the data tags listed. When no data tag list is given for a “deny” PSR rule, the set of “all possible tags” is used as the default value.

validity#

Attention

This is an OpenDDS extension.

This structure defines the validity of a particular publish or subscribe action. Thus, it is possible to declare that an action is valid for some subset of the grant’s validity. The format for validity is the same as validity.

default_rule#

The default rule is the rule applied if none of the grant’s allow rules or deny rules match the incoming operation to be verified. Recognized values are ALLOW and DENY.

Permissions XML Example#

<?xml version="1.0" encoding="UTF-8"?>
<dds xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.omg.org/spec/DDS-Security/20170801/omg_shared_ca_permissions.xsd">
  <permissions>
    <grant name="ShapesPermission">
      <subject_name>emailAddress=cto@acme.com, CN=DDS Shapes Demo, OU=CTO Office, O=ACME Inc., L=Sunnyvale, ST=CA, C=US</subject_name>
      <validity>
        <not_before>2015-10-26T00:00:00</not_before>
        <not_after>2020-10-26T22:45:30</not_after>
      </validity>
      <allow_rule>
        <domains>
          <id>0</id>
        </domains>
      </allow_rule>
      <deny_rule>
        <domains>
          <id>0</id>
        </domains>
        <publish>
          <topics>
            <topic>Circle1</topic>
          </topics>
        </publish>
        <publish>
          <topics>
            <topic>Square</topic>
          </topics>
          <partitions>
            <partition>A_partition</partition>
          </partitions>
        </publish>
        <subscribe>
          <topics>
            <topic>Square1</topic>
          </topics>
        </subscribe>
        <subscribe>
          <topics>
            <topic>Tr*</topic>
          </topics>
          <partitions>
            <partition>P1*</partition>
          </partitions>
        </subscribe>
      </deny_rule>
      <default>DENY</default>
    </grant>
  </permissions>
</dds>

DDS Security Implementation Status#

The following DDS Security features are not implemented in OpenDDS.

  1. Optional parts of the DDS Security v1.1 specification

    • Ability to write a custom plugin in C or in Java (C++ is supported)

    • Logging Plugin support

    • Built-in Logging Plugin

    • Data Tagging

  2. Use of RTPS KeyHash for encrypted messages

    • OpenDDS doesn’t use KeyHash, so it meets the spec requirements of not leaking secured data through KeyHash

  3. Immutability of Publisher’s Partition QoS, see OMG Issue DDSSEC12-49 (Member Link)

  4. Use of multiple plugin configurations (with different Domain Participants)

  5. CRL (RFC 5280) and OCSP (RFC 2560) support

  6. Certain plugin operations not used by built-in plugins may not be invoked by middleware

  7. Origin Authentication

  8. PKCS#11 for certificates, keys, passwords

  9. Relay as a permissions “action” (Publish and Subscribe are supported)

  10. Legacy matching behavior of permissions based on Partition QoS

  11. 128-bit AES keys (256-bit is supported)

  12. Configuration of Built-In Crypto’s key reuse (within the DataWriter) and blocks-per-session

  13. Signing (without encrypting) at the payload level, see OMG Issue DDSSEC12-59 (Member Link)

The following features are OpenDDS extensions:

  1. Validity of publish/subscribe actions validity.