8. Hands-On 5: Checking that Your DDS Traffic Is Protected

In this Hands-On, you will learn about the effects that enabling DDS Security has on the wire. We will start by disabling security in our project and viewing the contents of RTPS packets with Wireshark. Then we will re-enable the protections defined in Hands-On 2: Defining Your System’s Security Requirements. We will use Wireshark again to verify that messages from the publisher are encrypted.

Note

We will use Wireshark to capture and analyze the packets on the network. For instructions on getting and installing Wireshark, please refer to Building and Installing Wireshark in Wireshark’s User’s Guide. For instructions on enabling convenient coloring rules for the RTPS protocol, see How To configure Wireshark to show RTPS packets with specific colors from our Knowledge Base.

8.1. Disabling Security and Preparing Your Project for Traffic Capturing

In Hands-On 1: Securing Connext DDS Applications we defined a QoS profile named Alice to enable the Security Plugins. This profile inherits from the builtin profile, BuiltinQosLib::Generic.Security, which tells your DomainParticipant to enable the Security Plugins. (See Properties for Enabling Security in the RTI Security Plugins User’s Manual). We can instead use the BuiltinQosLib::Generic.Common profile to have an application that does not load the Security Plugins.

We will also need to force communication over UDPv4 to capture traffic using Wireshark. We need to do this because, by default, applications running on the same machine will communicate using shared memory (for more details, see How to capture traffic if my Connext DDS applications are communicating through shared memory from our Knowledge Base).

  1. Modify USER_QOS_PROFILES.xml to load the BuiltinQosLib::Generic.Common profile and force communication over the UDPv4 transport protocol:

    <qos_profile name="Alice" base_name="BuiltinQosLib::Generic.Common" is_default_qos="true">
         <domain_participant_qos>
            <!-- Disable shared memory to capture UDP packets on Wireshark -->
            <transport_builtin>
                <mask>UDPv4</mask>
            </transport_builtin>
            ...
    

    Please note that this change affects both the publisher and subscriber applications.

  2. Change your publisher’s source code to send a message that we will read using Wireshark:

    void run_publisher_application(unsigned int domain_id, unsigned int sample_count)
    {
        ...
        PatientMonitoring data;
        for (unsigned int samples_written = 0;
        !application::shutdown_requested && samples_written < sample_count;
        samples_written++) {
            // Modify the data to be written here
            data.patient_condition(
                    std::string("{heart_rate: ")
                    + std::to_string(100 + samples_written%10)
                    + "}");
            ...
    

    After this step, you will need to rebuild your project (see Linking Your Applications Against RTI Security Plugins and OpenSSL Libraries).

8.1.1. Analyzing RTPS Packets in Wireshark

  1. Open Wireshark and start capturing packets on the loopback interface 1. Alternatively, you may want to use another interface if your publisher and subscriber applications are on different machines 2. To filter out packets that are not related to your applications, apply the following display filter:

    rtps.domain_id == 1
    

    Note

    In most cases, you want to start capturing packets before you start your DDS applications. This way, you will be able to analyze the communication from the beginning, including DDS Discovery traffic.

  2. Run your publisher and subscriber as explained in Running the Applications. Specify Domain 1 with the -d option in the command line. You should see communication:

    Publisher:

    $ ./objs/<architecture>/PatientMonitoring_publisher -d 1
    Writing PatientMonitoring, count 0
    Writing PatientMonitoring, count 1
    Writing PatientMonitoring, count 2
    Writing PatientMonitoring, count 3
    

    Subscriber:

    $ ./objs/x64Linux3gcc5.4.0/PatientMonitoring_subscriber -d 1
    PatientMonitoring subscriber sleeping up to 1 sec...
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 101}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 102}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 103}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    

    Publisher:

    $ ./objs/<architecture>/PatientMonitoring_publisher -d 1
    Writing PatientMonitoring, count 0
    Writing PatientMonitoring, count 1
    Writing PatientMonitoring, count 2
    Writing PatientMonitoring, count 3
    

    Subscriber:

    $ ./objs/x64Linux3gcc5.4.0/PatientMonitoring_subscriber -d 1
    PatientMonitoring subscriber sleeping up to 1 sec...
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 101}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 102}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 103}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    

    Publisher:

    > objs\<architecture>\PatientMonitoring_publisher.exe -d 1
    Writing PatientMonitoring, count 0
    Writing PatientMonitoring, count 1
    Writing PatientMonitoring, count 2
    Writing PatientMonitoring, count 3
    

    Subscriber:

    > objs\<architecture>\PatientMonitoring_subscriber.exe -d 1
    PatientMonitoring subscriber sleeping up to 1 sec...
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 101}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 102}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 103}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    
  3. In the Wireshark capture, you should see a series of RTPS packets, as shown in the following screenshot. You can see the DDS data samples by looking at the serializedData field of DATA submessages. Since the current scenario does not load the Security Plugins, security is completely disabled and the payload can be decoded as ASCII plaintext.

    Figure 8.1 Wireshark capture of unprotected communication. The payload can be decoded as ASCII plaintext.

