.. include:: ../vars.rst

.. _chapter-cryptography:

************
Cryptography
************

Introduction
============

Cryptography is the process of making sure no adversaries can manipulate or
eavesdrop on communication. The |RTI_SP_PRODUCT| cover this process by means of the
|CryptoPlugin|. To prevent adversaries from manipulating messages, the
|CryptoPlugin| appends a message authentication code (MAC) to the message being
protected, therefore protecting its integrity. To prevent eavesdropping, the
|CryptoPlugin| can additionally encrypt the message, protecting its
confidentiality.

.. admonition:: Definitions

  The |CryptoPlugin| defines multiple protection levels that are applied to
  different parts of your communication. By **"protect a message"**, we refer to
  applying any of these protections to any particular part of your communication
  before sending it out. In other words, "to protect" implies "to perform the
  MAC cryptographic operations" -- when data integrity is protected; or "to
  perform the encrypt and MAC cryptographic operations" -- when both data
  integrity and data confidentiality are protected.

  On the receiver side, we will "validate" a message to verify it was not
  manipulated -- when data integrity is protected. We may also need to "decrypt"
  a message the sender protected against eavesdroppers -- when data
  confidentiality is protected. Therefore,
  **"validate (and potentially decrypt)"** is equivalent to "verify the MAC
  (and decrypt, only if the message was encrypted)".


With the |RTI_SP_PRODUCT|, you can specify a different level of protection to each of your
|TOPICs| (see :ref:`p2_core/elements_dds_secure_system:Topic-level rules`). For
example, you can protect the data integrity of a particular |TOPIC| by setting
the protection kind associated with that |TOPIC| to :xmlval:`SIGN` in the
|GovernanceDoc|. If the data sent on that |TOPIC| should also be protected from
potential eavesdropping, you can additionally protect its confidentiality by
setting its protection kind to :xmlval:`ENCRYPT`. This allows you to protect
each of your |TOPICs| with the level of protection that it requires. You can
also leave some of your |TOPICs| unprotected by setting its protection kind to
:xmlval:`NONE`, which could be useful to achieve compatibility with unsecure
parts of your system or to save resources.

.. note::

  In the case of |LIGHT_SP_BUILTIN|, which implements |SEC_SPEC_12|
  builtin PSK plugins, the |CryptoPlugin| does not support |TOPIC| level
  protection.
  Consequently, the sections in this chapter covering |TOPIC| level protection
  are only applicable to |SP_BUILTIN| or custom security plugins supporting
  |TOPIC| level protection.

|SecDPs|, |SecDWs|, and |SecDRs| use symmetric cryptography to protect the
messages they send. Each of these |SecEntities| is associated with different
cryptographic material, preventing unauthorized |Entities| from participating
in secure communication (see :ref:`p2_core/cryptography:Secure Entities`). For
example, when you create a |SecDW|, some keys are associated with it. We call
these keys |KeyMaterial|, and the contents of |KeyMaterial| are described in
:ref:`p2_core/cryptography:Local Sender's Key Material`. By only
sharing its |KeyMaterial| with authorized |DRs|, your |SecDW| makes sure that
only these |SecDRs| can read that information. This scheme, combined with the
fact that you can define different protection levels for your |DDS_ENTITIES|
based on DDS attributes (e.g., domain, topic name), provides granular security.

.. admonition:: Definitions

  Unless the documentation indicates differently, the keys (or |KeyMaterial|)
  associated with the |SecEntities| are considered to be
  |AXK|. |AXK| keys are
  exchanged after the authentication process is complete and allow granular
  security and topic-level protection. On the other hand, there are
  Pre-Shared keys (|PSK|), which are always distributed
  out-of-band to |SecDPs| (they are never associated with |SecDWs| or |SecDRs|)
  and they allow you to protect all traffic from the start-up of a |DDS_ENTITY|.
  For further details, see :ref:`p3_advanced/pre-shared_key:|PSKProtection|`.

The |CryptoPlugin| also puts in place a mechanism to prevent insiders from
pretending to be a different entity. For instance, consider a |DR| that
legitimately subscribes to a |DW| for a particular |TOPIC|. Since symmetric
encryption is used to protect data, the |DR| could potentially use the |DW|'s
key to send arbitrary samples, thus impersonating it. |DWs| can avoid this
situation by protecting samples with |OrigAuthProtection| (see
:ref:`p2_core/cryptography:Origin Authentication protection`).


Cryptography Plugin as an Enabler for Other Plugins
---------------------------------------------------

Protecting the confidentiality and integrity of data ensures that other
plugins can do their job correctly.

For example, the |AccessControlPlugin| will prevent your secure |DWs| from
sending samples to |DRs| that do not have permission to subscribe to a specific
|TOPIC|. However, if the |CryptoPlugin| does not enforce confidentiality by
encrypting your samples, malicious |DRs| could listen to the traffic on your
network, thus getting access to the data you wanted to protect and defeating
the purpose of Access Control. In this sense, the |CryptoPlugin| provides us
with the building blocks that enable other plugins to work properly. Access Control
decides whether an entity has permission to do something; Cryptography enforces
entities to meet this requirement.

The |AuthPlugin| interacts in a similar way with the |CryptoPlugin|. While the
|AuthPlugin| makes sure a participant is who it claims to be, it is the
|CryptoPlugin| that enforces that only authenticated participants have access to
the domain. The |CryptoPlugin| achieves this by protecting messages with
keys that have been only shared with successfully authenticated and
authorized participants.


Overview of How Cryptography Works in DDS
-----------------------------------------

To establish a DDS Secure communication, |SecEntities| (i.e., |SecDPs|,
|SecDWs|, and |SecDRs|) perform some cryptographic transformations based on some
security parameters and keys. |SecEntities| use symmetric cryptography to MAC
(and potentially encrypt) the information they protect. Therefore, a sender and
its matching receivers will use the same cryptographic material to communicate
securely. We will describe this in more detail in the section dedicated to
:ref:`p2_core/cryptography:Secure Entities`.

In order to exchange the keys that |SecEntities| need, mutually authenticated
participants establish an end-to-end channel to exchange sensitive cryptographic
material securely. This |SecKeyExchangeCh| allows your |SecDPs| to
confidentially exchange the |KeyMaterial| that |SecDWs| and |SecDRs| need to
communicate. We will describe this channel in more detail in
:ref:`p2_core/cryptography:Secure Key Exchange Channel (ParticipantVolatileMessageSecure topic)`.

|SecDWs| and |DRs| are not only used to protect the user-defined |TOPICs|. New secure builtin |EP| (|DWs| and |DRs|) will be created when you protect the discovery traffic or the liveliness assertions. More concretely, when you protect a |TOPIC|'s discovery information, your |DPs| will exchange the discovery information for that |TOPIC| through the |SecDiscoveryTopics|. You can also protect liveliness messages exchanged for |TOPICs| that have :value:`AUTOMATIC` or :value:`MANUAL_BY_PARTICIPANT` (see :ref:`p2_core/cryptography:enable_liveliness_protection (topic_rule)`). Protecting liveliness will result in your |DPs| exchanging these messages through the |SecLivelinessTopic| (see :ref:`p2_core/elements_dds_secure_system:Builtin Secure Liveliness Topic`). Note that these secure builtin |EPs| will coexist with their unsecure versions that will be used for |TOPICs| that aren't using Discovery/Liveliness Protection.

Protecting different parts of your communication implies that your messages
will have cryptographic transformations applied at different stages
(see :ref:`p2_core/cryptography:Security Protections Applied by DDS Entities`).
For example, |DataProtection| allows you to protect the samples published in a
particular |TOPIC|. You could also decide to protect the RTPS submessages for
that particular |TOPIC|. |SubmsgProtection| covers both :submsg:`DATA`
submessages -- which contain the (potentially already-protected) serialized
payload -- and submessages containing metadata, such as :submsg:`ACKNACK` and
:submsg:`HEARTBEAT` submessages (see
:link_connext_dds_pro_um:`Overview of the Reliable Protocol in the Core Libraries User's Manual <#users_manual/Overview_of_the_Reliable_Protocol.htm>`).
Finally, you could enable |RTPSProtection| to protect the complete RTPS
messages that your |DPs| put on the network. Note that the protections at
different stages are not mutually exclusive: the |CryptoPlugin| gives you the
flexibility to combine different levels of protection in the way that best fits
your security requirements. Also, applying cryptographic transformations at
different stages implies protecting different parts of the RTPS message, as
depicted in :numref:`Parts of the Message Protected by Each Protection Kind`.
For further details, see
:ref:`p2_core/cryptography:Securing DDS Messages on The Wire`.

.. figure:: ../static/protection-kinds.png
  :scale: 50%
  :name: Parts of the message protected by each protection kind
  :align: center

  Parts of the Message Protected by Each Protection Kind


The |CryptoPlugin| uses AES-GCM to protect the traffic (see
:ref:`Cryptographic Algorithms <p2_core/cryptography:Cryptographic Algorithms>`
for details). The AES-GCM transformation produces both the ciphertext and a
message authentication code (MAC) using the same secret key. This is sufficient
to protect the plaintext and ensure integrity. However there are situations where
multiple MACs are required. For example when a |DW| shares the same key with
multiple |DRs| and, in spite of this, the |DW| needs to ensure origin
authentication. In this situation the |DW| should create a separate
|RecSpecificKey| used only for authentication and append additional
|RecSpecificMACs|, each computed with one of the
|RecSpecificKeys| (see :ref:`p2_core/cryptography:Origin Authentication protection`).

Cryptographic Algorithms
========================

The |RTI_SP_PRODUCT| use different cryptographic algorithms for different purposes. Starting
with version 7.0.0, the user can modify and select algorithms supported and used
by |SecEntities|. This section describes the symmetric cipher algorithms
that can be configured in the |CryptoPlugin|.

In this section, we also describe the relationship between the algorithms that
can be configured in the |CryptoPlugin| and the
:link_connext_dds_api_cpp2:`ParticipantTrustAlgorithmInfo
<classrti_1_1topic_1_1trust_1_1ParticipantTrustAlgorithmInfo.html>` and
:link_connext_dds_api_cpp2:`EndpointTrustAlgorithmInfo
<classrti_1_1topic_1_1trust_1_1EndpointTrustAlgorithmInfo.html>` fields,
which are used to propagate the used and supported algorithms for a |DP|.
A complete list of values can be found in :numref:`SymmetricCipherBitValues`.

Note that a |SecEntity| may not propagate through discovery the exact list of
algorithms listed in the |GovernanceDoc|. The reason is that the final value
for a supported mask is an intersection of the algorithms allowed by the
|GovernanceDoc| and the list of algorithms supported by the |DP|. Remember that
the |GovernanceDoc| is about system-wide security requirements. Even if the
|GovernanceDoc| allows an algorithm, the implementation of the |RTI_SP_PRODUCT| for a
|DP| may not support it. For example, the |RTI_SP_PRODUCT| for wolfSSL may support different
algorithms than the |RTI_SP_PRODUCT| for OpenSSL.

Finally, this section also defines discovery defaults for every field of the
:link_connext_dds_api_cpp2:`ParticipantBuiltinTopicData::trust_algorithm_info
<classdds_1_1topic_1_1ParticipantBuiltinTopicData.html#aae52b29b4360c249ee6f2a4885d32735>`.
Discovery defaults are the values that are assumed when no value is propagated
through discovery see :ref:`p2_core/cryptography:Discovery of a remote Secure Entity`
for more details about discovery.

Participant Symmetric Cipher Algorithms
---------------------------------------

Participant Symmetric Cipher Algorithms collect algorithms used to encode
|DP| builtin |EP| traffic. The following algorithms are supported:

* AES-128-GCM
* AES-256-GCM

Participant Symmetric Cipher Algorithms specify three algorithm definitions:

* ``supported_mask``: A list of symmetric cipher algorithms supported by a |DP|.
  The default value includes AES-128-GCM and AES-256-GCM.
* ``builtin_endpoints_required_mask``: Indicates the algorithm the |DP| will use
  as the symmetric cipher algorithm to encode its protected builtin |EPs|'
  traffic. It is determined by the :property:`dds.sec.crypto.symmetric_cipher_algorithm`
  property (see :numref:`Properties for Configuring Cryptography Affecting Any Cryptography Plugin`).
  By default, it is set to AES-256-GCM.
* ``builtin_kx_endpoints_required_mask``: The algorithm used by the |DP|'s
  builtin |EPs| to encode key exchange traffic. The default is not set.
* ``user_endpoints_default_required_mask``: The default algorithm used by the |DP|'s
  |EPs| to encode user data traffic. If the |EPs|' symmetric cipher
  ``required_mask`` (see :ref:`p2_core/cryptography:Endpoint Symmetric Cipher Algorithms`)
  is not serialized on the wire, then the |RTI_SP_PRODUCT| assume that this is the algorithm
  used to protect the |EPs|' traffic.

Endpoint Symmetric Cipher Algorithms
------------------------------------
Endpoint Symmetric Cipher Algorithms collect algorithms used to encode
endpoints' traffic. The following algorithms are supported:

* AES-128-GCM
* AES-256-GCM

Endpoint Symmetric Cipher Algorithms specify two algorithm definitions:

* ``supported_mask``: A list of the symmetric cipher algorithms supported by the
  |EP|. This field is not propagated as part of the Endpoint Discovery process.
  It is also not populated as part of the builtin topic data
  :link_connext_dds_api_cpp2:`trust_algorithm_info
  <classdds_1_1topic_1_1PublicationBuiltinTopicData.html#a83849815467673e1df20e98236934887>`
  parameter in the
  :link_connext_dds_api_cpp2:`on_data_available
  <classdds_1_1sub_1_1AnyDataReaderListener.html#aa3b505b19d45572597c23fc38044a1fb>`
  callback. Instead, all bits of the mask are set by default (``0xffffffff``).
  When the builtin topic data is retrieved through the
  :link_connext_dds_api_cpp2:`matched_publication_data
  <namespacerti_1_1sub.html#a7e4857b568927b45359aa594157f9552>`
  or :link_connext_dds_api_cpp2:`matched_subscription_data
  <namespacerti_1_1pub.html#aef487efa6001f79dde9bb1485755d151>` APIs
  (depending on whether the |EP| is a |DW| or a |DR|) the field is populated
  with the information from the associated |DP|'s
  :link_connext_dds_api_cpp2:`supported mask
  <classrti_1_1topic_1_1trust_1_1ParticipantTrustInterceptorAlgorithmInfo.html#a3e2de49dc4d2066004df297662d04948>`.

* ``required_mask``: Indicates the algorithm the |EP| will use as the symmetric
  cipher algorithm to encode its traffic. It must be an algorithm that is
  propagated in the |DP| list of supported symmetric cipher algorithms. By default,
  it is set to AES-256-GCM. The symmetric cipher that an |EP| uses is
  determined by :property:`dds.sec.crypto.symmetric_cipher_algorithm` (see
  :numref:`Properties for Configuring Cryptography Affecting Any Cryptography Plugin`)

See :ref:`p2_core/cryptography:allowed_security_algorithms (domain_rule)` to
learn how to configure which of these algorithms are supported.

Secure Entities
===============

.. admonition:: Definition

  We will use the term |SecEntity| to refer to one of the following three |DDS_ENTITIES|:

  - |SecDW|: can perform |DataProtection| and/or |SubmsgProtection|.
  - |SecDR|: can perform |SubmsgProtection|.
  - |SecDP|: can perform |RTPSProtection|.

  In other words, a |SecEntity| is a |DW|, a |DR|, or a |DP| that has at least a protection kind different than :xmlval:`NONE` in its associated |GovRules|.

When a |SecDW| sends a sample to its matching |DRs|, it will protect the sample
by applying a cryptographic transformation (parametrized with a key). If, for
example, this is a reliable |TOPIC|, the |DRs| also need to send
:submsg:`ACKNACKs` to the |DW|, and these will be protected using the same
cryptographic transformation, but using different keys. As you can see, both
|DWs| and |DRs| need to send protected information to the other |EP|. In this
sense, we talk about Sender (the entity sending a secure message) and Receiver
(the entity receiving a secure message). Note that every |SecEntity| will have
its own Sender and Receiver. The Sender will protect the messages; the Receiver
will validate (and potentially decrypt) the messages.

To communicate with the other end, both the Sender and the Receiver will have a copy of the same |KeyMaterial|, from which we derive the key that is used by the cryptographic transformations. Each Sender will generate its own key to protect the outgoing messages; Receivers for that Sender will need the same key to validate (and potentially decrypt) the incoming messages. This |KeyMaterial| is securely exchanged between matching |SecEntities| through the |SecKeyExchangeCh|, as described in :ref:`p2_core/cryptography:Secure Key Exchange Channel (ParticipantVolatileMessageSecure Topic)`.

Architecture of Secure Entities
-------------------------------

|SecEntities| have some attributes (configuration) and mechanisms (algorithms)
that allow them to communicate securely. In addition, each |SecEntity| has a
Sender and a Receiver: the Sender handles the outgoing messages by protecting
them; the Receiver handles the incoming messages by validating (and potentially
decrypting) them.
|SecEntities| need to store and use keys as parameters for the cryptographic
algorithms. Upon its creation, each |SecEntity| generates the local Sender's
|KeyMaterial|. Receivers in matching |SecEntities| need a copy of this
|KeyMaterial| to validate (and potentially decrypt) the messages from this
Sender, as depicted in :numref:`Architecture Overview of Two Matching Secure
Entities`.

.. figure:: ../static/secure-entity-architecture.png
  :scale: 50%
  :name: Architecture Overview of Two Matching Secure Entities
  :align: center

  Architecture Overview of Two Matching |SecEntities|. **Important**: this
  figure is a simplified overview, |KeyMaterial| is never used directly to
  protect messages (|SessionKeys| derived from the |KeyMaterial| are used instead).


Security Mechanisms
^^^^^^^^^^^^^^^^^^^

To communicate securely, |SecEntities| need to perform operations that involve the |CryptoPlugin|. These operations include protecting the outgoing messages in the sender side and validating (and potentially decrypting) the incoming messages in the receiver side with the same symmetric key.