If we focus on the structure of captured packets, we can see that RTPS messages consist of a header and one or several submessages. In turn, every submessage has its header, metadata, and contents. In the previous screenshot, we can see a DATA submessage with some Flags in its header, then some metadata such as the writerEntityId, and finally, its serialized payload for the content. The following diagram outlines the structure of an unprotected RTPS packet.

Figure 8.2 Structure of an unprotected RTPS packet.

When our application uses security, the contents of the RTPS packets will show some differences. For example, cryptographic metadata will be added around the protected parts, which may be encrypted depending on the configured protection. For further details, see Securing DDS Messages on The Wire in the Security Plugins User’s Manual.

1

Recording on the loopback interface on a Windows system may require additional software (see How to capture traffic from the loopback interface using Wireshark in Windows from our Knowledge Base).

2

The screenshots in this Hands-On show the publisher and subscriber running on two different machines (with different IP addresses). We have edited the Resolved Name in Wireshark to better identify the applications. If the publisher and subscriber run on the same machine, you can still differentiate them by looking at the UDP ports.

8.2. Encrypting the Serialized Payload

In the previous section, you configured your DomainParticipants so they did not load the Security Plugins, making PatientMonitoring data vulnerable to eavesdropping and tampering attacks. In this section, we will analyze the effects that encrypting the payload has on the RTPS packets.

  1. Modify USER_QOS_PROFILES.xml to load the BuiltinQosLib::Generic.Security profile:

    <qos_profile name="Alice" base_name="BuiltinQosLib::Generic.Security" is_default_qos="true">
         <domain_participant_qos>
         ...
    

    Please note that this change affects both the publisher and subscriber applications.

  2. Make sure that this profile loads the Governance File that we defined in Hands-On 2: Defining Your System’s Security Requirements, which configures payload protection by setting the data_protection_kind to ENCRYPT.

8.2.1. Analyzing RTPS Packets in Wireshark

  1. Rerun your publisher and subscriber as explained in Running the Applications. Specify Domain 1 with the -d option in the command line. You should see communication:

    Publisher:

    $ ./objs/<architecture>/PatientMonitoring_publisher -d 1
    Writing PatientMonitoring, count 0
    Writing PatientMonitoring, count 1
    Writing PatientMonitoring, count 2
    Writing PatientMonitoring, count 3
    

    Subscriber:

    $ ./objs/x64Linux3gcc5.4.0/PatientMonitoring_subscriber -d 1
    PatientMonitoring subscriber sleeping up to 1 sec...
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 101}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 102}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 103}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    

    Publisher:

    $ ./objs/<architecture>/PatientMonitoring_publisher -d 1
    Writing PatientMonitoring, count 0
    Writing PatientMonitoring, count 1
    Writing PatientMonitoring, count 2
    Writing PatientMonitoring, count 3
    

    Subscriber:

    $ ./objs/x64Linux3gcc5.4.0/PatientMonitoring_subscriber -d 1
    PatientMonitoring subscriber sleeping up to 1 sec...
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 101}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 102}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 103}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    

    Publisher:

    > objs\<architecture>\PatientMonitoring_publisher.exe -d 1
    Writing PatientMonitoring, count 0
    Writing PatientMonitoring, count 1
    Writing PatientMonitoring, count 2
    Writing PatientMonitoring, count 3
    

    Subscriber:

    > objs\<architecture>\PatientMonitoring_subscriber.exe -d 1
    PatientMonitoring subscriber sleeping up to 1 sec...
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 101}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 102}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    PatientMonitoring subscriber sleeping up to 1 sec...
    [patient_condition: {heart_rate: 103}]
    PatientMonitoring subscriber sleeping up to 1 sec...
    
  2. Go back to Wireshark and look at the serializedData field of DATA submessages. You can check that the payload is now encrypted. Therefore it cannot be decoded as ASCII plaintext and trying to do so results in garbled output, as seen here:

    Figure 8.3 Wireshark capture of communication protected with data_protection_kind set to ENCRYPT. The payload is encrypted.

Notice that the length of the data field has increased. The reason is that the serializedData field now includes a header and a footer with cryptographic information. The CryptoHeader includes information such as an identifier for the key used to encrypt the payload. The CryptoFooter includes the generated message authentication code (MAC). This additional information allows the receiver to decrypt the message and verify its integrity. For further details, see Securing DDS Messages on The Wire in the Security Plugins User’s Manual.

You may also notice that the field named encapsulation options has changed to 0x0002. Although a CryptoHeader is now at the beginning of the serializedData, Wireshark does not have enough information to parse it. In fact, Wireshark does not know whether or not the serializedData is encrypted. For this reason, it always displays the encapsulation header (encapsulation kind and encapsulation options) at the beginning of the serializedData field. In this case, the payload is encrypted and these four bytes correspond to the transformation kind field in the CryptoHeader, where 0x00000002 means that the AES128 GCM transformation has been applied (the default for ENCRYPT).

The following diagram depicts the structure of an RTPS packet protected with payload encryption:

Figure 8.4 Structure of an RTPS packet with payload protection kinds, configured by the <data_protection_kind> rule.

Congratulations! You have verified that your payload is safe from a potential eavesdropper in your network.

8.3. Troubleshooting

  • My Wireshark captures are hard to read because message-type coloring is not active:

    Make sure that your Wireshark contains the coloring rules for the RTPS protocol (see How To configure Wireshark to show RTPS packets with specific colors from our Knowledge Base).

  • When I run the publisher/subscriber, they don’t communicate:

    Make sure that the Governance File is the same for both applications (publisher and subscriber). Otherwise, communication won’t work. Remember to sign the Governance File after modifying it and to restart your applications so changes take effect (see Signing the Governance File).

  • When I run the publisher/subscriber, I get this error:

    RTI_Security_AccessControl_create_participant:participant not allowed: no rule found; default DENY
    

    Make sure your applications are running in the allowed domain, in this case Domain 1 (requirement from Hands-On 3: Defining the DomainParticipant Permissions).

  • When I run the publisher/subscriber, I get this error:

    RTI_Security_AccessControl_validate_remote_permissions:failed to validate permissions
    

    Make sure both your publisher and subscriber have permissions signed by the same Permissions CA.

  • When I run the publisher/subscriber, I get this error:

    RTI_Security_AccessControl_get_participant_sec_attributes:failed to verify governance document signature
    

    Make sure that the Governance File has been signed by the right Permissions CA.

  • I cannot capture traffic from the loopback interface on a Windows system:

    Recording on the loopback interface on a Windows system may require additional software (see How to capture traffic from the loopback interface using Wireshark in Windows from our Knowledge Base).