The key used by the cryptographic functions is a symmetric |SessionKey| with a limited lifetime. The |SessionKey| derives from cryptographic material generated by the Sender entity upon its creation, then sent to the Receiver upon discovery of the remote entity. The |SessionKey| is a temporary key that will be valid for a particular session and derives from the Sender's |KeyMaterial| and |SessionID|. The Sender will periodically change the |SessionKey| used to protect the messages by changing the |SessionID|. To let the Receiver know what |SessionKey| it needs to use, the Sender includes the |SessionID| in every protected message.


Security Attributes
^^^^^^^^^^^^^^^^^^^

The security attributes define what part of the messages will be protected by the Sender and how, i.e., what transformation is applied and how it changes the transmitted packets. Security attributes come from the |GovRules| that apply to this |TOPIC| and need to be the same in every |EP| for this |TOPIC| in the secure domain (see :ref:`p2_core/cryptography:Discovery of a Remote Secure Entity`). (|GovRules| are user-defined in the Governance Document, see :ref:`p2_core/elements_dds_secure_system:Governance Document`).

In the case of a |SecDW|, the security attributes define whether the Sender will protect the serialized data and/or the RTPS submessage. |SecDRs| are limited to protecting the outgoing RTPS submessage, while |SecDPs| can protect outgoing RTPS messages at the RTPS message level.

The security attributes also define whether the Sender will MAC the protected message or it will encrypt and MAC it. In either case, the Sender will use the |SessionKey| to protect the outgoing messages; matching Receivers will use this same |SessionKey| to validate (and potentially decrypt) the incoming messages.


Local Sender's Key Material
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Upon its creation, |SecEntities| generate the local Sender's |KeyMaterial|. The
local Sender uses this cryptographic material to communicate with the remote
Receivers securely. The local Sender's |KeyMaterial| includes:

* the |SenderKey|
* the |SenderKeyID|, which identifies the |SenderKey|
* the |TransformationKind|, which is the algorithm that the Sender uses for
  protecting its contents.

Cryptographic algorithms do not use the |SenderKey| directly to protect
communications. Instead, the Sender derives temporary |SessionKeys| from its
|SenderKey| (and other parameters from its |KeyMaterial|). Cryptographic
operations use these temporary keys to protect outgoing messages. These
messages also include the |SenderKeyID| to allow the Receiver to identify,
within all the |KeyMaterial| received from a remote |DP|, what |KeyMaterial|
was used to protect the message. Note that RTPS messages already contain the
|SecEntity|'s GUID that identifies the |DP| from which the message originated.
Additionally, the outgoing messages also include a |SessionID|, which allows
the Receiver to derive the right |SessionKey| by applying certain cryptographic
operations over the selected |SenderKey| (see
:numref:`Derivation of the Session Key and Receiver-Specific Session Keys`).

When |OrigAuthProtection| is enabled, one additional |RecSpecificKey| per Receiver (identified by the |RecSpecificKeyIDs|) are stored in the |SecEntity| along with the local Sender's |KeyMaterial|. This key is used to derive the |RecSpecificSessionKey|, which in turn is used as input to the cryptographic operation that computes the |RecSpecificMAC| of the outgoing messages.

Note that while the |SenderKey| does not change in the whole lifecycle of the |SecEntity|; the |SessionID| changes periodically (see :ref:`p2_core/cryptography:Secure Communication`).

.. figure:: ../static/derivation-session-keys.png
  :scale: 50%
  :name: Derivation of the Session Key and Receiver-Specific Session Keys
  :align: center

  Derivation of the |SessionKey| and |RecSpecificSessionKeys|


Remote Sender's Key Material
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The Receiver in the local |SecEntity| needs the remote Sender's |KeyMaterial| to validate (and potentially decrypt) messages coming from that remote Sender. Note this is the same |KeyMaterial| we introduced in :ref:`p2_core/cryptography:Local Sender's Key Material`, but from the Receiver's perspective. The local |SecEntity| will receive the remote Sender's |KeyMaterial| through the |SecKeyExchangeCh| after the two matching |SecEntities| discover and validate each other. The local Receiver derives the |SessionKey| from the remote Sender's |KeyMaterial| and the |SessionID| included in each message. Then, it uses the |SessionKey| to validate (and potentially decrypt) incoming messages (see :ref:`p2_core/cryptography:Secure Communication`).

When the Receiver gets a message from the network, it takes the |SenderKeyID| and the remote |SecEntity|'s GUID from the RTPS message. With this information, the Receiver can identify the |SenderKey| that the Sender used to protect the message from the list of its received keys. Then, it uses the |SessionID|, also included in the protected message, to compute the |SessionKey|. Finally, the Receiver uses the |SessionKey| to validate (and potentially decrypt) the message.

When |OrigAuthProtection| is enabled, an additional |RecSpecificKey| is assigned to the local Receiver. This key is identified by the |RecSpecificKeyID| and is stored as part of the remote Sender's |KeyMaterial|. This key is used to derive the |RecSpecificSessionKey|, which in turn is used to verify the |RecSpecificMAC| of the incoming messages.

.. figure:: ../static/key-material-sender.png
  :scale: 50%
  :name: Key Derivation in the Sender
  :align: center

  Key Derivation in the Sender. The |KeyMaterial| is stored in the |SecEntity|.


.. figure:: ../static/key-material-receiver.png
  :scale: 50%
  :name: Key Derivation in the Receiver
  :align: center

  Key Derivation in the Receiver. The |KeyMaterial| stored in the |SecEntity| is identified with the |SenderKeyID|, present in the incoming message.


Lifecycle of Secure Entities
----------------------------

Creation of the Secure Entity
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Upon the creation of a |SecEntity|, the local |SenderKey| is generated and stored locally. This is done after the checks from the |AccessControlPlugin|, which verifies that the |Entity| has permission to do what it's being created for. Refer to :ref:`p2_core/cryptography:Local Sender's Key Material` for further details on the generated cryptographic material.


Discovery of a Remote Secure Entity
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

To successfully discover, |DPs| need to have a compatible configuration for the
participant security attributes. A compatible configuration involves
having the same |RTPSProtection| kind, the same |DiscoveryProtection|, and the
same |LivelinessProtection|.

The same logic applies to |SecEPs| and the endpoint security attributes. To
communicate, two matching |SecEPs| (a |SecDW| and a |SecDR|) need to present the
same |GovRules| for the |TOPIC| of these |SecEPs|.

To support these Governance compatibility checks, when you enable security,
|CONNEXT| sends additional properties as part of the discovery information.
These properties support making matching decisions. For further details, see
:ref:`p2_core/elements_dds_secure_system:Governance Compatibility Validation`.

|SecDPs| propagate information about their supported and used cryptographic
algorithms during discovery. This information is used to determine matching
between |DPs|, matching between |EPs|, and for early detection of configuration
issues. The information that |SecDP| propagate during discovery about their
cryptographic algorithms has the purpose of optimizing discovery traffic
(do not match with |DPs| that do not support your local security algorithms) and
improving debuggability. They are for improving system deployability and making
it easier to detect configuration errors; they are not to enforce security.

|DPs| propagate information about cryptographic algorithms in the following
:abbr:`PIDs (Parameter Identifiers)`:

* Digital Signature Algorithms: ``PID_PARTICIPANT_SECURITY_DIGITAL_SIGNATURE_ALGO``.
* Key Establishment Algorithms: ``PID_PARTICIPANT_SECURITY_KEY_ESTABLISHMENT_ALGO``.
* Symmetric Cipher Algorithms: ``PID_PARTICIPANT_SECURITY_SYMMETRIC_CIPHER_ALGO``.
* Endpoint Symmetric Cipher Algorithms: ``PID_ENDPOINT_SECURITY_SYMMETRIC_CIPHER_ALGO``.

If any of the PID values are set to defaults, or if security is disabled, they
are not propagated. The defaults are compatible with previous |RTI_SP_PRODUCT| releases;
communication with earlier releases is not affected. For detailed information
about supported and default cryptographic algorithms, see
:ref:`p2_core/authentication:Cryptographic Algorithms` in the "Authentication"
chapter and :ref:`p2_core/cryptography:Cryptographic Algorithms` in the
"Cryptography" chapter.

Each of these PIDs transmits the following information:

* ``PID_PARTICIPANT_SECURITY_DIGITAL_SIGNATURE_ALGO``: This PID has the
  authentication and the identity trust chain digital signature algorithms.
  The masks are as follows:

    * ``message_auth.supported_mask``
    * ``message_auth.required_mask``
    * ``trust_chain.supported_mask``
    * ``trust_chain.required_mask``

* ``PID_PARTICIPANT_SECURITY_KEY_ESTABLISHMENT_ALGO``: This PID contains a
  supported mask and a required mask for the key establishment algorithms.

    * ``shared_secret.supported_mask``
    * ``shared_secret.required_mask``

* ``PID_PARTICIPANT_SECURITY_SYMMETRIC_CIPHER_ALGO``: This PID contains the
  following masks. The local |DP| only checks that the value of these masks is
  compatible when protection is enabled at the RTPS level (see
  :ref:`p2_core/cryptography:RTPS Protection`).

    * ``supported_mask``: mask of supported algorithms that affects all
      endpoints.
    * ``builtin_endpoints_required_mask``: mask of required algorithms that
      affects all builtin endpoints besides the key exchange one.
    * ``builtin_kx_endpoints_required_mask``: mask of required algorithms that
      affects only the key exchange builtin endpoints.
    * ``user_endpoints_default_required_mask``: mask indicating the default
      algorithm used by the |DP|'s |EPs| to encode user data traffic. This
      algorithm is assumed to be used by |EPs| that do not send the
      ``PID_ENDPOINT_SECURITY_SYMMETRIC_CIPHER_ALGO`` PID.

* ``PID_ENDPOINT_SECURITY_SYMMETRIC_CIPHER_ALGO``: This PID contains a required
  mask with the algorithms that the remote |EP| must support. The algorithms
  that the local |EP| supports are not part of this PID. They are derived from
  the algorithms that the |DP| supports (PID in the previous bullet-point).

Two |SecEntities| are compatible with respect to their cryptographic algorithms
if their supported and required masks are compatible. Compatibility between a
supported and required mask depends on whether the highest bit of the required
mask is set. The |RTI_SP_PRODUCT| define the highest bit with a name of
`RTI_SECURITY_CRYPTO_ALGORITHM_INFO_BIT_COMPATIBILITY_MODE` and its value is the
result of the bitwise AND operation between the required mask and ``0x1 << 31``.
If the highest bit is set, it means that the masks are compatible
as long as they intersect (one of the other bits is set in both). If the
highest bit is not set, it means that all required algorithms must be supported.

In this version of the |RTI_SP_PRODUCT|, the
`RTI_SECURITY_CRYPTO_ALGORITHM_INFO_BIT_COMPATIBILITY_MODE` bit is only used as
part of the ``trust_chain.required_mask``. In the context of the identity trust
chain, the local |DP| doesn't have to support all of the digital signature
algorithms from the remote |DP|. One algorithm is enough (as long as it's one
of the algorithms defined in the |SEC_SPEC|, or it's a
vendor-specific algorithm but the local and remote |DPs| are from
the same vendor). This is because the chain is not always validated completely,
since any of the intermediate certificates in the |IdentityCert| might be signed by
the Identity CA. As a result, two |DPs| can match but still result in error
during validation of the |IdentityCert|.

The `RTI_SECURITY_CRYPTO_ALGORITHM_INFO_BIT_COMPATIBILITY_MODE` bit is ignored
in the ``message_auth.supported_mask``, ``message_auth.required_mask``,
``shared_secret.supported_mask``, ``shared_secret.required_mask``,
and the three symmetric cipher algorithm masks.
In the case of the authentication digital signature algorithms, the remote |DP|
computes a signature using the algorithm specified in its
``message_auth.required_mask``. The local |DP| must support it in order to
verify the signature, and confirm its authenticity. The same requirement is also
true for symmetric cipher algorithms.
Regarding key establishment algorithms, two |DPs| will use the preferred key
establishment algorithm from the |DP| that is the authentication initiator. In
that sense, we could argue that it is enough to do the intersection of the
initiator participant ``shared_secret.required_mask`` and the non-initiator
``shared_secret.supported_mask`` to determine key establishment algorithm
compatibility. The rationale for doing the matching for both |DPs|'
``shared_secret.required_mask`` and ``shared_secret.supported_mask``
is to make sure systems behave consistently independently of who is the
initiator |DP| (i.e., independently of the assigned |DP|'s GUIDs): if
communication would fail depending on who is the initiator, the
key establishment algorithm configuration is determined to be incompatible.

Key Material Exchange
^^^^^^^^^^^^^^^^^^^^^

Once the |SecEntities| have fully matched (same |TOPIC|, same type, compatible QoS, same security attributes) and permissions are checked, they exchange the |KeyMaterial| through the |SecKeyExchangeCh|.

Each of the |SecEntities| will register the local Sender's |KeyMaterial| and the remote Sender's |KeyMaterial| (that is received through the |SecKeyExchangeCh|). As specified in :ref:`p2_core/cryptography:Creation of the Secure Entity`, the common part of the local Sender's |KeyMaterial| is generated upon the entity creation.

When |OrigAuthProtection| is enabled, the |RecSpecificKeyMaterial| is also exchanged. In this case, the local |DP| maintains a list with the |RecSpecificKeys| that correspond to the discovered |SecEntities|. Since |Entities| in the same |DP| run in the same application memory space, a single |RecSpecificKey| is assigned to every |SecEntity| in a remote |DP|.

For further details on |KeyMaterial| Exchange, see :ref:`p2_core/cryptography:Secure Key Exchange`.


Secure Communication
^^^^^^^^^^^^^^^^^^^^

At this point, the |SecEntities| can communicate securely.

The Sender will add additional information in the outgoing messages so the Receiver can validate (and potentially decrypt) them. This includes the |SenderKeyID| and the |SessionID|. The message will also contain the MAC (a.k.a. the |CommonMAC|), and the |RecSpecificMACs| when |OrigAuthProtection| is enabled.

:numref:`Reception of a Secure Message` depicts the process of receiving a secured incoming message. Details on how the communication is protected on the wire are covered in :ref:`p2_core/cryptography:Cryptographic Information Added to RTPS Messages`.

.. figure:: ../static/reception-secure-msg.png
  :scale: 55%
  :name: Reception of a Secure Message
  :align: center

  Reception of a Secure Message


Algorithms Involved in Protecting Secure Entities Traffic
---------------------------------------------------------

Senders use AES-GCM to encrypt and MAC messages when the :xmlval:`ENCRYPT`
protection kind is in use. Alternatively, when the :xmlval:`SIGN` protection
kind is configured, Senders use AES-GMAC to MAC-only data. On the counterpart
side, Receivers use the same algorithms to validate the MAC of (and potentially
decrypt) incoming data. Note that AES-GMAC transformation is a particular case
of AES-GCM, which produces only a MAC and leaves the input message unencrypted.

AES-GCM can operate with 128-bit and 256-bit keys (see
:property:`dds.sec.crypto.symmetric_cipher_algorithm` in
:numref:`Properties for Configuring Cryptography Affecting Any Cryptography Plugin`).
Regardless of the key size, AES-GCM always operates in 128-bit (16-byte) blocks.
Hence, all the MACs are 128-bit (16-byte) long.

AES-GCM requires a symmetric key and an initialization vector to operate. In
|SP_BUILTIN| and |LIGHT_SP_BUILTIN|, the |SessionKey| is used as the symmetric
key, while the |IV| is the
concatenation of the |SessionID| and the so-called |IVsuffix|.

The same |IV| is associated with all the session keys of a specific Sender,
including the common |SessionKey| and all the |RecSpecificSessionKeys|. The
|IVsuffix| is incremented each time any of these keys are used to encrypt
and/or compute a MAC.

The |SessionID| and |IVsuffix| are sent as part of the protected message,
allowing the Receiver to derive the |SessionKey| and the |RecSpecificKey| that
it will use to validate (and potentially decrypt) the received messages.

As stated in the |SEC_SPEC|, the use of (Galois) counter mode
allows authenticated decryption of blocks in an arbitrary order. All that is
needed to decrypt and validate the authentication tag are the |SessionKey| and
the |IV|. This is very important for DDS because a |DR| may not receive all the
samples written by a matched |DW|. The use of DDS ContentFilteredTopics as well
as DDS QoS policies such as History (with :value:`KEEP_LAST` kind), Reliability
(with :value:`BEST_EFFORT` kind), Lifespan, and TimeBasedFilter, among others,
can result in a |DR| receiving a subset of the samples written by a |DW|.


Limiting the Usage of a Specific Session Key
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The |SessionBlockCounter| is an internal counter that keeps track of the number of blocks protected with the same |SessionKey|. Note that GCM uses 128-bit blocks. The purpose of this counter is to ensure that a single |SessionKey| is not used to protect more than the maximum blocks per session, as configured by the :property:`cryptography.max_blocks_per_session` property (see :numref:`|RTI_SP_PRODUCT_HEADING| Properties for Configuring Cryptography`). The |SessionBlockCounter| and the size of the plaintext are used to ensure that :property:`cryptography.max_blocks_per_session` will not be exceeded during the encode operation. If the encode operation detects that the counter would exceed the maximum then it will modify the |SessionID| (and derive new session keys) prior to transforming any of the input plaintext.

The change in the |SessionID| triggers the creation of new session keys, randomizes the |IVsuffix|, and resets the |SessionBlockCounter|.

Since the original |KeyMaterial| (see :ref:`p2_core/cryptography:Local Sender's Key Material`) stays the same even after creating new session
keys, this mechanism is not useful for removing |DPs| from the system. The next
section describes the mechanism that may be used for that purpose.


Limiting the Usage of Specific Key Material
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

In order to prevent removed remote |DPs| from processing encoded traffic from
the local |DP|, the local |DP| must ensure that the remote |DPs| do not have the
|KeyMaterial| to decode that traffic. And in order to prevent removed malicious
remote |DPs| from impersonating trusted |DPs| by using previously received
|KeyMaterial| to do message authentication, the local |DP| must change its
|KeyMaterial| and tell its peers to use the new |KeyMaterial| in place of the
old one when authenticating messages. The |RTI_SP_PRODUCT| add all of this functionality to
``banish_ignored_participants``. When this method is called, the local |DP|
creates a |KeyRevision|. A |KeyRevision| represents a revision of the
|KeyMaterial| used by the local |DP| and its contained |DR| and |DW| entities.
After sending the |KeyRevision| to currently legitimate remote |DPs| via the
|SecKeyExchangeCh| and receiving acknowledgments that the |KeyRevision| was
received, the local |DP| may **activate** the |KeyRevision|. When a
|KeyRevision| is activated, the new |KeyMaterial| becomes the |KeyMaterial|
that is used for encoding new content. Then, this new content will become
indecipherable by remote |DPs| that have been removed, while still being
decipherable by currently legitimate remote |DPs|. And this new |KeyMaterial|
will be distinguishable from the old |KeyMaterial|, which illegitimate remote
|DPs| may still possess, so a successful message authentication will actually
be trustworthy.

``banish_ignored_participants`` will still create a new |KeyRevision| even if
there are no new removed |DPs| since the last time
``banish_ignored_participants`` was called.

Since |RecSpecificKeys| are only shared with a subset of trusted receivers and
since they are always used in combination with the new |KeyMaterial|, there is
no need to regenerate |RecSpecificKeys|.

|KeyRevisions| are enabled by default. A |DP| that sets :xmltag:`enable_key_revision`
|GovRule| to :xmlval:`false` will not communicate with a |DP| that sets this
|GovRule| to :xmlval:`true` or with a |DP| of a release older than the |CONNEXT_700Version|
|RTI_SP_PRODUCT|, unless :xmltag:`allow_unauthenticated_participants` is set to :xmlval:`true`.
In this case, the two |DPs| may communicate either unsecurely or using exclusively |PSKProtection|.
This happens because on enabling |KeyRevisions|, the contents of the |CryptoHeader| (see
:ref:`p2_core/cryptography:Cryptographic Information Added to RTPS Messages`)
become different. The Core Libraries check the compatibility of
:xmltag:`enable_key_revision` at
|DP| discovery time, which is when it checks for Governance
compatibility in general (see
:ref:`p2_core/elements_dds_secure_system:Governance Compatibility Validation`).

.. note::

  * In the case of |LIGHT_SP_BUILTIN|, which implements |SEC_SPEC_12|
    builtin PSK plugins, |KeyRevisions| are not applicable (as there is no
    |KeyMaterial| exchanged through the wire). Still, the |PSK| (distributed
    out-of-band) is mutable and can be updated at runtime in order to securely
    stop communication with newly-untrusted |DPs|.
  * A |LIGHT_SP_BUILTIN| |DP| can communicate with a |SP_BUILTIN| |DP| that enables key
    revision if both |DPs| are configured to meet interoperability requirements
    detailed in :ref:`p3_advanced/pre-shared_key:|LIGHT_SP_BUILTIN_HEADING| and |SP_BUILTIN_HEADING| Interoperability`.

Automatically Banishing Ignored Participants
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

While you may call the ``banish_ignored_participants`` method whenever you want
to, you may not always know when you should call it. To help solve this
problem, the |RTI_SP_PRODUCT| will automatically introduce a new |KeyRevision| under
a set of reasonable circumstances.

As described in :ref:`p2_core/authentication:Dynamic Certificate Revalidation`,
if a |DP| that you are currently communicating with suddenly has its certificate
revoked or expired, then the |RTI_SP_PRODUCT| will stop communicating with it and create a
new |KeyRevision|.

But what if this sudden invalidation of a certificate happens to a |DP| that
you were **formerly** communicating with? How do the |RTI_SP_PRODUCT| keep track of |DPs|
that you are no longer communicating with? This is where the
:property:`dds.participant.trust_plugins.max_removed_participants_per_key_revision`
property comes into play. When you set this property to a value other than
:value:`0`, the |RTI_SP_PRODUCT| will keep a minimum state associated with this number of
remote |DPs| after you stop communicating with them and after the database
thread removes the deleted remote |DP| records. The |RTI_SP_PRODUCT| will automatically
introduce a new |KeyRevision| and purge all of the elements in this minimum
state when either of the following occurs:

* The number of remote |DPs| in this state is about to exceed the limit set by
  :property:`dds.participant.trust_plugins.max_removed_participants_per_key_revision`.
* Any of the |DPs| in this state has its certificate invalidated (e.g., revoked
  or expired).

In addition, the minimal state is purged whenever a new |KeyRevision| is
introduced for any reason.

The |RTI_SP_PRODUCT| use this mechanism to ensure that removed remote |DPs| whose
certificates are invalidated after their removal are properly banished. As you
would expect, if you set the property to :value:`0`, then the |RTI_SP_PRODUCT| will
automatically create a new |KeyRevision| whenever you stop communicating with
any remote |DP|, and therefore the |RTI_SP_PRODUCT| will have no need to keep this minimal
state. So this property empowers you to balance the overhead of frequent
banishments with the overhead of this minimal state. See
:ref:`p2_core/cryptography:Configuration Properties Affecting Any Cryptography Plugin`
for the memory footprint of this minimal state.


Secure Key Exchange Channel (ParticipantVolatileMessageSecure Topic)
====================================================================

In order to perform key exchange between |SecEntities|, |DPs| need to send directed messages to each other using a reliable and secure channel. These messages are intended only for participants that are currently in the system and therefore use a DURABILITY QoS of kind :value:`VOLATILE`. The |SEC_SPEC| introduces a new |SecKeyExchangeT|, also known as the |SecKeyExchangeTName| builtin |TOPIC|, to exchange these messages.


Secure Key Exchange Builtin Topic Characteristics And Security Attributes
-------------------------------------------------------------------------

The purpose of the |SecKeyExchangeT| is to reliably and securely transport the
|KeyMaterial| between the |SecEntities| of different |DPs|. This |TOPIC| uses a
RELIABILITY QosPolicy of kind :value:`RELIABLE` and a HISTORY QosPolicy of kind
:value:`KEEP_ALL` to make sure that keys get to the remote |SecEntity|. Also, a
DURABILITY QosPolicy of kind :value:`VOLATILE` is used to prevent sending data
to unauthorized late joiners. Finally, to protect the confidentiality of
messages sent on this channel, the |SecKeyExchangeEPs| use encryption as the
|SubmsgProtection|.

The |SecKeyExchangeCh| requires a |SecDW| and a |SecDR| in both the local
participant (|P1|) and the remote participant (|P2|). The |KeyMaterial| that
allows a |DW| and its matching |DRs| to communicate securely is normally
exchanged through this |SecKeyExchangeCh|. The only exception is the
|KeyMaterial| used by this channel's |SecEPs|, a |SharedKey| that will derive
from the information resulting from the authentication process. More concretely,
the |SharedKey| is derived using HMAC operations on the Challenges exchanged in
the Handshake and the |SharedSecret| that results from the authentication
process. For more information on these parameters, see
:ref:`p2_core/authentication:Handshake`.

The |KeyMaterial| derived for the |SecDW| and |DR| is identical. Nonetheless,
since only |P1| and |P2| know the |SharedKey|, this cryptographic material is
unique for |P1| and |P2|. In other words, this is a direct channel between |P1|
and |P2|. That means that if there were a third participant (|P3|) in the
system, there would be different keys for communicating between |P1| and |P3|.
So a |SharedKey| is particular to a single authentication session between a
pair of |DPs|. Hence, if somehow |P2| loses liveliness and |P1| cleans the state
associated with |P2|, and then |P1| rediscovers |P2|, they will end up with a
different |SharedKey|.


Secure Key Exchange
-------------------

Once the |SecKeyExchangeCh| is established, the |KeyMaterial| for every other |SecEntity| is exchanged through it. This |KeyMaterial| includes the |TransformationKind|, |SenderKey| and |SenderKeyID|, as well as the |RecSpecificKey| (see :ref:`p2_core/cryptography:Architecture of Secure Entities`).

If |KeyRevisions| are enabled (see
:ref:`p2_core/cryptography:Limiting the Usage of Specific Key Material`), then
the most recent |KeyRevisions| are also exchanged between the |DPs|.
This exchange gives the receiving side the ability to decode historical data
from the sending side. See
:ref:`p2_core/cryptography:Reencoding Protected Data when Regenerating Keys`
for more details.

|DPs| use this |TOPIC| to exchange the |KeyMaterial| that will be used to protect outgoing RTPS messages (when |RTPSProtection| is enabled). After that, |DPs| exchange the |KeyMaterial| for the builtin |SecEPs|, including the |SecPublicationDW| and |DR| used for Secure |EP_disc| (see :ref:`p2_core/elements_dds_secure_system:Security Builtin Topics`). Once your |DPs| have exchanged the keys for the builtin |SecEPs|, they can perform secure discovery, and once they discover particular user-defined |DWs| and |DRs|, the participants will also use this channel to exchange the keys for those |EP|.

More concretely, during |EP_disc|, two mutually authenticated participants (|P1| and |P2|) will send publication and subscription :submsg:`DATA` messages to inform their counterpart about their local |DWs| and |DRs|. When |P1| discovers that |P2| has a |DR| (|DR2|) matching a local |DW| (|DW1|), |P1| will register |DR2| as a remote endpoint. If |OrigAuthProtection| is enabled, |P1| will assign |DR2| |RecSpecificKeyMaterial|. After this, |P1| will send |DW1|'s local Sender |KeyMaterial| through the |SecKeyExchangeCh|. This message will include |DR2|'s |RecSpecificKeyMaterial|. |P2| will follow the same process: register |DW1|, assign it some |RecSpecificKeyMaterial| (if |OrigAuthProtection| is enabled), and send |DR2|'s local Sender |KeyMaterial| to |P1|. At this point, |DW1| and |DR2| have all the cryptographic material that they need to communicate securely (see :ref:`p2_core/cryptography:Local Sender's Key Material`).


Secure Key Redistribution
-------------------------

Suppose that while |DW1| and |DR2| are communicating, a third |DP|
(|P3|) and its |DR| (|DR3|) join the system. |DW1| communicates with |DR3| for
a while, but then |P1| decides that |P3| is no longer trustworthy, so |P1|
calls ``ignore_participant`` on |P3| and then calls
``banish_ignored_participants``
(see :ref:`p2_core/cryptography:Limiting the Usage of Specific Key Material`).
This call creates a new |KeyRevision| that is shared by **both** |P1|
**and** |DW1|, as well as by any of |P1|'s secure builtin endpoints. |P1| sends
sends this |KeyRevision| to |P2| over the |SecKeyExchangeCh|. While |P1| waits
for |P2| to acknowledge the |KeyRevision|, |P1| still uses its old
|KeyMaterial| to protect outgoing RTPS messages, and |DW1| still uses its old
|KeyMaterial| to protect its outgoing RTPS submessages and data payloads. As
soon as |P1| receives an acknowledgment for the |KeyRevision|, |P1| activates
the |KeyRevision|, and |P1| and |DW1| both use the same |KeyRevision| to derive
new |KeyMaterial| from their respective old |KeyMaterial|. Then, |P1| and |DW1|
both start using their new |KeyMaterial|.

If there is a fourth |DP| (|P4|, which is still trusted) in the system, and
|P4| takes too long to acknowledge the |KeyRevision|, then |P1| will remove
|P4| from its list of legitimate remote participants. You can configure the
timeout for this removal using
:property:`dds.participant.trust_plugins.max_key_redistribution_delay.sec`.
After |P1| removes |P4|, |P1| will activate the |KeyRevision|.

If |P1| calls ``banish_ignored_participants`` while still waiting to activate
the previous |KeyRevision|, then ``banish_ignored_participants`` will not
block. Instead, the Event thread (see
:link_connext_dds_pro_um:`Event Thread in the Core Libraries User's Manual <#users_manual/Event_Thread.htm>`)
will check every one second if the previous |KeyRevision| has been activated.
When it is activated, the Event thread will create and send the new
|KeyRevision|.


Securing DDS Messages on The Wire
=================================

When sending a protected message, some cryptographic information is added. The
following sections describe the details of the cryptographic information
(:ref:`p2_core/cryptography:Cryptographic Information Added to RTPS Messages`),
as well as the effect of different protection kinds on what gets sent on the
wire
(:ref:`p2_core/cryptography:RTPS Protocol Changes to Support Secure Entities Traffic`).


RTPS Protocol Changes to Support Secure Entities Traffic
--------------------------------------------------------

In the RTPS protocol, the main component is the RTPS message. RTPS messages have a header containing information about the sending entity, and have different units of information that are divided into submessages. In turn, each submessage has a header and its own elements. For example, a submessage can contain user data; it will have a data header and then contain your user data. Other submessages could contain metadata needed in DDS, such as :submsg:`HEARTBEATs`, :submsg:`ACKNACKs`, etc. To sum up, inside a single RTPS message you can have multiple submessages with different bits of information (see :numref:`General Structure of an RTPS Message`).

Depending on the protection kind, different parts of the message will be protected.

.. figure:: ../static/rtps-msg-structure.png
  :scale: 55%
  :name: General Structure of an RTPS Message
  :align: center

  General Structure of an RTPS Message


Serialized Data Protection
^^^^^^^^^^^^^^^^^^^^^^^^^^

You can enable |DataProtection| by setting the :xmltag:`data_protection_kind` |GovRule| to a value other than :xmlval:`NONE` (see :ref:`p2_core/cryptography:data_protection_kind (topic_rule)`).

|DataProtection| only applies to the Sender in the |DW|. If not batching, the
|DW| protects the sample payload right after the serialization. If batching, the
|DW| protects the entire batch right before the flush. The protected sample or
batch (including the MAC and potentially being encrypted) is stored in the
|DW|'s queue until sent. When resending samples (for instance, for sending
repairs), the sample is already in the |DW|'s queue, so additional cryptographic
operations are not needed (see 
:ref:`p3_advanced/design_considerations:Interaction Between the |RTI_SP_PRODUCT_HEADING| and Batching QoS`).

.. note::

  |SecDWs| can only communicate with compatible |SecDRs|, as described in :ref:`p2_core/cryptography:Discovery of a remote Secure Entity`. In other words, secure and unsecure |EPs| cannot communicate.


From an RTPS point of view, the |DataProtection| only protects the payload inside the :submsg:`DATA` submessages. Therefore, the Serialized Payload now becomes a |CryptoHeader|, a |SerializedPayload|/|CryptoContent| element, and a |CryptoFooter|, as :numref:`RTPS Message Transformation with Serialized Data Protection` depicts. Note that the |SerializedPayload| element (unchanged from input) is used when only protecting data integrity (:xmltag:`data_protection_kind` = :xmlval:`SIGN`); the |CryptoContent| element (encrypted |SerializedPayload|) is used when also protecting data confidentiality (:xmltag:`data_protection_kind` = :xmlval:`ENCRYPT`). Also, note that the submessage structure (and number) is not modified.

.. figure:: /../shared_content/static/data-protection.png
  :scale: 50%
  :name: RTPS Message Transformation with Serialized Data Protection
  :align: center

  RTPS Message Transformation with |DataProtection|


Instance Key Data Protection
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

**If not batching**, then |DataProtection| is also applied to instance key data. If
you set
:link_connext_dds_api_cpp2:`DATA_WRITER_PROTOCOL QosPolicy's serialize_key_with_dispose <classrti_1_1core_1_1policy_1_1DataWriterProtocol.html#a925e93c037dd5d7885355d1bec26ceaa>`
to :value:`TRUE`, then instance key data will get sent with dispose samples, so
it has to be protected. The protection is applied when you register the
instance, and the protected instance key data is stored in the |DW|'s queue.
Consequently, no additional cryptographic operations are needed when sending
dispose samples, and a decoding operation is needed if the |DW| calls
``get_key_value``.

**If batching**, then |DataProtection| is not applied to instance key data because
|DataProtection| is already applied to the entire batch, so there is no need
for further cryptographic operations on the instance key data. Consequently, no
additional cryptographic operations are needed if the |DW| calls
``get_key_value``.


Submessage Protection
^^^^^^^^^^^^^^^^^^^^^

You can enable |SubmsgProtection| by setting the :xmltag:`metadata_protection_kind` |GovRule| to a value other than :xmlval:`NONE` (see :ref:`p2_core/cryptography:metadata_protection_kind (topic_rule)`).

|SubmsgProtection| applies to messages sent both by the |DW| and the |DR|. The |SecEP| will protect the following types of RTPS submessages right before putting them in the wire.

* :submsg:`AckNack`
* :submsg:`AppAck`
* :submsg:`AppAckConf`
* :submsg:`Data`
* :submsg:`DataBatch`
* :submsg:`DataFrag`
* :submsg:`DataSession`
* :submsg:`Gap`
* :submsg:`Heartbeat`
* :submsg:`HeartbeatFrag`
* :submsg:`HeartbeatVirtual`
* :submsg:`NackFrag`


.. note::

  |SecDWs| can only communicate with compatible |SecDRs|, as described in :ref:`p2_core/cryptography:Discovery of a remote Secure Entity`. In other words, secure and unsecure |EPs| cannot communicate.


From an RTPS point of view, |SubmsgProtection| protects the submessages by prepending a Secure Prefix Submessage (:submsg:`SEC_PREFIX`) -- which contains the |CryptoHeader| -- to the Secure Body Submessage (:submsg:`SEC_BODY`) -- which contains the |CryptoContent|. It also appends a Secure Postfix Submessage (:submsg:`SEC_POSTFIX`) -- which contains the |CryptoFooter|. Therefore, the submessage becomes :submsg:`SEC_PREFIX` + :submsg:`SEC_BODY` + :submsg:`SEC_POSTFIX`, as the following diagram depicts.

Note that the number of RTPS submessages increases, but the overall RTPS message structure is not modified.

.. figure:: ../static/submsg-protection.png
  :scale: 50%
  :name: RTPS Message Transformation with Submessage Protection
  :align: center

  RTPS Message Transformation with |SubmsgProtection|


RTPS Protection
^^^^^^^^^^^^^^^

You can enable |RTPSProtection| by setting the
:xmltag:`rtps_protection_kind` or the :xmltag:`rtps_psk_protection_kind`
|GovRules| to a value other than :xmlval:`NONE`
(see :ref:`p2_core/cryptography:rtps_protection_kind (domain_rule)` and
:ref:`p2_core/cryptography:rtps_psk_protection_kind (domain_rule)`).

|RTPSProtection| affects the |DP| and applies to every packet [#]_ that is sent
by protecting the whole RTPS message right before putting it on the network.

The resulting protected packet will consist of an :submsg:`SRTPS Prefix` [#]_
-- which contains the |CryptoHeader| -- followed by an :submsg:`SRTPS Body`
-- which contains the |CryptoContent| -- and an :submsg:`SRTPS Postfix`
-- which contains the |CryptoFooter|. |RTPSProtection| modifies the structure of
the whole RTPS message and, when encryption is used, the confidentiality of all
the content (except the RTPS header) is protected.

.. note::

  |DPs| with |RTPSProtection| can only communicate with |DPs| that have this
  same protection. In other words, when you enable |RTPSProtection|, secure and
  unsecure |DPs| cannot interoperate.

From an RTPS point of view, |RTPSProtection| protects the whole RTPS message, including
the RTPS header. To protect the RTPS header (and its extensions), |RTPSProtection| uses
one of the following methods:

  1. Copying the RTPS Header into the :submsg:`SRTPS Body` and protecting its
     integrity with the same mechanism as the rest of the message content. 
     :numref:`RTPS Message Transformation with RTPS Protection` depicts the aforementioned
     structure. We will use this protection method when:

     * :property:`cryptography.enable_additional_authenticated_data` property is set to
       :value:`AUTO` (the default value), for |AXK| messages not including an RTPS
       Header Extension.

     * :property:`cryptography.enable_additional_authenticated_data` property is set to
       :value:`FALSE`, for all messages.

     .. figure:: ../static/rtps-protection.png
      :scale: 50%
      :name: RTPS Message Transformation with RTPS Protection
      :align: center

      RTPS Message Transformation with |RTPSProtection|

  2. Leveraging Additional Authenticated Data (AAD) of the AES-GCM algorithm.
     This protection method does not involve copying the RTPS Header into the
     :submsg:`SRTPS Body`. :numref:`RTPS Message Transformation with RTPS Protection with AAD`
     depicts such a message. We will use this protection method when:

     * :property:`cryptography.enable_additional_authenticated_data` property is set
       to :value:`AUTO` (the default value). With this option, messages protected with
       |PSK| and messages including an RTPS Header Extension submessage are protected with
       AAD.

     * :property:`cryptography.enable_additional_authenticated_data` property is set
       to :value:`TRUE`. With this option, all protected messages are protected with AAD.

     .. figure:: ../static/rtps-protection-aad.png
      :scale: 50%
      :name: RTPS Message Transformation with RTPS Protection with AAD
      :align: center

      RTPS Message protected with AAD. Includes an optional RTPS Header Extension submessage.

.. note::

  |LIGHT_SP_BUILTIN| always protects its outgoing RTPS messages with AAD. It is not
  possible to change the protection method.

.. [#] Exceptions of RTPS messages to which |RTPSProtection| applies are covered
   in :ref:`p2_core/cryptography:DomainParticipants`.

.. [#] SRTPS stands for Secure RTPS.


Origin Authentication Protection
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

|OrigAuthProtection| allows the Receiver to make sure that the Sender is who it claims to be (i.e., it can authenticate the origin), even when the Sender communicates with multiple Receivers via multicast and shares the same encryption key with all of them. For instance, consider a |DR| that legitimately subscribes to a |DW| for a particular |TOPIC|. Since symmetric encryption is used to protect data, the |DR| could potentially use the |DW|'s key to send arbitrary samples, thus impersonating it. |DWs| can avoid this situation by protecting samples with |OrigAuthProtection|.

.. hint::

  You can add |OrigAuthProtection| to |SubmsgProtection| by setting the :xmltag:`metadata_protection_kind` |GovRule| to :xmlval:`SIGN_WITH_ORIGIN_AUTHENTICATION` or :xmlval:`ENCRYPT_WITH_ORIGIN_AUTHENTICATION`.

  You can add |OrigAuthProtection| to |RTPSProtection| by setting the :xmltag:`rtps_protection_kind` |GovRule| to :xmlval:`SIGN_WITH_ORIGIN_AUTHENTICATION` or :xmlval:`ENCRYPT_WITH_ORIGIN_AUTHENTICATION`.

  For further information, see :ref:`p2_core/cryptography:Understanding ProtectionKinds`.

This protection involves computing additional |RecSpecificMACs| with a secret key that the Sender shares only with a set of Receivers (ideally one). The additional MACs are computed by applying the AES-GMAC algorithm parameterized with the |RecSpecificKey| to the |CommonMAC|, and appending the result to it in the |CryptoFooter|.

The number of |RecSpecificMACs| in an RTPS message is the union of the |RecSpecificMACs| each of its submessages would need. For example, assume that you have an RTPS message with three submessages. The first submessage is directed to a receiver |A|, the receiver of the second submessage is |B|, and the receiver of the third submessage is unknown. In this situation, if |SubmsgProtection| were set to protect the origin authentication, the first submessage would have the |RecSpecificMAC| for |A|, the second submessage would have the |RecSpecificMAC| for |B|, and the third submessage would have the |RecSpecificMAC| for all the matching |EPs|, let's say |A|, |B|, |C|, and |D|. Therefore, to satisfy the requirements of every submessage, the RTPS message will include the following |RecSpecificMACs|:

.. math::

  \lbrace A\rbrace\cup\lbrace B\rbrace\cup\lbrace A,B,C,D\rbrace=\lbrace A,B,C,D\rbrace


.. figure:: ../static/rec-specific-macs-multiple-receivers.png
  :scale: 50%
  :name: Receiver-specific MACs included in an RTPS Message that uses RTPS Protection with Origin Authentication
  :align: center

  |RecSpecificMACs| included in an RTPS Message that uses |RTPSProtection| with Origin Authentication


Note that adding |OrigAuthProtection| to |DataProtection| is not allowed (i.e., the :xmlval:`DATA_WITH_ORIGIN_AUTHENTICATION` ProtectionKind does not exist). This is a consequence of the stage at which data is secured. On one hand, RTPS and Submessage Protections happen at wire-serialization time, right before handing the data to the transport. On the other hand, |DataProtection| happens right before the sample is saved in the |DW|'s queue. The writer history stores the protected payload and this happens only once. While RTPS messages and submessages are re-protected when they are re-sent, user data is not. Once the sample is in the queue, the |DW| has no information about the |DRs| interested in it. If a |DR| joins later and wants to receive historical data, the current sample in the queue would not be valid because it wouldn't have the new |RecSpecificMAC| appended to it.

The diagram in :numref:`Location of the Different Kinds of Protection` summarizes the location of the protection.

.. figure:: ../static/applying-protection.png
  :scale: 50%
  :name: Location of the Different Kinds of Protection
  :align: center

  Location of the Different Kinds of Protection

.. warning::

    |OrigAuthProtection| allows the Receiver to make sure that the Sender is
    who it claims to be **according to the SampleInfo::publication_handle.** If
    the Sender uses a different GUID field (i.e., the
    ``SampleInfo::original_publication_virtual_guid`` or the
    ``SampleInfo::source_guid``) to claim to be a different sender,
    and the Receiver also uses this field to determine the sender's origin,
    then |OrigAuthProtection| does not protect against this kind of
    impersonation. This kind of protection comes from the |GovernanceDoc| and
    |PermissionsDoc|. For more information, see
    :ref:`p2_core/access_control:DataWriters Acting as a Proxy for other DataWriters`.

Cryptographic Information Added to RTPS Messages
------------------------------------------------

When the Sender protects a message, it appends the MACs to the message and includes some information that the Receiver will need in order to derive the |SessionKey|. More concretely, the secured message will contain these elements: a |CryptoHeader|, |CryptoContent| (or |SerializedPayload|) and a |CryptoFooter|.


Crypto Header
^^^^^^^^^^^^^

The |CryptoHeader| element indicates to the Receiver the cryptographic
transformation that was used to protect the message. It also identifies the
cryptographic material used to protect the message. It has three parts:

* transformation_id: The transformation_id consists of a transformation_kind
  part and a transformation_key_id part. The transformation_key_id contains the
  |SenderKeyID|: four bytes that are used in combination with the identity of
  the sending |DP| (already present in the RTPS header) to uniquely identify the
  |KeyMaterial| used to derive the |SessionKey| that protected the message.
  The transformation_kind are another four bytes:

   * If the RTPS message is protected using
     :ref:`p3_advanced/pre-shared_key:|PSKProtection|`, then the first three
     bytes are the passphrase key revision (see
     :ref:`p3_advanced/pre-shared_key:Passphrase identifier`). Otherwise, these
     three bytes are the identifier of the |KeyRevision| that was used to
     protect the message (see
     :ref:`p2_core/cryptography:Limiting the Usage of Specific Key Material` and
     the documentation for the
     :property:`dds.participant.trust_plugins.key_revision_max_history_depth`
     property). An identifier of :value:`0` indicates that the original Key
     Material (without applying any Key Revisions) was used to protect the
     message.

   * The fourth and final byte is the same |TransformationKind| that was sent
     during the :ref:`p2_core/cryptography:Secure Key Exchange`.

* session_id: The session_id is used in combination with the |KeyMaterial| to derive the cryptographic keys used for the encryption and MAC operations, including the |SessionKey| and the |RecSpecificSessionKey|.
* initialization_vector_suffix: The initialization_vector_suffix is concatenated with the session_id to produce the |IV| used as an input to the AES-GCM and AES-GMAC cryptographic operations/transformations.


Crypto Content / Serialized Payload
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The |CryptoContent| is a sequence of octets that contain the encrypted version of the protected message when protecting both the integrity and confidentiality of the message (with :xmlval:`ENCRYPT` protection kinds). Alternatively, the |SerializedPayload| is sent in plaintext when only the message's integrity is protected (with :xmlval:`SIGN` protection kinds).


Crypto Footer
^^^^^^^^^^^^^

The |CryptoFooter| consists of the |CommonMAC| (and the |RecSpecificMACs|, when |OrigAuthProtection| is used).

* |CommonMAC|: The |CommonMAC| in the |CryptoFooter| is the authentication tag generated by the AES-GMAC transformation using the |SessionKey| and the |IV|. This transformation operates on the message being protected in plaintext when the :xmlval:`SIGN` protection kind is used, or on the encrypted message when the protection kind is :xmlval:`ENCRYPT`. The result is a 128-bit (16-byte) MAC that protects the message integrity.

* |RecSpecificMACs|: (only when |OrigAuthProtection| is used) The |RecSpecificMACs| in the |CryptoFooter| are the AES-GMAC tags computed on the |CommonMAC| using each of the |RecSpecificSessionKeys| and the same |IV|. Each of the |RecSpecificMACs| is 128-bit (16-byte).

The |RecSpecificMACs| are computed with a secret key that the Sender shares only with a set of Receivers (ideally one). The |RecSpecificMACs| provide origin authentication to the Receiver even when the Sender is communicating with multiple Receivers via multicast and shares the same encryption key with all of them. For more information, see :ref:`p2_core/cryptography:Origin Authentication Protection Implications`.


Security Protections Applied by DDS Entities
============================================

|SecEntities| are responsible for protecting the messages that they put on the wire. When you protect different parts of the communication related to a |TOPIC| in your |GovernanceDoc|, you are actually defining the |Entities| and |SecEntities| that are used to transmit the information related to that |TOPIC|. This includes:

#. Whether |SecDWs| and |DRs| (or regular |DWs| and |DRs|) will be used to transmit the |TOPIC|'s payload (along with the Endpoint's metadata such as :submsg:`HEARTBEATs`, :submsg:`ACKNACKs` and :submsg:`GAPs` submessages).
#. Whether the |EP_disc| traffic will be exchanged through the secure version of the Builtin Discovery Endpoints.
#. Whether the liveliness assertions will be exchanged through the secure version of the Builtin Participant Message Endpoints (if the LIVELINESS QosPolicy is :value:`AUTOMATIC` or :value:`MANUAL_BY_PARTICIPANT`, as described in :ref:`p2_core/cryptography:enable_liveliness_protection (topic_rule)`).

Also, when you enable |RTPSProtection|, your |SecDPs| will additionally protect every RTPS message that is put on the network. (Of course, this includes the messages related to this |TOPIC|).

Keep in mind that to be able to communicate, the |DPs| in your secure domain need to protect the different parts of the communication related to your |TOPIC| the same way. For this reason, your |DPs| need to load compatible Governance documents (see :ref:`p2_core/elements_dds_secure_system:Governance Compatibility Validation`).

Let's analyze what part of the communication (related to your |TOPIC|) each of these (potentially *Secure*) |Entities| can protect and what the valid levels of protection are.


DomainParticipants
------------------

In an unsecure scenario, |EPs| send packets directly to the network, without going through any |DP|-level protection. This remains the same when you don't use |RTPSProtection|. However, you can enable the |RTPSProtection| by setting the :xmltag:`rtps_protection_kind` to a value other than :xmlval:`NONE`. Then the |DP| will intercept the RTPS message produced by your |EPs| (with a callback) and protect the whole message before putting it on the network.

Note that the |DP| will apply |RTPSProtection| to every outgoing RTPS message except for the following:

* DCPSParticipant builtin |TOPIC| messages (used in the |DP_disc| Phase)
* Authentication (ParticipantStatelessMessage) builtin |TOPIC| messages
* Secure Key Exchange (|SecKeyExchangeTName|) builtin |TOPIC| messages
* Binding Ping messages (can be protected with
  :property:`dds.sec.crypto.rtps_psk_secret_passphrase`).

The levels of protection that the |SecDP| can apply are listed in :numref:`Protection Levels Applied by SecDPs During RTPSProtection`. Note that this protection will apply to every RTPS message sent by your |DPs|. Therefore if you have another type of protection enabled, multiple nested cryptographic operations will be performed on your data.

.. table:: Protection Levels Applied by |SecDPs| During |RTPSProtection|
  :name: Protection Levels Applied by SecDPs During RTPSProtection

  +--------------------------------+----------------------------------------------+-------------------------------------------------------+
  | Governance Rule                | ProtectionKind                               | Level of Protection                                   |
  +================================+==============================================+=======================================================+
  | :xmltag:`rtps_protection_kind` | :xmlval:`NONE`                               | No protection                                         |
  |                                +----------------------------------------------+-------------------------------------------------------+
  |                                | :xmlval:`SIGN`                               | Integrity                                             |
  |                                +----------------------------------------------+-------------------------------------------------------+
  |                                | :xmlval:`ENCRYPT`                            | Integrity and confidentiality                         |
  |                                +----------------------------------------------+-------------------------------------------------------+
  |                                | :xmlval:`SIGN_WITH_ORIGIN_AUTHENTICATION`    | Integrity and origin authentication                   |
  |                                +----------------------------------------------+-------------------------------------------------------+
  |                                | :xmlval:`ENCRYPT_WITH_ORIGIN_AUTHENTICATION` | Integrity, confidentiality, and origin authentication |
  +--------------------------------+----------------------------------------------+-------------------------------------------------------+


User-Defined Endpoints (DataWriters/DataReaders)
------------------------------------------------

User-defined |EP| are responsible for exchanging the |TOPIC|'s payload with the Security parameters that you define. You can configure user-defined |EPs| to protect either the Serialized Data, the RTPS submessages or both.
Protecting the Serialized Data implies protecting the |TOPIC|'s payload, which is contained in :submsg:`DATA` submessages.
Protecting the RTPS submessages implies protecting both :submsg:`DATA` submessages (which contain the payload) and other submessages that contain metadata (such as :submsg:`HEARTBEATs`, :submsg:`ACKNACKs` and :submsg:`GAPs` submessages).

|DataProtection| and |SubmsgProtection| are performed by the same |SecEntity|, but at different stages:

* |DataProtection| is applied to data in the |DW|'s queue, before encapsulating it in an RTPS submessage.
* |SubmsgProtection| is applied right before putting the information on the network. Note that a batch of serialized data elements could be sent in the same submessage.

You can configure user-defined |EP| to apply different levels of protection at each of these stages, as shown in :numref:`Protection Levels Applied by user-defined EPs for DataProtection` and Table :numref:`Protection Levels Applied by user-defined EPs for SubmsgProtection`.

You can configure the level of protection applied at each level independently. So if you want to protect the confidentiality of the payload and the integrity of the metadata sent by your user-defined |SecEPs| you could set :xmltag:`data_protection_kind` to :xmlval:`ENCRYPT` and :xmltag:`metadata_protection_kind` to :xmlval:`SIGN`. Note that in this case, your |DW| will perform an AES-GCM operation over the serialized data, storing the encrypted and MAC'd payload in its queue (with its corresponding format: |CryptoHeader| | |CryptoContent| | |CryptoFooter|). Then right before putting the data on the network, it will perform an AES-GMAC operation to the :submsg:`DATA` submessage, inserting the MAC'd submessage in an RTPS message (with its corresponding format: SEC Prefix | SEC Body | SEC Postfix).

.. table:: Protection Levels Applied by user-defined |EPs| for |DataProtection|
  :name: Protection Levels Applied by user-defined EPs for DataProtection
  :width: 100%

  +--------------------------------+-------------------+-------------------------------+
  | Governance Rule                | ProtectionKind    | Level of Protection           |
  +================================+===================+===============================+
  | :xmltag:`data_protection_kind` | :xmlval:`NONE`    | No protection                 |
  |                                +-------------------+-------------------------------+
  |                                | :xmlval:`SIGN`    | Integrity                     |
  |                                +-------------------+-------------------------------+
  |                                | :xmlval:`ENCRYPT` | Integrity and confidentiality |
  +--------------------------------+-------------------+-------------------------------+

.. table:: Protection Levels Applied by user-defined |EPs| for |SubmsgProtection|
  :name: Protection Levels Applied by user-defined EPs for SubmsgProtection

  +------------------------------------+----------------------------------------------+-------------------------------------------------------+
  | Governance Rule                    | ProtectionKind                               | Level of Protection                                   |
  +====================================+==============================================+=======================================================+
  | :xmltag:`metadata_protection_kind` | :xmlval:`NONE`                               | No protection                                         |
  |                                    +----------------------------------------------+-------------------------------------------------------+
  |                                    | :xmlval:`SIGN`                               | Integrity                                             |
  |                                    +----------------------------------------------+-------------------------------------------------------+
  |                                    | :xmlval:`ENCRYPT`                            | Integrity and confidentiality                         |
  |                                    +----------------------------------------------+-------------------------------------------------------+
  |                                    | :xmlval:`SIGN_WITH_ORIGIN_AUTHENTICATION`    | Integrity and origin authentication                   |
  |                                    +----------------------------------------------+-------------------------------------------------------+
  |                                    | :xmlval:`ENCRYPT_WITH_ORIGIN_AUTHENTICATION` | Integrity, confidentiality, and origin authentication |
  +------------------------------------+----------------------------------------------+-------------------------------------------------------+


Builtin Secure Discovery Endpoints
----------------------------------

Builtin Discovery |EP| are responsible for exchanging the |EP_disc| information that allows the local |DP| to discover remote |EP| (and remote participants to discover the local |DP|'s |EP|). You can configure whether to use the secure version (or the regular unsecure version) of the Builtin Discovery Endpoints with the :xmltag:`enable_discovery_protection` |GovRule|. If you set this |GovRule| to :xmlval:`TRUE`, discovery information related to your |TOPIC| will be exchanged through the Builtin Secure Discovery Endpoints, and Topic Queries related to your |TOPIC| will be communicated through the Builtin Secure ServiceRequest Endpoints. These |EP| will apply |SubmsgProtection| to the level you configure with the :xmltag:`discovery_protection_kind` |GovRule|.

The levels of protection that the Builtin Secure Discovery Endpoints can apply are listed in table :numref:`Protection Levels Applied by Builtin Secure Discovery Endpoints and Builtin Secure ServiceRequest Endpoints`. Note that this protection level will apply to the discovery and topic query information for every |TOPIC| that sets :xmltag:`enable_discovery_protection` = :xmlval:`TRUE`.

.. table:: Protection Levels Applied by Builtin Secure Discovery Endpoints and Builtin Secure ServiceRequest Endpoints in the |SubmsgProtection| Stage
  :name: Protection Levels Applied by Builtin Secure Discovery Endpoints and Builtin Secure ServiceRequest Endpoints

  +-------------------------------------+----------------------------------------------+-------------------------------------------------------+
  | Governance Rule                     | ProtectionKind                               | Level of Protection                                   |
  +=====================================+==============================================+=======================================================+
  | :xmltag:`discovery_protection_kind` | :xmlval:`NONE`                               | No protection                                         |
  |                                     +----------------------------------------------+-------------------------------------------------------+
  |                                     | :xmlval:`SIGN`                               | Integrity                                             |
  |                                     +----------------------------------------------+-------------------------------------------------------+
  |                                     | :xmlval:`ENCRYPT`                            | Integrity and confidentiality                         |
  |                                     +----------------------------------------------+-------------------------------------------------------+
  |                                     | :xmlval:`SIGN_WITH_ORIGIN_AUTHENTICATION`    | Integrity and origin authentication                   |
  |                                     +----------------------------------------------+-------------------------------------------------------+
  |                                     | :xmlval:`ENCRYPT_WITH_ORIGIN_AUTHENTICATION` | Integrity, confidentiality, and origin authentication |
  +-------------------------------------+----------------------------------------------+-------------------------------------------------------+


Secure Topic Query and Locator Reachability Support
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Builtin Service Request |EP| are responsible for exchanging Topic Queries and Locator Reachability responses. The Builtin Secure Service Request |EP| will apply |SubmsgProtection| to the level you configure with the :xmltag:`discovery_protection_kind` |GovRule|. (See :ref:`p2_core/elements_dds_secure_system:Builtin Secure ServiceRequest Topic`).

The decision about which version of the Builtin Service Request endpoint (secure or not secure) the |DR| uses to send Topic Queries will depend on the value configured for the :xmltag:`enable_discovery_protection` |GovRule| for that |DR|.

The decision about which version of the Builtin Service Request endpoint (secure or not secure) the Participant uses to send Locator Reachability responses to a remote Participant will be based on whether or not that remote Participant is using security.


Builtin Secure Liveliness Endpoints
-----------------------------------

Builtin Liveliness |EP| are responsible for maintaining the liveliness of |TOPICs| that set the LIVELINESS QosPolicy to :value:`AUTOMATIC` or :value:`MANUAL_BY_PARTICIPANT` (see :ref:`p2_core/cryptography:enable_liveliness_protection (topic_rule)`). You can configure whether to use the secure version (or the regular unsecure version) of the Builtin Liveliness Endpoints with the :xmltag:`enable_liveliness_protection` |GovRule|. If you set this |GovRule| to :xmlval:`TRUE`, liveliness information related to your |TOPIC| will be exchanged through the Builtin Secure Liveliness Endpoints (only if the LIVELINESS QosPolicy is set to one of the values listed above). These |EP| will apply |SubmsgProtection| to the level you configure with the :xmltag:`liveliness_protection_kind` |GovRule|.

The levels of protection that the Builtin Secure Liveliness Endpoints can apply are listed in table :numref:`Protection Levels Applied by Builtin Secure Liveliness Endpoints`. Note that this protection level will only apply to |TOPICs| that set the LIVELINESS QosPolicy to one of the values listed above and set :xmltag:`enable_liveliness_protection` = :xmlval:`TRUE`.

.. table:: Protection Levels Applied by Builtin Secure Liveliness Endpoints at the |SubmsgProtection| Stage
  :name: Protection Levels Applied by Builtin Secure Liveliness Endpoints

  +--------------------------------------+----------------------------------------------+-------------------------------------------------------+
  | Governance Rule                      | ProtectionKind                               | Level of Protection                                   |
  +======================================+==============================================+=======================================================+
  | :xmltag:`liveliness_protection_kind` | :xmlval:`NONE`                               | No protection                                         |
  |                                      +----------------------------------------------+-------------------------------------------------------+
  |                                      | :xmlval:`SIGN`                               | Integrity                                             |
  |                                      +----------------------------------------------+-------------------------------------------------------+
  |                                      | :xmlval:`ENCRYPT`                            | Integrity and confidentiality                         |
  |                                      +----------------------------------------------+-------------------------------------------------------+
  |                                      | :xmlval:`SIGN_WITH_ORIGIN_AUTHENTICATION`    | Integrity and origin authentication                   |
  |                                      +----------------------------------------------+-------------------------------------------------------+
  |                                      | :xmlval:`ENCRYPT_WITH_ORIGIN_AUTHENTICATION` | Integrity, confidentiality, and origin authentication |
  +--------------------------------------+----------------------------------------------+-------------------------------------------------------+


Related Governance Rules
========================

You can control what protection kind you apply to different parts of your communication. You can do this by setting some Cryptography rules in your |GovernanceDoc|. For information on what |SecEntity| is responsible for protecting each part of the message, see :ref:`p2_core/cryptography:Security Protections Applied by DDS Entities`.


Understanding ProtectionKinds
-----------------------------

Attributes whose names end with ``_protection_kind`` share a type called
ProtectionKind. The |SEC_SPEC| lists five possible values of
ProtectionKind, all of which are supported by the |RTI_SP_PRODUCT|.

* :xmlval:`NONE` indicates that no cryptographic transformation is applied.

* :xmlval:`SIGN` indicates that the cryptographic transformation is purely a Galois message authentication code (GMAC, referred to as MAC), which protects the integrity of the message the protection applies to. No encryption is performed. The MAC is placed after the content (in the |CryptoFooter|). If the Receiver finds a missing or incorrect MAC, the Receiver will reject the content.

* :xmlval:`ENCRYPT` indicates that the cryptographic transformation is AES encrypted followed by a MAC computed on the ciphertext, also known as Galois/Counter Mode (GCM), protecting both the integrity and confidentiality of the messages. The MAC is placed after the content (in the |CryptoFooter|). If the Receiver finds a missing or incorrect MAC, the Receiver will reject the content.

* ProtectionKinds ending in :xmlval:`_WITH_ORIGIN_AUTHENTICATION` indicate that
  in addition to using the Sender's key to generate a |CommonMAC|, the Sender
  generates |RecSpecificMACs| using keys that are only shared with a subset of
  Receivers (ideally, only one). The additional MACs are placed after the
  |CommonMAC| (also in the |CryptoFooter|). They prove to the Receiver that the
  Sender originated the message, preventing other Receivers from impersonating
  the Sender. If the Receiver finds a missing or incorrect |CommonMAC|, the
  Receiver will reject the content. If the Receiver finds a missing or incorrect
  |RecSpecificMAC| that was computed using its own |RecSpecificKey|, the Receiver
  will reject the content. For further details,
  see :ref:`p2_core/cryptography:Origin Authentication Protection`).

  .. note::

    The :xmltag:`rtps_protection_kind` values ending in
    :xmlval:`_WITH_ORIGIN_AUTHENTICATION` are allowed only if the value of the
    property :property:`cryptography.max_receiver_specific_macs` is not
    :value:`0`.

    All other :xmltag:`*_protection_kind` values ending in
    :xmlval:`_WITH_ORIGIN_AUTHENTICATION` are allowed only if the value of the
    property :property:`cryptography.max_receiver_specific_macs` is greater
    than :value:`1` (In particular, :value:`AUTO` is not allowed. See
    :numref:`|RTI_SP_PRODUCT_HEADING| Properties for Configuring Cryptography`
    and
    :ref:`p2_core/cryptography:Origin Authentication Protection Implications`.)

The ProtectionKinds ending in :xmlval:`_WITH_ORIGIN_AUTHENTICATION` are as follows:

* :xmlval:`SIGN_WITH_ORIGIN_AUTHENTICATION` indicates that a |CommonMAC| is performed on the content, and |RecSpecificMACs| are performed on the |CommonMAC|. This provides integrity and origin authentication protections.

* :xmlval:`ENCRYPT_WITH_ORIGIN_AUTHENTICATION` indicates that a GCM is performed on the content, and |RecSpecificMACs| are performed on the |CommonMAC|. This provides integrity, confidentiality, and origin authentication protections.


Domain-Level Rules
------------------

The following attributes belong inside a :xmltag:`domain_rule`.


rtps_protection_kind (domain_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This ProtectionKind specifies how to protect a |DP|'s outgoing messages and
what kind of protection is required of incoming messages. A message consists of
an RTPS header and submessages, so a message is an envelope around submessages.
If :xmltag:`allow_unauthenticated_participants` = :xmlval:`TRUE`,
:xmltag:`rtps_protection_kind` must be set to :xmlval:`NONE`. Setting
:xmltag:`rtps_protection_kind` to :xmlval:`NONE` will cause the |DP| to accept
both protected and unprotected incoming RTPS messages. Setting
:xmltag:`rtps_protection_kind` to something other than :xmlval:`NONE` will
cause the |DP| to reject incoming RTPS messages that have a missing or
incorrect MAC.

rtps_psk_protection_kind (domain_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This ProtectionKind specifies how to protect RTPS bootstrapping messages.
From the point of view of the |RTI_SP_PRODUCT|, we consider RTPS bootstrapping messages
to include all the messages that are exchanged before the Secure Key Exchange
Channel (see
:ref:`p2_core/cryptography:Secure Key Exchange Channel (ParticipantVolatileMessageSecure topic)`)
can deliver the participant symmetric keys.
RTPS bootstrapping messages currently include: SPDP messages,
SPDP2 bootstrap messages, Authentication messages, Secure Key Exchange Channel
messages, and Locator Ping messages. Bootstrapping messages aren't protected by
the :xmltag:`rtps_protection_kind` ProtectionKind.

The :xmltag:`rtps_psk_protection_kind` ProtectionKind supports the values
:xmlval:`NONE`, :xmlval:`SIGN`, and :xmlval:`ENCRYPT`. The
:xmlval:`WITH_ORIGIN_AUTHENTICATION` protection kinds are not allowed. Values
different than :xmlval:`NONE` require setting a pre-shared key seed and
algorithm consistently throughout your system. For details on
the :property:`dds.sec.crypto.rtps_psk_secret_passphrase` and
:property:`dds.sec.crypto.rtps_psk_symmetric_cipher_algorithm` properties, see
:numref:`Properties for Configuring Cryptography Affecting Any Cryptography Plugin`.
To learn more about how |PSKProtection| works, read the
:ref:`p3_advanced/pre-shared_key:|PSKProtection|` section.

A special case is when |PSKProtection| is enabled and the value of
:xmltag:`rtps_protection_kind` is :xmlval:`NONE`. If so, the |CryptoPlugin| protect all
RTPS messages according to the ProtectionKind in
:xmltag:`rtps_psk_protection_kind`. In this case, to reduce discovery-time
overhead, consider using the |LIGHT_SP_BUILTIN| (read
:ref:`p3_advanced/lightweight_security:The |LIGHT_SP_BUILTIN_HEADING|`) if your
application doesn't require authentication or access control.

.. warning::

    The |LIGHT_SP_BUILTIN| do not support the |GovernanceDoc|, so they have the
    :property:`dds.sec.access.rtps_psk_protection_kind` property for
    configuring this ProtectionKind. This property has the same effect as the
    :xmltag:`rtps_psk_protection_kind` |GovRule|. Do not configure the
    :property:`dds.sec.access.rtps_psk_protection_kind` property in the
    |SP_BUILTIN|.

discovery_protection_kind (domain_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This ProtectionKind specifies the :xmltag:`metadata_protection_kind` used for
the secure builtin |DW| and |DR| entities used for discovery, Topic Queries,
and Locator Reachability Responses.

The :xmltag:`discovery_protection_kind` will protect |EP_disc| for the |TOPICs|
that set :xmltag:`enable_discovery_protection`. This includes information
exchanged for discovering new |EP| and for updating existing ones, as described
in :ref:`p2_core/cryptography:enable_discovery_protection (topic_rule)`. The
:xmltag:`discovery_protection_kind` will also protect messages that contain
updates to the existing |DPs|. Note that new |DP| discovery announcements are
never protected (but updates to existing |DPs| are protected).


liveliness_protection_kind (domain_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This ProtectionKind specifies the :xmltag:`metadata_protection_kind` used for
the secure builtin |DW| and |DR| entities used for liveliness.

The :xmltag:`liveliness_protection_kind` will protect liveliness information
from |TOPICs| that set :xmltag:`enable_liveliness_protection` (only if the
|DW|'s LIVELINESS QosPolicy is :value:`AUTOMATIC` or
:value:`MANUAL_BY_PARTICIPANT`, as described in
:ref:`p2_core/cryptography:enable_liveliness_protection (topic_rule)`).

monitoring_metrics_protection_kind (domain_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This ProtectionKind specifies the :xmltag:`metadata_protection_kind` used
for the builtin |DW| and |DR| entities used for exchanging periodic and
event metrics in the *RTI Connext Observability Framework*. If it is not
present in the |GovernanceDoc|, the protection level is inherited from
:xmltag:`discovery_protection_kind`.

The final value used for the protection kind (originating either from
:xmltag:`monitoring_metrics_protection_kind` or :xmltag:`discovery_protection_kind`)
has an impact on |DP| matching.

If the monitoring metrics channel is enabled on both the local and remote |DP|, the
protection kind used by the builtin entities must be equal.

This tag is optional. See :ref:`chapter-observability-framework` for further
details.

monitoring_logging_protection_kind (domain_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This ProtectionKind specifies the :xmltag:`metadata_protection_kind` used
for the builtin |DW| and |DR| entities used for exchanging logging messages
in the *RTI Connext Observability Framework*. If it is not present in the
|GovernanceDoc|, the protection level is inherited from
:xmltag:`discovery_protection_kind`.

The final value used for the protection kind (originating either from
:xmltag:`monitoring_logging_protection_kind` or :xmltag:`discovery_protection_kind`)
has an impact on |DP| matching.

If the monitoring logging channel is enabled on both the local and remote |DP|, the
protection kind used by the builtin entities must be equal.

This tag is optional. See :ref:`chapter-observability-framework` for further
details.

.. _section-service-request-protection-kind:

service_request_protection_kind (domain_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This ProtectionKind specifies the :xmltag:`metadata_protection_kind` used
for the builtin ServiceRequest |DW| and |DR|. The ServiceRequest channel is a
builtin channel created per |DP|. It is used for a variety of features, including
Topic Query, Instance State Consistency and Locator Reachability.

If the :xmltag:`service_request_protection_kind` tag is not present in the |GovernanceDoc|,
the protection kind is derived from the :xmltag:`discovery_protection_kind`.

The final value used for the protection kind (originating either from
:xmltag:`service_request_protection_kind` or :xmltag:`discovery_protection_kind`)
has an impact on |DP| matching.

instance_state_consistency_protection_kind (domain_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This ProtectionKind specifies the :xmltag:`metadata_protection_kind` used
by the builtin |DWs| and |DRs| of the Instance State Consistency channel(s).
Instance State Consistency |DWs| and |DRs| are builtin |DW| and |DR| that are
created per Publisher and Subscriber. They are only created if a user's |DW| or
|DR| within that Publisher or Subscriber has configured Instance State Consistency
within the Reliability QoS Policy.

If the :xmltag:`instance_state_consistency_protection_kind` tag is not present
in the |GovernanceDoc|, the protection kind is derived from the
:xmltag:`discovery_protection_kind`.

The final value used for the protection kind (originating either from
:xmltag:`instance_state_consistency_protection_kind` or
:xmltag:`discovery_protection_kind`) has an impact on endpoint matching. When
entities with instance state consistency enabled are created, the protection
kind configured for the instance state consistency is compared, and if not
equal the participants are marked as incompatible. This compatibility check is
only performed if both the DomainParticipants use versions of DDS that support
Instance State Consistency.

For more information about the security model used within instance state
consistency, see 
:ref:`p2_core/cryptography:Interactions with Instance State Consistency`.

type_lookup_protection_kind (domain_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This ProtectionKind specifies the :xmltag:`metadata_protection_kind` used
by the builtin |DWs| and |DRs| of the TypeLookup Service Channel. By default the
protection kind of the TypeLookup Service Channel is :xmlval:`ENCRYPT` (matching
the configuration of the Secure Key Exchange Builtin Topic).

The :xmltag:`type_lookup_protection_kind` provides the ability to configure the
ProtectionKind to something other than :xmlval:`ENCRYPT`. This configuration
option is not part of the |SEC_SPEC| (which explicitly states that
the ProtectionKind of the TypeLookup Service Channel should be
:xmlval:`ENCRYPT`). See :ref:`p3_advanced/differences_wrt_spec:Differences Affecting Builtin Plugins to be Addressed by Next DDS Security Specification`
for more information about this configuration setting.
The protection of the TypeLookup Service Channel is defined explicitly in the
DDS-Secure specification without this ProtectionKind. However, the specification
does not provide a way to prevent insider attacks (by way of configuring origin
authnetication on the channel). This extension to the specification provides a 
way for users to mitigate inisder attacks.

This ProtectionKind is optional. If left unset, the protection of the TypeLookup
Service channel will be exactly as defined by the specification.


allowed_security_algorithms (domain_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This element determines the security algorithms that are allowed in your system.
There are four families of algorithms. You can specify the list of approved
system-wide algorithms for each of the families:

* :xmltag:`digital_signature`: Configures the digital signature algorithms that
  |DPs| can use for generating and validating signatures during the
  authentication process. Unless
  :xmltag:`digital_signature_identity_trust_chain` is set,
  :xmltag:`digital_signature` also configures the digital signature algorithms
  that |DPs| can use in the context of the identity trust chain. These are the
  algorithms that are allowed when verifying the Identity Certificate (local or
  remote) against the Identity Certificate Authority. Its possible values are
  :xmlval:`RSASSA-PSS-MGF1SHA256+2048+SHA256`,
  :xmlval:`RSASSA-PKCS1-V1_5+2048+SHA256`, :xmlval:`ECDSA+P256+SHA256`, and
  :xmlval:`ECDSA+P384+SHA384`.

* :xmltag:`digital_signature_identity_trust_chain`: If set, overwrites the
  configuration of :xmltag:`digital_signature` for configuring the digital
  signature algorithms that |DPs| can use in the context of the identity trust
  chain. These are the algorithms that are allowed when verifying the
  |IdentityCert| (local or remote) against the Identity Certificate Authority.
  Its possible values are: :xmlval:`RSASSA-PSS-MGF1SHA256+2048+SHA256`,
  :xmlval:`RSASSA-PKCS1-V1_5+2048+SHA256`, :xmlval:`ECDSA+P256+SHA256`,
  :xmlval:`ECDSA+P384+SHA384`, :xmlval:`EDDSA+ED25519+SHA512`
  (<< experimental >>), and :xmlval:`EDDSA+ED448+SHAKE256` (<< experimental >>).

* :xmltag:`key_establishment`: Algorithms that |DPs| can use for key
  establishment. Its possible values are: :xmlval:`DHE+MODP-2048-256`,
  :xmlval:`ECDHE-CEUM+P256`, :xmlval:`ECDHE-CEUM+P384`,
  :xmlval:`ECDHE-CEUM+X25519` (<< experimental >>), and
  :xmlval:`ECDHE-CEUM+X448` (<< experimental >>).

* :xmltag:`symmetric_cipher`: Algorithms that |DPs| and their endpoints can use
  for symmetric cipher operations. Its possible values are:
  :xmlval:`AES128+GCM`, and :xmlval:`AES256+GCM`.

|SecDPs| propagate their list of supported and allowed algorithms during
discovery. Two |DPs| will match or not, depending on their supported and allowed
algorithms. They will try to authenticate each other only if they are
compatible.

You can allow the |DPS| in your system to use any supported security
algorithm if you don't add the :xmltag:`allowed_security_algorithms` XML
element to the |GovernanceDoc|. In that case, the only restriction comes from
the implementation of the |CryptoPlugin|. For example, a particular crypto library may
not support some algorithms. The |CryptoPlugin| will internally populate the supported
algorithms and let other |DPs| know about them during discovery.

Instead of allowing all security algorithms, you can minimize discovery overhead
by choosing the values of your :xmltag:`allowed_security_algorithms` to match
the |SEC_SPEC_12| defaults for discovery. You can do so with a |GovernanceDoc|
like the following one:

.. literalinclude:: ../snippets/example_default_algorithms_governance_file.xml
  :language: xml
  :class: break-lines

These defaults are the values that remote |DPs| assume if no information
regarding the security algorithms is received from a |DP|. Unless your system
has to support additional algorithms, use this combination in order to minimize
discovery traffic.

.. warning::

    The |RTI_SP_PRODUCT| did not support restricting their algorithms before
    version 7.0.0. New |DPs| will assume that old |DPs| support and use the
    default algorithms. These algorithms are specified in the |SEC_SPEC_12| and
    listed in the |GovernanceDoc| above.

    Interoperability with |DPs| prior to version 7.0.0 is not affected if you
    don't add the :xmltag:`allowed_security_algorithms` XML element to the
    |GovernanceDoc| (it means, all security algorithms are supported). This is
    the case if you use a single |GovernanceDoc| for all the |DPs| in your
    system (new and old). Besides minimizing discovery traffic, the
    |GovernanceDoc| above also ensures interoperability with |DPs| prior to
    version 7.0.0.

    However, communication may fail with older |DPs| if the
    :xmltag:`allowed_security_algorithms` tag in the |GovernanceDoc| of the new
    |DPs| is different from the one in this section (the OMG default values for
    discovery). Communication will not happen if matching between the
    :xmltag:`allowed_security_algorithms` configured in the |GovernanceDoc|
    and the OMG-default algorithms (assumed by the new |DP| about the old one)
    fail. This mismatch may certainly be a result of a wrong assumption. After
    all, the new |DP| can't do better because it doesn't know the actual
    algorithms used and supported by the old |DP|. In this case, you have this
    information when designing your system. Choose the security algorithms that
    your |DPs| allow so that interoperability is not affected. For example,
    matching with older |DPs| may fail if you don't allow the
    :xmlval:`AES128+GCM` symmetric cipher algorithm. The reason is the default
    value of the :property:`cryptography.encryption_algorithm` property
    (:property:`dds.sec.crypto.symmetric_cipher_algorithm` in newer releases)
    changed in version 7.0.0 from :xmlval:`AES128+GCM` to :xmlval:`AES256+GCM`.

    Note that interoperability with the |RTI_SP_PRODUCT| 7.0, 7.1, and 7.2
    feature releases requires using the |GovernanceDoc| in this section.

.. _section-enable-key-revision:

enable_key_revision (domain_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

:xmltag:`enable_key_revision` may be :xmlval:`true` or :xmlval:`false`. It
controls whether or not a new |KeyRevision| (see
:ref:`p2_core/cryptography:Limiting the Usage of Specific Key Material`) is
introduced when you call ``banish_ignored_participants`` or when one of the
reasonable circumstances described in
:ref:`p2_core/cryptography:Automatically Banishing Ignored Participants`
occurs.

If the :property:`dds.participant.trust_plugins.key_revision_max_history_depth`
property is not set, then setting :xmltag:`enable_key_revision` to
:xmlval:`true` will effectively set
:property:`dds.participant.trust_plugins.key_revision_max_history_depth` to a
non-zero value, and setting :xmltag:`enable_key_revision` to
:xmlval:`false` will effectively set
:property:`dds.participant.trust_plugins.key_revision_max_history_depth` to
:value:`0`.

If the :property:`dds.participant.trust_plugins.key_revision_max_history_depth`
property is set, then it may be :value:`0` if and only if
:xmltag:`enable_key_revision` is :xmlval:`false`; otherwise, |DP| creation will
fail with an error message similar to this one:

.. code-block:: console

  PRESParticipant_setupSecurity:INCONSISTENT FAILURE | dds.participant.trust_plugins.key_revision_max_history_depth property value should be 0 if and only if key revisions are disabled in the trust plugins. Your property value is 8.

:xmltag:`enable_key_revision` is an optional element. If it is not specified,
the default value is :xmlval:`true`.

Topic-Level Rules
-----------------

The following attributes belong inside a :xmltag:`topic_rule`.


metadata_protection_kind (topic_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This ProtectionKind specifies how to protect a |DW|'s or |DR|'s outgoing RTPS submessages. These submessages include, but are not limited to, :submsg:`DATA`, :submsg:`HEARTBEAT`, :submsg:`ACKNACK`, :submsg:`APP_ACK`, and :submsg:`GAP`. (For the full list of affected RTPS submessages, refer to :ref:`p2_core/cryptography:Submessage protection`.) Note that :submsg:`DATA` submessage is an envelope around a serialized payload, so :xmltag:`metadata_protection_kind` affects data as well as metadata.


data_protection_kind (topic_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This attribute may be :xmlval:`NONE`, :xmlval:`SIGN`, or :xmlval:`ENCRYPT`. It specifies how to protect a |DW|'s serialized payload, as described in :ref:`p2_core/cryptography:Serialized data protection`.

The |DW| applies this protection upon adding the serialized payload to the |DW|'s queue (the |DW|'s queue stores the protected payload). In that sense, one difference between :xmltag:`metadata_protection_kind` and :xmltag:`data_protection_kind` is that for :xmltag:`metadata_protection_kind`, the submessage protection takes effect immediately before sending out the content, so if a given serialized payload needs to be resent multiple times, the submessage protection will be re-computed every time the serialized payload is (re)sent; on the other hand, the serialized data protection is applied only when the sample is added to the writer queue and, therefore, this protection does not need to be re-computed every time the serialized payload is sent.

|RecSpecificMACs| are never included in this protection, so the ProtectionKinds ending in :xmlval:`_WITH_ORIGIN_AUTHENTICATION` are not allowed for this attribute.


enable_discovery_protection (topic_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This attribute may be :xmlval:`TRUE` or :xmlval:`FALSE`. It specifies whether to use the secure or unsecure builtin |EP| for certain outgoing traffic related to this |TOPIC|. Such traffic includes |EP_disc| messages, TopicQuery messages, and Instance State Transition requests. :xmltag:`enable_discovery_protection` also specifies whether or not to reject unsecure incoming |EP_disc| messages related to this |TOPIC|. For further details, see :ref:`p2_core/cryptography:Builtin Secure Discovery Endpoints`.


enable_liveliness_protection (topic_rule)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This attribute may be :xmlval:`TRUE` or :xmlval:`FALSE`. The value of this attribute matters only if the |DW|'s LIVELINESS QosPolicy is :value:`AUTOMATIC` or :value:`MANUAL_BY_PARTICIPANT` (see :link_connext_dds_pro_um:`LIVELINESS QosPolicy in the Core Libraries User's Manual <#users_manual/LIVELINESS_QosPolicy.htm>`). In either of these cases, :xmltag:`enable_liveliness_protection` specifies whether or not to use the secure builtin |EP| for exchanging liveliness messages for |DWs| of this |TOPIC|. Otherwise, when LIVELINESS QosPolicy is :value:`MANUAL_BY_TOPIC`, this attribute does not take effect and it is the user-defined |SecEPs| that take care of liveliness assertions, which are protected with :xmltag:`metadata_protection_kind`. For further details, see :ref:`p2_core/cryptography:Builtin Secure Discovery Endpoints`.


Advanced Cryptography Concepts
==============================

Reliability Behavior When MAC Verification Fails
------------------------------------------------

From a security point of view, message corruption due to random errors produced on the network cannot be distinguished from malicious tampering.

When setting :xmltag:`data_protection_kind`, :xmltag:`metadata_protection_kind`, or :xmltag:`rtps_protection_kind` to a value other than :xmlval:`NONE`, the |DR| may reject a sample due to MAC verification (for example, if the sample is tampered). When this happens, the |DR| does not deliver the sample to the application, and the sample is lost. If the RELIABILITY QosPolicy is set to :xmlval:`RELIABLE`, however, the |DW| will still repair the lost sample.

Note that depending on the level of protection, a tampered/replayed sample may be rejected at different levels:

* If :xmltag:`metadata_protection_kind` or :xmltag:`rtps_protection_kind` is a value other than :xmlval:`NONE`, the sample will be rejected before reaching the |DR| queue.

* If Submessage and RTPS Protection checks passed, and :xmltag:`data_protection_kind` is set to a value other than :xmlval:`NONE`, the sample will be rejected by the |DR| queue (or lost, in the case of best effort communication).

Configuring Reliability Protocol Settings of the Secure Key Exchange Topic
--------------------------------------------------------------------------

The |RTI_SP_PRODUCT| support configuring the reliability protocol settings of the Secure Key Exchange (|SecKeyExchangeTName|) builtin topic, which is a reliable |TOPIC|. You can configure this by modifying the DDS_DiscoveryConfigQosPolicy (see :link_connext_dds_pro_um:`DISCOVERY_CONFIG QosPolicy (DDS Extension) in the Core Libraries User's Manual <#users_manual/DISCOVERY_CONFIG_Qos.htm>`). For more information about how to configure the Key Exchange topic reliability protocol settings, see :numref:`DDS_DiscoveryConfigQosPolicy Fields Affecting the RTPS Protocol-Related Configuration of the Secure Key Exchange Topic`.

If a Secure Key Exchange |DW| marks a Secure Key Exchange |DR| as inactive
(due to a lack of response within the **max_heartbeat_retries** number of
periodic heartbeats), and if :xmltag:`allow_unauthenticated_participants` =
:xmlval:`FALSE`, then the |DW|'s |DP| will remove the |DR|'s |DP| as if
liveliness were lost. Without this removal, the |DPs| will unrecoverably stop
communicating with each other due to a pending Secure Key Exchange sample being
removed from the writer queue and never resent. Removing the |DP| will at least
provide an opportunity to reestablish communication after a new round of
discovery, authentication, and key exchange. The only time this removal doesn't
happen is when :xmltag:`allow_unauthenticated_participants` = :xmlval:`TRUE`
and the local Secure Key Exchange |DW| or |DR| has never successfully received
traffic from the |DP|. In that case, the local |DP| will treat the remote |DP|
as an unauthenticated |DP| and will only communicate with its unsecure
endpoints.

.. list-table:: DDS_DiscoveryConfigQosPolicy Fields Affecting the RTPS Protocol-Related Configuration of the |SecKeyExchangeT|
  :name: DDS_DiscoveryConfigQosPolicy Fields Affecting the RTPS Protocol-Related Configuration of the Secure Key Exchange Topic
  :widths: auto
  :header-rows: 1
  :class: longtable

  * - Type
    - Field Name
    - Description

  * - :link_connext_dds_pro_um:`RtpsReliableWriterProtocol_t <#users_manual/DATA_WRITER_PROTOCOL_Qos.htm#Table_RtpsReliableWriterProtocol>`
    - ``secure_volatile_writer``
    - RTPS protocol-related configuration settings for the builtin Secure Key Exchange writer

  * - :link_connext_dds_pro_um:`DDS_RtpsReliableReaderProtocol_t <#users_manual/DATA_READER_PROTOCOL_Qos.htm#receiving_2076951295_1134218>`
    - ``secure_volatile_reader``
    - RTPS protocol-related configuration settings for the builtin Secure Key Exchange reader


Securing Application-Level Acknowledgments
------------------------------------------

As mentioned in :ref:`p2_core/cryptography:Submessage Protection`, the protection of :submsg:`AppAck` submessages is determined by :xmltag:`metadata_protection_kind`. Therefore, if an AppAck contains valid response data, that response data's protection is determined by :xmltag:`metadata_protection_kind` (not :xmltag:`data_protection_kind`). Moreover, the |TOPIC|'s :xmltag:`enable_read_access_control` (not :xmltag:`enable_write_access_control`) determines whether the |DR| is allowed to match with a |DW| and send such AppAcks. With that in mind, a |DP| with permission to read but not write the |TOPIC| could create a |DR| (let's call it |DR1|) whose response data always contains all of the sample's contents being acknowledged. Even if no other |DRs| can interpret the AppAck response data as a data sample (because the response data would not be coming from a :submsg:`DATA` submessage), |DR1| could compromise the |TOPIC|'s payload confidentiality by putting samples in plaintext on the wire.

You can mitigate this threat by setting :xmltag:`metadata_protection_kind` to :xmlval:`ENCRYPT`. Doing so will force |DR1| to set :xmltag:`metadata_protection_kind` to :xmlval:`ENCRYPT` to match with the |DW|, ensuring that |DR1| will encrypt its response data.

.. warning::

  In version 5.3.x or below of the |RTI_SP_PRODUCT|, it's still possible to misconfigure |DR1| not to encrypt its response data -- |DR1| would still match with the |DW| despite setting :xmltag:`metadata_protection_kind` not equal to :xmlval:`ENCRYPT`.


Origin Authentication Protection Implications
---------------------------------------------

As described in :ref:`p2_core/cryptography:Origin Authentication Protection`, protecting the origin authentication of a message involves computing and sending a |RecSpecificMAC| to each of the message's Receivers.
By default (i.e., when :property:`cryptography.max_receiver_specific_macs` is
:value:`AUTO`), when :xmltag:`rtps_protection_kind` is set to a value ending in
:xmlval:`_WITH_ORIGIN_AUTHENTICATION`, each receiving |DP| is assigned a unique
|RecSpecificKey|, and the |SP_BUILTIN| send the |RecSpecificMACs| of all
of the message's destinations when sending a message. If these
|RecSpecificMACs| cause the message to exceed the :property:`message_size_max`
configured in the transports used by |CONNEXT|
(see :link_connext_dds_pro_um:`Setting Builtin Transport Properties with the PropertyQosPolicy in the Core Libraries User's Manual <#users_manual/Setting_Builtin_Transport_Properties_wit.htm?Highlight=message_size_max>`),
then |CONNEXT| will continuously resend the same message, appending different
|RecSpecificMACs| with each resend, until it sends all of the
|RecSpecificMACs|.

.. note::

    The value of the property
    :property:`cryptography.max_receiver_specific_macs` cannot be :value:`AUTO` (default)
    if any non-``rtps`` :xmltag:`*_protection_kind` values end in
    :xmlval:`_WITH_ORIGIN_AUTHENTICATION`. The only
    :xmlval:`_WITH_ORIGIN_AUTHENTICATION` protection kind that supports
    :value:`AUTO` is :xmltag:`rtps_protection_kind` (see
    :numref:`|RTI_SP_PRODUCT_HEADING| Properties for Configuring Cryptography`).

Reducing Performance Impact of Origin Authentication
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

You can reduce the performance impact of ProtectionKinds ending in :xmlval:`_WITH_ORIGIN_AUTHENTICATION` by limiting the number of |RecSpecificMACs| in your Secure Domain with the :property:`cryptography.max_receiver_specific_macs` property (see :numref:`|RTI_SP_PRODUCT_HEADING| Properties for Configuring Cryptography`). Setting this resource limit will have security implications. For instance, assume that you set :property:`cryptography.max_receiver_specific_macs` to 10, and you have 20 |DPs| in your Secure Domain. In this case, you will have groups of 2 participants who share the same |RecSpecificKey| and could pretend to be the other participant. Note that, with this setup, all the participants would have a single peer that could be a potential attacker. If this resource limit is unchanged, as the number of participants grows, an increasing number of participants will share the same key. Hence, each participant could impersonate an increasing number of other participants.

For example, suppose you have 100 participants and set this limit to 5. Since the keys will rotate every 5 participants (like in a circular buffer), you will have five groups of 20 participants with the same |RecSpecificKey|. If they happen to have writers and readers for the same |TOPIC|, they could potentially attack the origin authentication.

To successfully perform this attack, a malicious participant needs two keys:

* The |SenderKey|: generated by the Sender on the |SecEntity| creation. It is only exchanged with |SecEntities| matching that of the Sender -- for instance, two DRs in different |DPs| matching the same |DW|.

* The |RecSpecificKey|: assigned by a |DP| to the other |DPs| it discovers.
  The :property:`cryptography.max_receiver_specific_macs` property, when set to
  a positive integer, limits the number of different |RecSpecificKeys| a |DP|
  will assign. These keys are assigned in a round-robin fashion -- for
  instance, with :property:`cryptography.max_receiver_specific_macs` set to
  :value:`5`, |P6| and |P1| will share the same |RecSpecificKey|.


Choosing a reasonable value for this property will depend on multiple factors, such as your system's number of |DPs| and number of |TOPICs|.

Let's consider the following scenarios, assuming that all the DPs in your system set :property:`cryptography.max_receiver_specific_macs` to 5:

#. In a Secure Domain in which |DP| |P0| sends content to six other |DPs|, only |P1| and |P6| will share the |RecSpecificKey|. Therefore, |P1| could potentially pretend to be |P0| when sending content to |P6| and vice versa. This impersonation can only happen if |P1| and |P6| have |DRs| for the same Topic and have matched the same |DW| (otherwise, they won't have the |SenderKey| to generate the |CommonMAC|.

#. In a Secure Domain with 100 |DPs|, there will be five groups of 20 participants with the same |RecSpecificKey|. In this case, a malicious |DP| could only impersonate the other 19 |DPs| with which it shares the |RecSpecificKey|.


As suggested by the second example, the :property:`cryptography.max_receiver_specific_macs` allows you to divide |DPs| into groups, reducing the impact of a potential attack against the origin authentication. Which group a participant belongs in depends on the order of discovery, and therefore, is randomized. In this sense, the :property:`cryptography.max_receiver_specific_macs` defines the size of a circular buffer with |RecSpecificKeys|. When |P1| discovers |P2|, |P1| assigns the next key in its buffer to |P2|. Suppose |P2| loses liveliness with |P1|, and they discover again. In that case, |P1| will assign |P2| the next key in its circular buffer, which may differ from the previous one, potentially resulting in a group change with respect to |P1|.


Reencoding Protected Data when Regenerating Keys
------------------------------------------------

As mentioned in :ref:`p2_core/cryptography:Serialized data protection` and
:ref:`p2_core/cryptography:Instance Key Data Protection`, a |DW|
that protects its serialized data stores the protected serialized data and
instance key data in its queue. And as described in
:ref:`p2_core/cryptography:Limiting the Usage of Specific Key Material`, it is
possible for a |DW| to change its |KeyMaterial| during its lifetime. In this
section, we describe what happens to the stored protected data when new
|KeyRevisions| are introduced.

The :xmltag:`enable_key_revision` |GovRule| determines whether or not to enable
|KeyRevisions|, and the property
:property:`dds.participant.trust_plugins.key_revision_max_history_depth`
determines how many
|KeyRevisions| to keep locally. When the |DP| calls ``banish_ignored_participants``
enough times for the number of |KeyRevisions| to reach this limit, the |DP|
must remove the oldest |KeyRevision| in order to make space for the next
|KeyRevision|. But what if there still exists a sample in the queue that was
protected using the oldest |KeyRevision|?

Let's consider that we have the following:

* **S0**: A sample that was protected using the oldest |KeyRevision|.
* |DW1|: The sample **S0** exists in this |DW|'s queue.
* |P1|: The local |DP| that is calling ``banish_ignored_participants``. |DW1|
  belongs to this |DP|.
* |P2|: A new |DP| that joins the system.
* |DR2|: A |DR| with DURABILITY QosPolicy of kind :value:`TRANSIENT_LOCAL` that
  belongs to |P2|.

Then, the following could happen:

* |P1| removes the oldest |KeyRevision|.
* |P2| joins the system.
* |P1| sends |P2| its seven most recent |KeyRevisions| (see
  :ref:`p2_core/cryptography:Secure Key Exchange`), which do not include the
  oldest |KeyRevision| because it was just removed.
* When |DR2| receives **S0** from |DW1|, |DR2| is unable to decode **S0**
  because it doesn't have the necessary |KeyRevision|.

To solve this problem, |DW1| has to reencode **S0** with the latest
|KeyRevision| before |P1| removes the oldest |KeyRevision|. The reencoding
involves these steps, which are automatically done by the |RTI_SP_PRODUCT|:

* Block the |DW|'s Publisher. The |DW| has to stop writing data during the
  reencoding.
* Decode using the same |KeyRevision| that was used to encode. The
  |KeyRevision| identifier in the :ref:`p2_core/cryptography:Crypto Header`
  identifies which |KeyRevision| was used to encode.
* Encode using the latest |KeyRevision|.

After this reencoding, |DR2| will have the necessary |KeyRevision| to decode
**S0**.

Note that |P1| sends |P2| only its seven most recent |KeyRevisions|. This
number is called the |KeyRevisionWindowSize|. The number is eight instead
of ``key_revision_max_history_depth`` in order to do the following:

* Limit the amount of memory |P2| needs for keeping track of the |KeyRevisions|
  used by |P1| and all of the other |DPs| communicating with |P2|.
* Limit the amount of network traffic |P1| needs for sending |KeyRevisions| to
  late-joining |DPs|.

As a further optimization, the
|KeyRevisionWindowSize| is reduced from seven to one if |P1| never creates any
|DWs| with the RELIABILITY QosPolicy kind set to :value:`RELIABLE` and
the :xmltag:`data_protection_kind` |GovRule| set to a value other than
:xmlval:`NONE`.

Also note that ``key_revision_max_history_depth`` is allowed to be greater than
eight. Consider this scenario:

* |P1| has ``key_revision_max_history_depth`` set to :value:`8`.
* A KEEP_LAST |DW| from |P1| encodes **S0** using the original |KeyMaterial|
  (revision :value:`0`).
* When |P1| has to make space for revision :value:`8`, the |DW| has to
  reencode **S0**.
* Before sending out **S0** to any |DRs|, the |DW| writes a sample that
  replaces **S0** in the |DW|'s queue.
* That reencoding of **S0** has become wasted effort.

To avoid this wasted effort, |P1| can set ``key_revision_max_history_depth`` to
a value greater than :value:`8`. Then, the |DW| will only reencode **S0** if
it is actually requested by a |DR| through a NACK message. This is known as
**lazy reencoding** because it only happens when it's required by a |DR|. This
configuration avoids wasted reencodings at the cost of additional memory. See
:ref:`p2_core/cryptography:Configuration Properties Affecting Any Cryptography Plugin`
for the memory footprint of |KeyRevisions|.

Unlike non-lazy reencoding, lazy reencoding does not require blocking the
|DW|'s Publisher.

Interactions with Persistence Service
-------------------------------------

When you enable security, |RTI_PERSISTENCESERVICE| will perform |DataProtection| before storing data into the database, at the level specified by :ref:`p2_core/cryptography:data_protection_kind (topic_rule)`. To do so, |PERSISTENCESERVICE| creates |SecDRs| to subscribe to |TOPICs| with TRANSIENT or PERSISTENT durability (see :link_connext_dds_pro_um:`Introduction to RTI Persistence Service in the Core Libraries User's Manual <#users_manual/PersistenceIntro.htm>`), and |SecDWs| to write data to both the network and the database. Hence, after discovering a |TOPIC|, |PERSISTENCESERVICE| creates a :entity:`PRSTDataReader` and a :entity:`PRSTDataWriter`.

The :entity:`PRSTDataReader` receives data from the |CONNEXTDATABUS| and verifies (and potentially decrypts) it. The :entity:`PRSTDataWriter` reencodes the data with its own key before inserting it into the database. The stored encoded data includes the payload and the metadata necessary to validate (and potentially decrypt) it, such as the |CryptoHeader| and |CryptoFooter| (see :ref:`p2_core/cryptography:Serialized data protection`).

The first time |PERSISTENCESERVICE| creates a :entity:`PRSTDataWriter`, it
randomly generates a |SenderKey| that it stores encrypted in the database row
containing the information about the writer. The key used for this encryption
is the output of a derivation function whose input is the required
user-specified property :property:`dds.data_writer.history.key_material_key`
(see :numref:`Properties for Configuring Secure Persistence Service`). The
|CryptoPlugin| uses PBKDF2 (Password-Based Key Derivation Function) with
SHA-512 (Secure Hash Algorithm with a 512-bit hash value) as the key derivation
function, which also takes a random salt as input; and AES-256-GCM as the
encryption algorithm. The key derivation function derives both the key and the
IV (|IV|) used in the encryption. |PERSISTENCESERVICE| stores the random salt
along with the :entity:`PRSTDataWriter`'s encrypted |SenderKey|. If
|KeyRevisions| are enabled (see
:ref:`p2_core/cryptography:Limiting the Usage of Specific Key Material`), then
|PERSISTENCESERVICE| also stores the :property:`key_revision_max_history_depth` most
recent |KeyRevisions|, which will be necessary to decode the data upon
restarting |PERSISTENCESERVICE| (see
:ref:`p2_core/cryptography:Reencoding Protected Data when Regenerating Keys`.
Upon restarting |PERSISTENCESERVICE|, we use the original
:entity:`PRSTDataWriter`'s |KeyRevision| to decode, and we use the new
:entity:`PRSTDataWriter`'s latest |KeyRevision| to encode). The |KeyRevisions|
are encrypted in the same way as the |SenderKey|.

When |PERSISTENCESERVICE| restarts, it loads each :entity:`PRSTDataWriter`'s |SenderKey| and |KeyRevisions| from the database. To do so, |PERSISTENCESERVICE| needs the same configuration. If a different configuration is provided (e.g., wrong value for :property:`dds.data_writer.history.key_material_key`), |PERSISTENCESERVICE| creation will fail.

Note that when |PERSISTENCESERVICE| reads the data from the database, the :entity:`PRSTDataWriter` does NOT verify the MAC stored with the data before sending it out on the wire. It is up to the user |DRs| to verify the MAC. Consequently, if an attacker alters the database's data, the :entity:`PRSTDataWriter` will resend the tampered data many times over the wire until the reliability protocol causes the data to be lost.

For further information, see :ref:`section-persistence-service`.


Interactions with FlatData and Zero Copy
----------------------------------------

For more information about the |RTI_SP_PRODUCT|'s interactions with *Zero Copy
transfer over shared memory*, see the following section in the
*RTI Connext DDS Core Libraries User's Manual*:

* :link_connext_dds_pro_um:`Using Zero Copy Transfer Over Shared Memory in the Core Libraries User's Manual <#users_manual/SendingLDZeroCopyUsing.htm>` (see "Interactions with |RTI_SP_PRODUCT| and Compression")

Lightweight Security Pre-Shared Key RTPS Protection
---------------------------------------------------

To avoid the discovery-time overhead of mutual authentication and key exchange,
you may use the |LIGHT_SP_BUILTIN| described in
:ref:`p3_advanced/lightweight_security:The |LIGHT_SP_BUILTIN_HEADING|` and provide a
pre-shared key seed with the
:property:`dds.sec.crypto.rtps_psk_secret_passphrase` property. In
addition to the integrity and authentication of RTPS messages, |LIGHT_SP_BUILTIN| can
also protect their confidentiality (for more information, see the
:property:`dds.sec.crypto.rtps_psk_symmetric_cipher_algorithm` property).

|PSKProtection| is available in both the |SP_BUILTIN| and the |LIGHT_SP_BUILTIN|
libraries.
You can read the :ref:`p3_advanced/pre-shared_key:|PSKProtection|` section to
learn more about |PSKProtection|, including how it works, how to configure it,
and the difference between using it in the |SP_BUILTIN| library or in the
|LIGHT_SP_BUILTIN| library.

Interactions with Instance State Consistency
--------------------------------------------

Instance State Consistency uses the builtin |DW| and |DR| that are
shared by all user-created |DWs| and |DRs| within the same |PUB| or |SUB|.
When security is enabled, these builtin entities will ensure that the
topic granular security offered by |CONNEXT| is maintained.

If the user-created |DW| or |DR| uses either Serialized Data Protection or Submessage
Protection, these entities' builtin instance state endpoint will be secure.
It is possible that both the secure and non-secure variants of the builtin
instance state endpoints are created within a |PUB| or |SUB| (if that |PUB| or
|SUB| contains both secure and non-secure endpoints).

When security is used, the request for instance state data is sent using the builtin
secure service request |DW|. Protection for this |DW| is configured via the
`service_request_protection_kind` tag (see 
:ref:`p2_core/cryptography:service_request_protection_kind (domain_rule)` for
more information on the protection configuration of the service request channel).

The actual response samples sent by the instance state |DW| may contain
sensitive data (such as key hashes, timestamps, GUIDs). This data would normally
be protected by the user |DW|'s protection info. To maintain the
topic-level security offered by |CONNEXT|, each instance state response sample
is protected using Serialized Data Protection, with the protection info of the
|DW| whose instance state data is being requested. Although the builtin instance
state |DW| is shared by multiple user |DWs|, each response sample only contains
instance state data from a single user |DW|.
The `instance_state_consistency_protection_kind` goverance rule
(see :ref:`p2_core/cryptography:instance_state_consistency_protection_kind (domain_rule)`)
configures the submessage protection of the builtin secure instance
state |DW| and |DR|.

Interactions with TypeLookup Service
------------------------------------

Secure TypeLookup Service is described in the |SEC_SPEC_12|. As described by that
specification, a "Secure Type"—a type only used by |TOPICs| configured with
:xmltag:`enable_discovery_protection` (see
:ref:`p2_core/cryptography:enable_discovery_protection (topic_rule)`) set to
:xmlval:`true`—can **only** be
propagated via the Secure TypeLookup Service channel. Specifically, this means:

* If a request for a secure type is received on the non-secure TypeLookup Service
  channel, the request will be ignored.

* If a request for a non-secure type is received on the secure TypeLookup Service
  channel, the request will be processed and a response will be sent on the
  secure channel.

* A TypeLookup request can contain a mix of both secure types and non-secure types.
    * If a request containing both secure and non-secure types is received
      on the non-secure channel, only the non-secure types will be included in
      the response and the response will be sent on the non-secure channel.
    * If a request containing both secure and non-secure types is received on the
      secure channel, all of the types will be included in the response and the
      response will be sent on the secure channel.

A TypeLookup Service response will only ever be sent in response to a request sample,
and it will be made on the same channel that the request was received on. A response will
never be sent on the non-secure channel for a request received on the secure channel
(and a response will never be sent on the secure channel for a request received on
the non-secure channel).
If a requester receives a response on a different channel than the request was
issued on, the response will be dropped.

When security is enabled on a |DP|, all types registered by that |DP| initially start as
Secure Types. A Secure Type transitions to being non-secure if a |TOPIC| is created using
that type and has its :xmltag:`enable_discovery_protection` set to :xmlval:`false`
(see :ref:`p2_core/cryptography:enable_discovery_protection (topic_rule)`).
Once a Type becomes non-secure, it will never be secure again,
even if the |TOPIC| that caused the transition to non-secure is deleted.

Properties for Configuring Cryptography
=======================================

The :ref:`section-sp-properties` listed in :numref:`|RTI_SP_PRODUCT_HEADING| Properties for Configuring Cryptography` configure Cryptography:

.. list-table:: |RTI_SP_PRODUCT| Properties for Configuring Cryptography
  :name: |RTI_SP_PRODUCT_HEADING| Properties for Configuring Cryptography
  :widths: 40 60
  :header-rows: 1
  :class: longtable

  * - Property Name (prefix with :property:`com.rti.serv.secure.`) [#fPrefix]_
    - Property Value Description

  * - :property:`cryptography.max_blocks_per_session`
    - :required:`Optional`

      The number of message blocks that can be protected with the same
      |SessionKey|. Whenever the number of blocks exceeds this value, a new
      |SessionKey| is computed. The block size is always 128 bits (the AES
      block size).
      You can specify this value in decimal, octal, or hex. This value is an
      unsigned 64-bit integer.

      :type:`Unsigned integer`: :value:`[1 - MAX_UINT64]`

      Default: :value:`MAX_UINT64`

  * - :property:`cryptography.encryption_algorithm` (deprecated)
    - :required:`Optional`

      Deprecated. Use :property:`dds.sec.crypto.symmetric_cipher_algorithm`
      instead.

  * - :property:`cryptography.max_receiver_specific_macs`
    - :required:`Optional`

      The maximum number of Receiver-Specific Message Authentication Codes (MACs) that are appended to an encoded result.

      For example, if this value is 32, and the |DP| is configured to protect both RTPS messages and submessages with |OrigAuthProtection|, there could be 32 |RecSpecificMACs| in the result of ``encode_datawriter_submessage``, and there could be another 32 |RecSpecificMACs| in the result of ``encode_rtps_message``. If there are more than 32 Receivers, the Receivers will be assigned one of the 32 possible MACs in a round-robin fashion. Note that in the case of ``encode_datawriter_submessage``, all the readers belonging to the same |DP| will always be assigned the same |RecSpecificMAC|.

      Setting this value to :value:`0` will completely disable |RecSpecificMACs|. For further details see :ref:`p2_core/cryptography:Origin Authentication Protection Implications`.

      :type:`Integer`: :value:`[2, 3275]`, or :value:`0` to completely disable |RecSpecificMACs|,
      or :value:`AUTO` to allow an unlimited number of |RecSpecificMACs| if
      :xmltag:`rtps_protection_kind` ends in :xmlval:`WITH_ORIGIN_AUTHENTICATION`.

      Default: :value:`AUTO` (non-``rtps`` :xmltag:`*_protection_kind` values ending in :xmlval:`WITH_ORIGIN_AUTHENTICATION` are not allowed)


  * - :property:`cryptography.share_key_for_metadata_and_data_protection`
    - :required:`Optional`

      Indicator of whether the metadata and data encoding operations share the same |KeyMaterial| or use different keys. By default, |DWs| with both :xmltag:`metadata_protection_kind` and :xmltag:`data_protection_kind` set to a value other than :xmlval:`NONE` use the same |KeyMaterial| for protecting both RTPS submessages and serialized data. To change this behavior, set this property to :xmlval:`FALSE`.

      :type:`Boolean`.

      Default: :value:`TRUE` (they share |KeyMaterial|)

  * - :property:`cryptography.enable_additional_authenticated_data`
    - :required:`Optional`

      **Available in:** |SP_BUILTIN|

      Enable Additional Authenticated Data (AAD) for encode operations that support
      it. Currently only applicable to RTPS protection
      (:xmltag:`rtps_protection_kind` set to a value other than :xmlval:`NONE`),
      where it is used to protect the RTPS Header and RTPS Header Extension
      Submessage if present.

      It's of an enum type:

        * :value:`TRUE` enables AAD for all protected messages,

        * :value:`FALSE` disables it for all protected messages,

        * :value:`AUTO` enables AAD for messages protected with |PSK| and for messages
          containing an RTPS Header Extension submessage. Disables AAD for messages
          protected with |AXK|.

      Must be set to :value:`TRUE` or :value:`AUTO` if using RTPS protection in
      combination with RTPS 2.5 Header Extension.

      This property is not available in |LIGHT_SP_BUILTIN|, which always use AAD.

      :type:`Enum`: :value:`AUTO` (default), :value:`TRUE`, :value:`FALSE`

      Default: :value:`AUTO`.

.. [#fPrefix] Assuming you used :value:`com.rti.serv.secure` as the alias to
   load the plugin. If not, change the prefix to match the string used with
   :property:`com.rti.serv.load_plugins`, followed by the :value:`.` character.


Configuration Properties Affecting Any Cryptography Plugin
----------------------------------------------------------

:numref:`Properties for Configuring Cryptography Affecting Any Cryptography Plugin`
lists a set of :ref:`section-sp-properties` that are
not exclusive to the shipped builtin plugins, but that will affect any
|CryptoPlugin|.

.. list-table:: Properties for Configuring Cryptography Affecting Any |CryptoPlugin|
  :name: Properties for Configuring Cryptography Affecting Any Cryptography Plugin
  :widths: 40 60
  :header-rows: 1
  :class: longtable

  * - Property Name
    - Property Value Description

  * - :property:`dds.sec.crypto.symmetric_cipher_algorithm`
    - :required:`Optional`

      Encryption algorithm that the Sender uses for protecting RTPS messages with
      |AXK| keys. The value of this property determines the |TransformationKind|
      sent through the |SecKeyExchangeCh| (and in the |CryptoHeader|) to inform the
      Receiver about the transformation used to protect the data.

      The options are :value:`AES128+GCM` and :value:`AES256+GCM`. The number indicates
      the number of bits in the key in either the GMAC or GCM variant of the algorithm.

      This property sets the algorithm and key length only. To set the variant
      of the algorithm, set the |GovernanceDoc|'s :xmltag:`protection_kind`
      either to :xmlval:`ENCRYPT`, for GCM, or to :xmlval:`SIGN`, to use the GMAC
      variant of this algorithm.

      This property is set for |DPs|, and affects both user and builtin |EPs|.
      The exceptions are the Secure Key Exchange |DW| and |DR|, which always
      use :value:`AES256+GCM` for the encryption transformation.

      :type:`Enum`: :value:`AUTO` (equivalent to :value:`AES256+GCM`),
      :value:`AES128+GCM`, :value:`AES256+GCM`

      Default: :value:`AUTO`

      .. warning::

        This DDS Security property behaves exactly like the previous
        |RTI_SP_PRODUCT| :property:`cryptography.encryption_algorithm` property.
        :property:`cryptography.encryption_algorithm` is deprecated. Use
        :property:`dds.sec.crypto.symmetric_cipher_algorithm` instead.

  * - :property:`dds.sec.crypto.rtps_psk_symmetric_cipher_algorithm`
    - :required:`Optional`

      Algorithm used to protect RTPS messages protected with
      :ref:`p3_advanced/pre-shared_key:|PSKProtection|`. The available options are
      :value:`AES256+GCM` (default) and :value:`AES128+GCM`. The number indicates
      the number of bits in the key in either the GMAC or GCM variant of the algorithm.
      The |LIGHT_SP_BUILTIN| offer an additional cryptographic algorithm, :value:`SM4+GCM`,
      which uses 128-bit long keys. This property sets the algorithm and key length
      only; see the note below for more information about setting the algorithm's variant.

      This property must be set if |PSKProtection| is enabled (see
      :ref:`p2_core/cryptography:rtps_psk_protection_kind (domain_rule)`).
      It must be configured consistently throughout your system. That is, all
      the |DPs| need to have the same value in order to communicate.

      The value of this property (combined with :value:`rtps_psk_protection_kind`)
      determines the |TransformationKind| sent through the |SecKeyExchangeCh| and
      in the |CryptoHeader|.

      :type:`Enum`: :value:`AUTO` (equivalent to :value:`AES256+GCM`),
      :value:`AES128+GCM`, :value:`AES256+GCM`, :value:`SM4+GCM` (|LIGHT_SP_BUILTIN| only).

      Default: :value:`AUTO`

      .. note::

        - The |LIGHT_SP_BUILTIN| (see
          :ref:`p2_core/cryptography:Lightweight Security Pre-Shared Key RTPS Protection`)
          protect all RTPS messages with |PSKProtection|. The |SP_BUILTIN| protect
          all RTPS Messages with a PSK only if the :xmltag:`rtps_protection_kind` |GovRule|
          is set to :xmlval:`NONE`. If the :xmltag:`rtps_protection_kind` value is
          different than :xmlval:`NONE`, the |SP_BUILTIN| will use |PSKProtection| to
          protect only bootstrapping RTPS messages. Once the authentication process
          is complete, the |SP_BUILTIN| protect RTPS messages using |AXK| keys and
          the algorithm specified by the :property:`dds.sec.crypto.symmetric_cipher_algorithm`
          property.

        - You can configure whether to protect only the integrity of messages
          (GMAC variant of this algorithm) or both the confidentiality and
          integrity (GCM variant). To do so in the |SP_BUILTIN|, set the
          :xmltag:`rtps_psk_protection_kind` |GovRule|  (see
          :ref:`p2_core/cryptography:rtps_psk_protection_kind (domain_rule)`)
          in the |GovernanceDoc| to either :xmlval:`ENCRYPT` (GCM) or
          :xmlval:`SIGN` (GMAC). In the |LIGHT_SP_BUILTIN|, configuration can be done
          through the :property:`dds.sec.access.rtps_psk_protection_kind` property.

  * - :property:`dds.sec.crypto.rtps_psk_secret_passphrase`
    - :required:`Optional`

      This property must be set if |PSKProtection| is enabled (see
      :ref:`p2_core/cryptography:rtps_psk_protection_kind (domain_rule)`).
      It must be configured consistently throughout your system. That is, all
      the |DPs| need to have the same value in order to communicate. The only
      exception is when the |DPs| have additional decode-only passphrases
      configured with the
      :property:`dds.sec.crypto.rtps_psk_secret_passphrase_extra` property.

      The |RTI_SP_PRODUCT| use this secret passphrase (in combination with other
      publicly available data) to derive the per-participant key used for
      encoding RTPS messages.

      This property is mutable through the |DP| ``set_qos`` API.
      The |DP| will use the updated passphrase to derive the new local and remote
      pre-shared keys. From that point on, the |DP| will use the new keys to
      encrypt and decrypt RTPS messages protected with |PSKProtection|.
      You should expect warning messages (about receiving messages encoded with
      a different pre-shared key identifier) as you change the property value
      throughout your system. Once all your |DPs| have the same passphrase, all
      pre-shared key protected traffic will be encoded and decoded with
      consistent keys. At that point, warning messages will stop. You can
      configure the :property:`dds.sec.crypto.rtps_psk_secret_passphrase_extra`
      property to update the passphrase without losing any RTPS messages.

      Updating the value of this property implies not only a change in the
      secret key, but also a change in the key identifier. Each secret key
      should be associated with a unique key identifier.
      Updating the secret key without changing the key identifier is not
      allowed and will result in `set_qos` returning
      DDS_RETCODE_NOT_ALLOWED_BY_SECURITY.
      The pre-shared secret identifier shouldn't be re-used either. You may set
      a new secret key with an old key identifier, but doing so is not advised.
      In that case, the |RTI_SP_PRODUCT| may end up using the old pre-shared key
      to try (without success) to decode an RTPS message that was encoded using
      the new key.

      :type:`String`. There are two acceptable formats for this property:

      * Passphrase value explicitly in the property: It must follow the format
        ``data:,<passphrase_id>:<passphrase>``. ``<passphrase_id>`` is an
        unique four-byte integer number that identifies the key. It must be in
        the :value:`[0, 2^32 - 1]` range, excluding the values that have
        ``0xFF`` as the least significant byte (e.g. 255, 1023, 2047, etc).
        Interoperability with releases older than 7.4.0 requires the passphrase
        id to be a value between 0 and 254.
        ``<passphrase>`` is the secret passphrase string that the
        |RTI_SP_PRODUCT| will use to derive the per-participant pre-shared key.

      * Path and name of a supplemental file that contains the passphrase value.
        May start with the ``file:`` prefix, followed by a path to a file.
        If no prefix is provided, the |RTI_SP_PRODUCT| assume the value is a
        file path. The file content must follow the format
        ``<passphrase_id>:<passphrase>``, exactly the same as if it were
        provided explicitly. If the passphrase is provided in a file, the
        |RTI_SP_PRODUCT| can track this file for changes and update used keys if
        a valid change is detected. The file will be tracked automatically if
        the value of :property:`files_poll_interval` is different than :value:`0`.
        If you delete this file, the |RTI_SP_PRODUCT| will keep using the last
        valid passphrase. Similarly, if you remove the contents of the tracked
        file, the |RTI_SP_PRODUCT| will fail to read the new passphrase and
        keep using the last one.


      It is recommended that you take the appropriate measures to protect
      any file containing this key, or alternatively to securely retrieve
      and set up this property programmatically.

      ``<passphrase_id>`` must be provided to support proper handling of
      different passphrase revisions, and it must be consistent across all the
      |DPs| within a domain. This value must be different with every passphrase
      change, otherwise the update will be rejected. It is good practice to use
      incremental, subsequent values for every new key provided.
      Rolling back to a lower number (e.g., 0) after the indexes have been
      exhausted is acceptable.

      ``<passphrase>`` must be a string containing up to 512 ASCII printable
      characters (character codes 32 to 126, both included). The first and last
      characters of the ``<passphrase>`` shall not be the space character
      (character code 32).

      Default: not set

      .. attention::

        It is strongly encouraged (and the user's responsibility) to provide a
        key passphrase with good entropy and length. Ideally, the pre-shared key
        passphrase should be a true random 256-bit seed. There are a few methods
        to obtain such a string. For example, one could use a specialized
        dictionary (e.g., BIP39) to draw words from, or a Base64-encoded sequence
        of random binary bits. Note that actual entropy may be less than what
        the length of the string suggests. For example, the ASCII character
        space does not use the whole 8-bit space: instead, only 5-6 bits are
        used. To obtain the desirable entropy and strength one would need at
        least 256/5.5 = 47 truly random characters. A dictionary-based approach
        offers less entropy, and the seed created this way would need to be
        longer.

  * - :property:`dds.sec.crypto.rtps_psk_secret_passphrase_extra`
    - :required:`Optional`

      This property allows configuring an extra pre-shared key passphrase. It
      can be used in conjunction with :property:`dds.sec.crypto.rtps_psk_secret_passphrase`
      if there is a requirement for a seamless transition to a new passphrase,
      while allowing a grace period for the entire system to update and avoid
      message loss because of slow-to-update participants.

      PSK Protection uses this pre-shared key passphrase to derive the key used
      for decoding RTPS messages only. Encoding RTPS messages does not use this
      passphrase.

      This property is mutable through the |DP| ``set_qos`` API, or through
      file tracking (see :property:`files_poll_interval` property). You should
      only set its value during an update of the primary passphrase. See section
      :ref:`p3_advanced/pre-shared_key:Updating the |PSK| passphrase without message loss`
      for more information. The |RTI_SP_PRODUCT| will stop using the extra
      passphrases if you do one of the following: remove the
      :property:`dds.sec.crypto.rtps_psk_secret_passphrase_extra` property,
      assign the empty string (``""``) to the property value, delete the tracked
      file, or delete the contents of the tracked file (empty the file).

      :type:`String`. This property accepts a list of passphrases separated by
      either a new line (``\n`` character), a carriage return (``\r``
      character), or a combination of both. The passphrases can be provided
      directly in the property value (``data:,`` prefix) or in a supplemental
      file (no prefix or ``\file:`` prefix). Each passphrase follows the same
      format as :property:`dds.sec.crypto.rtps_psk_secret_passphrase`
      (``<passphrase_id>:<passphrase>``).

      This property can have a maximum of two passphrases, but one of them
      must be equal to the primary passphrase (the one in
      :property:`dds.sec.crypto.rtps_psk_secret_passphrase`). That is, only one
      unique new passphrase is allowed. The property value is not valid if
      there are more than two passphrases, or if there are two passphrases and
      one of them doesn't match the primary passphrase. For example,
      ``data:,0:my_extra_passphrase``, or
      ``data:,0:my_extra_passphrase\n1:my_primary_passphrase`` would both be
      valid options. However,
      ``data:,0:my_extra_passphrase\n1:another_extra_passphrase`` is not a valid
      value because this property does not support two new passphrases, and the
      value must include the current primary passphrase.

      Default: not set

  * - :property:`dds.participant.trust_plugins.key_revision_max_history_depth`
    - :required:`Optional`

      Controls the number of key revisions that are used to encode samples in
      the |DW| queues. As the value increases, the reencoding of writer queue
      historical samples gets more delayed or even avoided, but the memory
      footprint of the |DP| increases. The memory used for key revisions is
      preallocated, and it is roughly equal to 36 bytes (or 164 bytes if the
      |DP| has at least one |DW| using ODBC writer history)
      multiplied by the key_revision_max_history_depth. If there is at least
      one reliable |DW| that is protecting its payload, then the |DP| will send
      8 key revisions instead of just 1 to each late joiner |DP|. Each key
      revision adds about 128 bytes of network traffic, so that's
      128 * (8 - 1) = 896 more bytes per late joiner |DP|.

      A |DP| that sets this property to a value other than :value:`0` will not
      communicate with a |DP| that sets this property to :value:`0` or with a
      |DP| of a release older than the |CONNEXT_700Version| |RTI_SP_PRODUCT|.

      :type:`Integer`: :value:`[8, 1000000]`, or :value:`0` to completely
      disable |KeyRegen|.

      Default: :value:`14` if :xmltag:`enable_key_revision` is :xmlval:`true`
      or unspecified, :value:`0` if :xmltag:`enable_key_revision` is :xmlval:`false`.

  * - :property:`dds.participant.trust_plugins.max_key_redistribution_delay.sec`
    - :required:`Optional`

      Controls the maximum time in seconds between generating and using a new
      key revision. After this time, remote |DPs| that have not yet
      acknowledged the new key revision will be completely removed.

      :type:`Integer`: :value:`[1, MAX_INT32]`, or :value:`-1` to wait
      indefinitely for key revision acknowledgements.

      Default: :value:`60`

  * - :property:`dds.participant.trust_plugins.max_removed_participants_per_key_revision`
    - :required:`Optional`

      Controls the number of |DPs| that you were formerly communicating with to
      keep track of before automatically creating a new |KeyRevision|. As the
      value increases, the overhead of creating a new |KeyRevision| occurs less
      frequently, but the memory footprint of the |DP| increases. The memory
      used for keeping track of these removed |DPs| is preallocated, and it is
      roughly equal to 72 bytes multiplied by the
      max_removed_participants_per_key_revision, plus an additional 512 bytes.

      See
      :ref:`p2_core/cryptography:Automatically Banishing Ignored Participants`
      for more information.

      :type:`Integer`: :value:`[0, 50000]`.

      Default: :value:`50`

  * - :property:`dds.data_writer.history.use_530_encoding_alignment` (deprecated)
    - :required:`Optional`

      This property is deprecated and has no effect. A warning message will be
      logged if this property is set to :value:`TRUE`.

      :type:`Boolean`.

      Default: :value:`FALSE`

  * - :property:`dds.data_writer.cryptography.taint_data`
    - :required:`Optional`

      Simulate tainted data.
      Connext DDS will modify one byte of encoded data after the GMAC is
      computed. This property applies to the DataWriterQos, and can be used for
      testing validation of the GMAC hash. Note that Connext DDS will only taint
      live data (repair data is not tainted). Also, tainting
      requires running on a little-endian machine.

      If :value:`TRUE`, then the encoded data is modified after computing the
      final layer of GMAC or GCM.
      After failing to validate the GMAC hash, the |RTI_SP_PRODUCT| will log the following
      message with :value:`DDS_LOGGING_ERROR_LEVEL` level:

      .. code-block:: console

        DecryptFinal failed. Possible GCM authentication failure

      See :ref:`p2_core/logging:Interface Between the Logging Plugin and the Connext DDS Builtin Logging System`
      for more information about the |RTI_SP_PRODUCT| log level values.

      :value:`TRUE` is not supported when
      :xmltag:`enable_key_revision` is set to :xmlval:`true`.

      If :value:`FALSE`, then the encoded data is not modified after computing
      the final layer of GMAC or GCM. This is the default behavior.

      :type:`Boolean`.

      Default: :value:`FALSE`
